5. Docker容器互聯1--Docker存儲原理和基於Docker Volum的容器互聯

目錄

Docker 容器互聯

1  基於Docker Volum的容器互聯

1.1 Docker的文件存儲

1.2Docker Volume 

1.3 數據容器共享解決方案(volumes-form)


Docker 容器互聯

1  基於Docker Volum的容器互聯

1.1 Docker的文件存儲

docker的文件系統是copy on write方式的, 文件是一層層往上疊加的, 最下的一層是隻讀的, 要修改的時候會複製這層只讀的覆蓋在只讀的上面作爲一層可寫的, 這個時候原來的只讀文件依然是存在的這是看不到了

docker 中鏡像的存儲就是使用的上述方式,分層結構如下

上圖Docker的容器就是通過只讀的鏡像上面覆蓋的可寫層, 要想把這個可寫層持久化, 就要用到之前的講的 docker commit 了

但是鏡像的層次又可以共享:

 

鏡像是分層疊加的, 頂層的鏡像依賴於底層的鏡像, 容器是通過鏡像 Copy On Write 一個可寫層, 這個可寫層 Commit 就完成了持久化又成了一個新的鏡像. 

Docker鏡像的存儲位置:

docker的鏡像是分層的,一個鏡像往往是多個鏡像分層疊加出來的, 鏡像的分層信息是存儲在 Docker Graph 裏面

這裏記錄了鏡像有些那些層,   每一層的父層和大小等信息

 

其中 GrapDB 存儲的是分層結構 , Repository 裏面存儲是鏡像的信息, 兩者結合得到鏡像的分層信息

但是這些裏面存儲都是鏡像的信息, 並不是鏡像的實際存儲位置,

鏡像的二進制文件存儲位置是. /var/lib/docker/<storage-driver>

<storage-driver> 是  Docker Graph Driver , 不同的 Docker Graph Driver 會存儲在不同的目錄, 比如本機採用的是 overlay2

Docker Graph Driver 是Docker 使用來管理存儲鏡像每層內容及可讀寫的容器的驅動, 目前主要有 DeviceMapper、AUFS、Overlay、Overlay2、Btrfs、ZFS 等,不同的存儲驅動實現方式有差異,鏡像組織形式可能也稍有不同,但都採用棧式存儲,並採用 Copy-on-Write策略。且存儲驅動採用熱插拔架構,可動態調整。

Graph Driver 就類似於Java連接數據庫的 JDBC, 只不過這個驅動是用於 docker Deamon 來對鏡像個容器進行讀寫.

選擇策略:

  • 若內核支持多種存儲驅動,且沒有顯式配置,Docker 會根據它內部設置的優先級來選擇。優先級爲 AUFS > Btrfs/ZFS > Overlay2 > Overlay > DeviceMapper。若使用 DeviceMapper 的話,在生產環境,一定要選擇 direct-lvm, loopback-lvm 性能非常差。
  • 選擇會受限於 Docker 版本、操作系統、系統版本等。例如,AUFS 只能用於 Ubuntu 或 Debian 系統,Btrfs 只能用於 SLES (SUSE Linux Enterprise Server, 僅 Docker EE 支持)。
  • 有些存儲驅動依賴於後端的文件系統。例如,Btrfs 只能運行於後端文件系統 Btrfs 上。
  • 不同的存儲驅動在不同的應用場景下性能不同。例如,AUFS、Overlay、Overlay2 操作在文件級別,內存使用相對更高效,但大文件讀寫時,容器層會變得很大;DeviceMapper、Btrfs、ZFS 操作在塊級別,適合工作在寫負載高的場景;容器層數多,且寫小文件頻繁時,Overlay 效率比 Overlay2 更高;Btrfs、ZFS 更耗內存。

 

 

1.2Docker Volume 

Docker Copy on Write 

和剛剛說的一樣, Docker 的寫操作主要分爲兩種, 一個是 塊級別的, 一個是文件級別的,  塊級別的在修改文件的時候會把修改部分所在的塊 copy 到 write層用於寫, 文件級別則是直接複製真個文件到 write 層,   所以塊級別能夠節省空間, 但是塊級別 copy的操作次數多, 文件級別直接copy 文件就會是的容器變大, 但是直接copy 文件就會大大減少copy操作的次數. 

以上操作對容器中中需要頻繁讀寫的大文件就很不利,  塊級別的 COW 操作太頻繁,效率低, 文件級別的又會使得容器變得很大, 比如mysql數據庫的數據庫存儲文件.

這個時候就引入了 Volume, Volme 可以將宿主機的文件映射到容器直接操作, 不必經過 COW, 常見的高頻寫文件有日誌系統和數據存儲文件.

Vloume使用是通過docker run  的 -v 參數來實現的

[docker@VM_121_116_centos ~]$ docker run -it  -p 6379:6379 -v ~/redis/date:/data  redis /bin/bash
root@b385ca73cad3:/data# ls
appendonly.aof	root  tomcat
root@b385ca73cad3:/data# mkdir testdir
root@b385ca73cad3:/data# exit
exit
[docker@VM_121_116_centos ~]$ ll
total 580364
drwxrwxr-x 2 docker docker      4096 Mar  6 22:00 dockerFile
-rw-rw-r-- 1 docker docker 594276824 Mar  6 17:31 ideaIU-191.6014.8.exe
drwxr-xr-x 3 root   root        4096 Mar 19 21:26 redis
[docker@VM_121_116_centos ~]$ cd redis/date/
[docker@VM_121_116_centos date]$ ll
total 16
-rw-r--r-- 1 polkitd ssh_keys  443 Mar 19 21:27 appendonly.aof
-rw-r--r-- 1 polkitd ssh_keys  249 Mar 19 21:27 root
drwxr-xr-x 2 root    root     4096 Mar 19 21:32 testdir
-rw-r--r-- 1 polkitd ssh_keys  259 Mar 19 21:27 tomcat
[docker@VM_121_116_centos date]$ 

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 如命令所示 使用 -v 把宿主機的  ~/redis/date 掛載到 容器的 /data , 之後在容器的 /data  建立一個  testdir 文件夾. 之後在宿主機的 ~/redis/data 裏面看見了剛剛建的文件夾. 如不指定宿主機目錄, 那麼docker就會在docker得volume目錄中創建一個目錄掛載到容器內, 當容器刪除的時候, 這個目錄也就隨之刪除了. 

這樣容器的 /data 目錄就能避免大量的 COW 操作了, 直接進行讀寫.

在次看看容器信息 使用 docker inspect

[docker@VM_121_116_centos date]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
b385ca73cad3        redis               "docker-entrypoint..."   8 minutes ago       Exited (0) 7 minutes ago                       sad_murdock
e8abf8c09a26        mysql:5.6           "docker-entrypoint..."   3 weeks ago         Exited (0) 2 weeks ago                         mysql5.6
[docker@VM_121_116_centos date]$ docker inspect b385ca73cad3
[
    {
        "Id": "b385ca73cad3607f78fc87214dadf23435eebeaf5ee5551a17f160a432b08264",
        "Created": "2019-03-19T13:31:55.437267785Z",
        "Path": "docker-entrypoint.sh",
        "Args": [
            "/bin/bash"
        ],
        "State": {
            "Status": "exited",
            "Running": false,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 0,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2019-03-19T13:31:55.783433554Z",
            "FinishedAt": "2019-03-19T13:32:42.591792526Z"
        },
====================省略==================================
        
        "GraphDriver": {
            "Name": "overlay2",
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9-init/diff:/var/lib/docker/overlay2/61d911e09963bc0e77b7020b7bdbf798a5c35dbd90514c810f3aebb6875610f7/diff:/var/lib/docker/overlay2/fdddcb2b85492183f28660470d17c554e5bdb3a01cc8089e9c2112da7eefb4d5/diff:/var/lib/docker/overlay2/9476ee9fd3b0ccad81bdfa469c4188bda49230dff3598e9018cb763a0ba683c1/diff:/var/lib/docker/overlay2/65cfb70d00faeb7477439d635dc0a6f78f4f3d7bb6c5d28b29c6428744a58ee3/diff:/var/lib/docker/overlay2/55e18ec0a5caafed7907512ee5f2dd3e4db5cd701a1adfe5f4fe3bec2911e922/diff:/var/lib/docker/overlay2/ed7f62d6e611f876fb9eb55b06653b23198a915971fd1efdffbb61c33626f759/diff",
                "MergedDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9/merged",
                "UpperDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9/diff",
                "WorkDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9/work"
            }
        },
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/home/docker/redis/date",
                "Destination": "/data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
=============================省略================================
       
            }
        }
    }
]
[docker@VM_121_116_centos date]$

 

可以看到 將  /home/docker/redis/date 掛載到 /data

講了這麼多怎麼基於 Volume 互聯呢?  我們剛剛把宿主機一個指定的目錄掛載到了容器內部, 那麼要是我們把這個目錄掛載到多個容器有什麼效果呢?

我們再次創建一個容器還是掛在這個目錄

[docker@VM_121_116_centos date]$ docker run -it  -p 26379:6379 -v ~/redis/date:/data --name redistwo  redis /bin/bash 
root@cf0ca7e833bb:/data# ls
appendonly.aof	root  testdir  tomcat
root@cf0ca7e833bb:/data# mkdir testdirtwo
root@cf0ca7e833bb:/data# exit
exit

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

爲了區別剛剛那個, 我們加了 --name 參數, 進入容器發現有剛剛的建的  testdir, 我們再次建一個 testdirtwo, 再次回到上個容器看看

[docker@VM_121_116_centos date]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
cf0ca7e833bb        redis               "docker-entrypoint..."   3 minutes ago       Exited (0) 2 minutes ago                        redistwo
b385ca73cad3        redis               "docker-entrypoint..."   26 minutes ago      Exited (0) 25 minutes ago                       sad_murdock
e8abf8c09a26        mysql:5.6           "docker-entrypoint..."   3 weeks ago         Exited (0) 2 weeks ago                          mysql5.6 
[docker@VM_121_116_centos date]$ docker start b385ca73cad3
b385ca73cad3
[docker@VM_121_116_centos date]$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
b385ca73cad3        redis               "docker-entrypoint..."   28 minutes ago      Up 7 seconds        0.0.0.0:6379->6379/tcp   sad_murdock
[docker@VM_121_116_centos date]$ docker exec -it b385ca73cad3 /bin/bash
root@b385ca73cad3:/data# ls
appendonly.aof	root  testdir  testdirtwo  tomcat
root@b385ca73cad3:/data# 

有第二個容器創建的文件夾, 這樣就容器之間的互聯

對於跨越宿主機的容器互聯, 可是在linux採取共享目錄等技術, 或者分佈式文件系統

有 iscsi nfs ceph 等

1.3 數據容器共享解決方案(volumes-form)

將本地目錄掛載到容器, 在 DockerFile 中是不推薦使用的, 因爲這樣的容器就不可移植了. 

就要不指定宿主機的目錄, 使用容器存儲位置的目錄. 

如下:

[docker@VM_121_116_centos date]$ docker run -it  -p 6379:6379 -v /data --name oneredis  redis /bin/bash
root@6636fb7d293c:/data# mkdir redis
root@6636fb7d293c:/data# ls
redis
root@6636fb7d293c:/data# exit
exit
[docker@VM_121_116_centos date]$ docker inspect oneredis

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

查看掛載信息結果: 將 /var/lib/docker/volumes/b4fca8f9587e906919b5c2110b5e33643315dcc73d24ca177c8122072b44ef0a/_data 掛載到了 /data

我們沒有實現約定好共享目錄,就不能體檢知道掛載的目錄,  其他容器怎麼從這裏讀取呢?

這個時候要用 --volumes-from

示例:

[docker@VM_121_116_centos date]$ docker run -it  -p 26379:6379 --volumes-from=oneredis --name tworedis  redis /bin/bash
root@bb1d9cd3a282:/data# ls
redis
root@bb1d9cd3a282:/data# exit
exit

  

能看到第一個容器創建的目錄

再看看容器掛載

和第一個一模一樣

這樣就解決的移植性的問題

一般的解決方案就是 建議一個 數據共享的管理容器, 其他業務容器 volumes-from 數據管理容器, 這樣實現業務容器互聯

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章