一、需求
docker使服務之間實現容器隔離,比如Javaweb項目前端、后端、數據庫、數據庫后台,分別把它們部署在不同的容器里面,實現隔離。但服務和服務之間也有互訪的需求,這就涉及到容器網絡和容器互聯掛載訪問機制的內容。
容器是基於鏡像創建的,最后的容器文件系統包括鏡像的只讀層+可寫層,容器中的進程操作的數據持久化都是保存在容器的可寫層上。一旦容器刪除后,這些數據就沒了,除非我們人工備份下來(或者基於容器創建新的鏡像)。能否可以讓容器進程持久化的數據保存在主機上呢?這樣即使容器刪除了,數據還在。
docker本身提供了一種機制,可以將主機上的某個目錄與容器的某個目錄(稱為掛載點、或者叫卷)關聯起來,容器上的掛載點下的內容就是主機的這個目錄下的內容,這類似linux系統下mount的機制。 這樣的話,我們修改主機上該目錄的內容時,不需要同步容器,對容器來說是立即生效的。掛載點可以讓多個容器共享。
二、通過docker run命令
1、運行命令:
# docker run --name node1 -h nodex -v /home/upload/:/data -d -i -t centos /bin/bash
其中的 -v 標記 在容器中設置了一個掛載點 /data(就是容器中的一個目錄),並將主機上的 /home/upload/ 目錄中的內容關聯到 /data下。
這樣在容器中對/data目錄下的操作,還是在主機上對/home/upload/的操作,都是完全實時同步的,因為這兩個目錄實際都是指向主機目錄。
通過docker inspect 命令查看目錄對應關系
# docker inspect node1
[ { "Id": "d1c5d9eb3838c724b597db428ce26e72cfc667fbefb0ed712dbbaef5f374070f", ............................. "Mounts": [ { "Type": "bind", "Source": "/home/upload", "Destination": "/data", "Mode": "", "RW": true, "Propagation": "rprivate" } ], ...........................
2、運行命令:
# docker run --name node2 -h nodex -v /data -d -i -t centos /bin/bash
上面-v的標記只設置了容器的掛載點,並沒有指定關聯的主機目錄。這時docker會自動綁定主機上的一個目錄。通過docker inspect 命令可以查看到。
# docker inspect node2
[ { "Id": "d1c5d9eb3838c724b597db428ce26e72cfc667fbefb0ed712dbbaef5f374070f", ............................. "Mounts": [ { "Type": "volume", "Name": "d04353ed38845a54a2bd5909b82c470fe644391626f877644e9580aba22a3a12", "Source": "/var/lib/docker/volumes/d04353ed38845a54a2bd5909b82c470fe644391626f877644e9580aba22a3a12/_data", "Destination": "/data", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ...........................
上面 Mounts下的每條信息記錄了容器上一個掛載點的信息,"Destination" 值是容器的掛載點,"Source"值是對應的主機目錄。
可以看出這種方式對應的主機目錄是自動創建的,其目的不是讓在主機上修改,而是讓多個容器共享。
三、通過dockerfile創建掛載點
上面介紹的通過docker run命令的-v標識創建的掛載點只能對創建的容器有效。
通過dockerfile的 VOLUME 指令可以在鏡像中創建掛載點,這樣只要通過該鏡像創建的容器都有了掛載點。
還有一個區別是,通過 VOLUME 指令創建的掛載點,無法指定主機上對應的目錄,是自動生成的。
# cat Dockerfile
下面的dockfile文件通過VOLUME指令指定了兩個掛載點 /data1 和 /data2
#test FROM centos MAINTAINER djl VOLUME ["/data1","/data2"]
# docker build -t test .
[root@localhost ~]# docker build -t test . Sending build context to Docker daemon 28.77 MB Step 1/3 : FROM centos ---> 9f38484d220f Step 2/3 : MAINTAINER djl ---> Running in d14672dadf87 ---> 602a4b8e796d Removing intermediate container d14672dadf87 Step 3/3 : VOLUME /data1 /data2 ---> Running in 30b586d5aaf4 ---> f51b774e7869 Removing intermediate container 30b586d5aaf4 Successfully built f51b774e7869
查看構建的鏡像
# docker images
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE test latest f51b774e7869 2 minutes ago 202 MB centos latest 9f38484d220f 4 months ago 202 MB
運行一個容器
# docker run --name node3 -h nodex -d -i -t test /bin/bash
[root@localhost ~]# docker run --name node3 -h nodex -d -i -t test /bin/bash 6fb05f94a368e05dd96e2f42432f1e4c0dcad1bd6b726079c69fba0625783c38 [root@localhost ~]# [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6fb05f94a368 test "/bin/bash" 8 seconds ago Up 7 seconds node3 f2bf65a82acc centos "/bin/bash" About an hour ago Up About an hour node1 d1c5d9eb3838 centos "/bin/bash" 2 hours ago Up 2 hours node2
我們通過docker inspect 查看通過該dockerfile創建的鏡像生成的容器,可以看到如下信息
# docker inspect node3
[ { "Id": "d1c5d9eb3838c724b597db428ce26e72cfc667fbefb0ed712dbbaef5f374070f", ............................. "Mounts": [ { "Type": "volume", "Name": "cc2fcaccae2dca5021d82d4d581e1f500816a96745237527d4fa7925a2061e04", "Source": "/var/lib/docker/volumes/cc2fcaccae2dca5021d82d4d581e1f500816a96745237527d4fa7925a2061e04/_data", "Destination": "/data1", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" }, { "Type": "volume", "Name": "2f7419b960ae0a3f7be58875f5021312b181fdad72e2c7390b2bb7aab7d06b24", "Source": "/var/lib/docker/volumes/2f7419b960ae0a3f7be58875f5021312b181fdad72e2c7390b2bb7aab7d06b24/_data", "Destination": "/data2", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ...........................
可以看到兩個掛載點的信息。
四、容器共享卷(掛載點)
下面我們創建另一個容器可以和node3共享 /data1 和 /data2卷 ,這是在 docker run中使用 --volumes-from標記,如:
1、可以是來源不同鏡像,如:
# docker run --name node4 -itd --volumes-from node3 centos /bin/bash
[root@localhost ~]# docker run --name node4 -itd --volumes-from node3 centos /bin/bash ced022f71608c81fd2d689861809b033996351e4dc23c210eaeda675ff28a31b [root@localhost ~]# [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ced022f71608 centos "/bin/bash" 3 seconds ago Up 2 seconds node4 6fb05f94a368 test "/bin/bash" 12 minutes ago Up 12 minutes node3 f2bf65a82acc centos "/bin/bash" 2 hours ago Up 2 hours node1 d1c5d9eb3838 centos "/bin/bash" 2 hours ago Up 2 hours node2
驗證:
[root@localhost ~]# docker exec node3 ls / anaconda-post.log bin data1 data2 dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var [root@localhost ~]# docker exec node4 ls / anaconda-post.log bin data1 data2 dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
2、也可以是同一鏡像,如:
# docker run --name node5 -itd --volumes-from node3 test /bin/bash
[root@localhost ~]# docker run --name node5 -itd --volumes-from node3 test /bin/bash e6a2584eab2cce5b678f432d8eb48a762e5b1b2d57bcd76ee48f121c51ff282d [root@localhost ~]# [root@localhost ~]# docker exec node5 ls / anaconda-post.log bin data1 data2 dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
五、最佳實踐:數據容器
如果多個容器需要共享數據(如持久化數據庫、配置文件或者數據文件等),可以考慮創建一個特定的數據容器,該容器有1個或多個卷。
其它容器通過--volumes-from 來共享這個數據容器的卷。
因為容器的卷本質上對應主機上的目錄,所以這個數據容器也不需要啟動。
# docker run --name dbdata test echo "data container"
[root@localhost ~]# docker run --name dbdata test echo "data container" data container [root@localhost ~]# [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ac04a4f5d1ab test "echo 'data contai..." 9 seconds ago Exited (0) 9 seconds ago dbdata e6a2584eab2c test "/bin/bash" 8 minutes ago Up 8 minutes node5 ced022f71608 centos "/bin/bash" 16 minutes ago Up 16 minutes node4 6fb05f94a368 test "/bin/bash" 28 minutes ago Up 28 minutes node3 f2bf65a82acc centos "/bin/bash" 2 hours ago Up 2 hours node1 d1c5d9eb3838 centos "/bin/bash" 3 hours ago Up 3 hours node2 [root@localhost ~]# docker start dbdata dbdata [root@localhost ~]# [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ac04a4f5d1ab test "echo 'data contai..." 58 seconds ago Exited (0) 4 seconds ago dbdata e6a2584eab2c test "/bin/bash" 9 minutes ago Up 9 minutes node5 ced022f71608 centos "/bin/bash" 16 minutes ago Up 16 minutes node4 6fb05f94a368 test "/bin/bash" 29 minutes ago Up 29 minutes node3 f2bf65a82acc centos "/bin/bash" 2 hours ago Up 2 hours node1 d1c5d9eb3838 centos "/bin/bash" 3 hours ago Up 3 hours node2
說明:有個卷,容器之間的數據共享比較方便,但也有很多問題需要解決,如權限控制、數據的備份、卷的刪除等。
參考博客: