docker 數據卷管理


一. 數據卷管理

參考:  https://www.cnblogs.com/zangxueyuan/p/9142731.html

     https://blog.csdn.net/hellozhxy/article/details/80239646

     http://www.cnblogs.com/sparkdev/p/6216154.html

     https://www.cnblogs.com/sparkdev/p/8504050.html

 

1. 數據卷

數據卷是一個可供容器使用的特殊目錄,它繞過文件系統,可以提供很多有用的特性:
1.    數據卷可以在容器之間共享和重用。
2.    對數據卷的更改會立即生效。
3.    對數據卷的更新不會影響鏡像。
4.    數據卷會一直存在,直到沒有容器使用。

數據卷的使用,類似於 linux 下對目錄或文件進行 mount 操作。

2.使用數據卷的最佳場景

  • 在多個容器之間共享數據,多個容器可以同時以只讀或者讀寫的方式掛載同一個數據卷,從而共享數據卷中的數據。
  • 當宿主機不能保證一定存在某個目錄或一些固定路徑的文件時,使用數據卷可以規避這種限制帶來的問題。
  • 當你想把容器中的數據存儲在宿主機之外的地方時,比如遠程主機上或雲存儲上。
  • 當你需要把容器數據在不同的宿主機之間備份、恢復或遷移時,數據卷是很好的選擇。

 

3. 數據卷原理 

下圖描述了 docker 容器掛載數據的三種方式:

 

 

 

docker 數據卷的本質是容器中的一個特殊目錄。在容器創建的過程中,docker 會將宿主機上的指定目錄(一個以數據卷 ID 為名稱的目錄)掛載到容器中指定的目錄上。這里使用的掛載方式為綁定掛載(bind mount),所以掛載完成后的宿主機目錄和容器內的目標目錄表現一致。
比如我們執行下面的命令創建數據卷 hello,並掛載到容器 testcon 的 /world 目錄:

 

$ docker volume create hello
$ docker run -id --name testcon --mount type=volume,source=hello,target=/world ubuntu /bin/bash

實際上在容器的創建過程中,類似於在容器中執行了下面的代碼:

// 將數據卷 hello 在宿主機上的目錄綁定掛載到 rootfs 中指定的掛載點 /world 上
mount("/var/lib/docker/volumes/hello/_data", "rootfs/world", "none", MS_BIND, NULL)

 

4.  數據卷的創建、掛載

(1) 創建隨機名字的volume,並掛載到容器的/data目錄

docker  run  -it  -d --name u1  -v /data  ubuntu /bin/bash

說明:  在用 docker run 命令的時候,使用 -v 標記可以在容器內創建一個數據卷。多次使用 -v 標記可以創建多個數據卷

(2) 創建命名的數據卷並掛載

說明:  

法1:
docker volume create  u1_vol #創建
docker run -it -d --name u1 -v u1_vol:/data  ubuntu #將數據卷u1_vol掛載到容器的/data目錄


法2:
直接下面這條命令會創建命名數據卷后掛載。
docker run -it -d --name u1 -v u1_vol:/data 

(3) 將宿主機目錄 掛載到容器

docker run  -it -d  --name u1  -v /tmp:/opt  ubuntu  /bin/bash

 

(4)  將單個文件作為volume掛載到容器中.

#將當前目錄下的t.txt 文件掛載為 容器的/opt/t.txt
docker run  -it -d  --name u1  -v $(pwd)/t.txt:/opt/t.txt  ubuntu  /bin/bash

 

(5) 掛載數據卷為只讀 ro

docker run -it -d --name u1 -v u1_vol:/data:ro  ubuntu

 

(6) 指定數據卷是否可以共享 ,docker 默認的是 z,可以共享。 Z表示私有數據卷

 

(7) 使用Dockerfile 添加volume 

#使用VOLUME 指令向容器添加volume,與上面(1)相同
VOLUME  /data

VOLUME ["/data1","/data2"] #添加多個

在使用 docker build 命令生成鏡像並且以該鏡像啟動容器時會掛載一個數據卷到 /data 目錄。根據我們已知的數據覆蓋規則,如果鏡像中存在 /data 目錄,這個目錄中的內容將全部被復制到宿主機中對應的目錄中,並且根據容器中的文件設置合適的權限和所有者。


注意,VOLUME 指令不能掛載主機中指定的目錄。這是為了保證 Dockerfile 的可一致性,因為不能保證所有的宿主機都有對應的目錄
在實際的使用中,這里還有一個陷阱需要大家注意:在 Dockerfile 中使用 VOLUME 指令之后的代碼,如果嘗試對這個數據卷進行修改,這些修改都不會生效!下面是一個這樣的例子:

FROM ubuntu
RUN useradd nick
VOLUME /data     #VOLUME添加數據卷
RUN touch /data/test.txt   #對上面的數據卷修改是不會生效的
RUN chown -R nick:nick /data

通過這個 Dockerfile 創建鏡像並啟動容器后,該容器中存在用戶 nick,並且能夠看到 /data 目錄掛載的數據卷。但是 /data 目錄內並沒有文件 test.txt,更別說 test.txt 文件的所有者屬性了。要解釋這個現象需要我們了解通過 Dockerfile 創建鏡像的過程
Dockerfile 中除了 FROM 指令的每一行都是基於上一行生成的臨時鏡像運行一個容器,執行一條指令並執行類似 docker commit 的命令得到一個新的鏡像。這條類似 docker commit 的命令不會對掛載的數據卷進行保存。
所以上面的 Dockerfile 最后兩行執行時,都會在一個臨時的容器上掛載 /data,並對這個臨時的數據卷進行操作,但是這一行指令執行並提交后,這個臨時的數據卷並沒有被保存。因而我們最終通過鏡像創建的容器所掛載的數據卷是沒有被最后兩條指令操作過的。我們姑且叫它 "Dockerfile 中數據卷的初始化問題"。

 

下面的寫法可以解決 Dockerfile 中數據卷的初始化問題:

FROM ubuntu
RUN useradd nick
RUN mkdir /data && touch /data/test.txt
RUN chown -R nick:nick /data
VOLUME /data

通過這個 Dockerfile 創建鏡像並啟動容器后,數據卷的初始化是符合預期的。這是由於在掛載數據卷時,/data 已經存在,/data 中的文件以及它們的權限和所有者設置會被復制到數據卷中。
還有另外一種方法可以解決 Dockerfile 中數據卷的初始化問題。就是利用 CMD 指令和 ENTRYPOINT 指令的執行特點:與 RUN 指令在鏡像構建過程中執行不同,CMD 指令和 ENTRYPOINT 指令是在容器啟動時執行。因此使用下面的 Dockerfile 也可以達到對數據卷的初始化目的

FROM ubuntu
RUN useradd nick
VOLUME /data
CMD touch /data/test.txt && chown -R nick:nick /data && /bin/bash

 

5. 數據的覆蓋問題

  • 如果掛載一個空的數據卷到容器中的一個非空目錄中,那么這個目錄下的文件會被復制到數據卷中。
  • 如果掛載一個非空的數據卷到容器中的一個目錄中,那么容器中的目錄中會顯示數據卷中的數據。如果原來容器中的目錄中有數據,那么這些原始數據會被隱藏掉。

這兩個規則都非常重要,靈活利用第一個規則可以幫助我們初始化數據卷中的內容。掌握第二個規則可以保證掛載數據卷后的數據總是你期望的結果。

 

6.  共享數據卷與數據卷容器

數據卷的共享有兩種方式:

(1)  兩個docker之間直接共享數據卷

root@ubuntu:~# docker run  -it -d  --name u1  -v share_vol:/opt   ubuntu:14.04  /bin/bash  #將數據卷share_vol掛載到容器的/opt
7c9bcad41f3d9172699f0add3d6ba65d4a50c6ebac57fc5a042938198896e951
root@ubuntu:~# docker run  -it -d  --name u2  --volumes-from u1  ubuntu:14.04  /bin/bash   #u2 使用u1的數據卷
58a1a4dad1bed5372d9c30d6a8d13644f376426c1fa603de5bab5b52199a6095
root@ubuntu:~# docker exec -it u1 /bin/bash    #在容器u1 /opt 中新建文件
root@7c9bcad41f3d:/# cd opt/
root@7c9bcad41f3d:/opt# echo "u1">>1.txt
root@7c9bcad41f3d:/opt# exit
root@ubuntu:~# docker exec -it u2 /bin/bash   #容器u2與u1用的是共享數據卷,所以也能看見u1創建的文件,反之.
root@58a1a4dad1be:/# cd opt/
root@58a1a4dad1be:/opt# ls
1.txt
root@58a1a4dad1be:/opt# 

 

(2) 單獨創建一個數據容器,其它容器與之共享volume.推薦用這種方式。

 

如果用戶需要在容器之間共享一些持續更新的數據,最簡單的方式是使用數據卷容器。數據卷容器其實就是一個普通的容器,專門用它提供數據卷供其他容器掛載。

一個容器掛載了一個volume,即使這個容器停止運行,該volume仍然存在,其它容器也可以使用--volumes-from 與這個容器共享volume.

--volumes-from 可以使用多個,使得容器與多個已有容器共享volume。

 

創建數據卷容器,給容器掛載一個 volume后容器停止,好節約資源.

docker run --name share_docker  -v share_vol:/data  ubuntu /bin/bash

然后在其他容器中使用 --volumes-from 來掛載 share_docker容器中的數據卷。

root@ubuntu:~# docker run -it -d --name u1 --volumes-from share_docker  ubuntu /bin/bash
fdc15fca2a7e2545b0751315797cbe8fe868b7fd37c295cff8df8189f3254e5f
root@ubuntu:~# docker run -it -d --name u2 --volumes-from share_docker  ubuntu /bin/bash
98e511fb3ef5e6fe3a06ac0b6aa3a97e8881ffaeb48ccb585d3b8cd92b429d1d

(注意,命令中沒有指定數據卷的信息,也就是說新容器中掛載數據卷的目錄和源容器中是一樣的。)

 

此時容器 u1 和 u2 都掛載同一個數據卷到相同的目錄 /data。三個容器任何一個在該目錄下寫入數據其他容器都能看到。

 

但刪除掛載了數據卷的容器時,數據卷並不會被自動刪除。如果要刪除一個數據卷,必須在刪除最后一個還掛載着它的容器時顯式的使用 docker rm -v 命令來指定同時刪除關聯的容器。

 

數據容器的好處: 將上面需要共享數據的容器進行了較好的解耦,避免了容器之間共享數據而產生相互依賴.

 

7.  備份、恢復或遷移volume

volume作為數據的載體,在很多情況下需要對其中的數據進行備份遷移。一個很容易想到的辦法是使用 docker inspect 查找到volume 在宿主機上對應的文件夾的位置,然后復制其中的內容或者打包。這種做法不推薦,推薦使用  --volumes-from來實現.

 

備份: 

root@ubuntu:~# docker run --rm --volumes-from share_docker -v $(pwd):/backup ubuntu tar cvf /backup/data.tar /data
/data/
/data/2.txt
/data/1.txt
tar: Removing leading `/' from member names

說明:
share_docker容器包含了我們希望備份的一個volume,上面這行命令啟動了另外一個臨時容器,這個容器掛載了兩個volume,第一個volume來自 share_docker 的共享,也就是需要備份的
volume。第二個volume將宿主機的當前目錄掛載到臨時容器的/backup目錄。容器運行后要將備份內容(/data文件夾)備份到容器的/backup/data.tar.然后刪除容器,備份后的data.tar
就留在了宿主機的當前目錄.
 
        

 

 

恢復: 

創建需要恢復數據的目標容器:
root@ubuntu:~# docker run -it -d --name back_docker -v  back_vol:/data ubuntu /bin/bash 
e24b5e898c2016b7ebda93a266a351c6d9a47e6a3f828dac3c8a56cadfc0ce26


啟動臨時容器用於恢復。
docker run --rm --volumes-from  back_docker -v $(pwd):/backup ubuntu tar xvf /backup/data.tar -C /

data/
data/2.txt
data/1.txt
root@ubuntu:~# docker exec  -it back_docker  /bin/bash  #查看發現數據恢復
root@e24b5e898c20:/# cd data/
root@e24b5e898c20:/data# ls
1.txt  2.txt

 

 

8.  使用 mount 語法掛載數據卷

之前我們使用 --volume(-v) 選項來掛載數據卷,現在 docker 提供了更強大的 --mount 選項來管理數據卷。mount 選項可以通過逗號分隔的多個鍵值對一次提供多個配置項,因此 mount 選項可以提供比 volume 選項更詳細的配置。使用 mount 選項的常用配置如下:
type 指定掛載方式,我們這里用到的是 volume,其實還可以有 bind 和 tmpfs。
volume-driver 指定掛載數據卷的驅動程序,默認值是 local。
source 指定掛載的源,對於一個命名的數據卷,這里應該指定這個數據卷的名稱。在使用時可以寫 source,也可以簡寫為 src。
destination 指定掛載的數據在容器中的路徑。在使用時可以寫 destination,也可以簡寫為 dst 或 target。
readonly 指定掛載的數據為只讀。
volume-opt 可以指定多次,用來提高更多的 mount 相關的配置。
下面我們看個具體的例子:

$ docker volume create hello
$ docker run -id --mount type=volume,source=hello,target=/world ubuntu /bin/bash

我們創建了名稱為 hello 的數據卷,然后把它掛在到容器中的 /world 目錄。通過 inspect 命令查看容器的詳情中的 "Mounts" 信息可以驗證實際的數據卷掛載結果.

 

使用 volume driver 把數據存儲到其它地方

除了默認的把數據卷中的數據存儲在宿主機,docker 還允許我們通過指定 volume driver 的方式把數據卷中的數據存儲在其它的地方,比如 Azrue Storge 或 AWS 的 S3。
簡單起見,我們接下來的 demo 演示如何通過 vieux/sshfs 驅動把數據卷的存儲在其它的主機上。
docker 默認是不安裝 vieux/sshfs 插件的,我們可以通過下面的命令進行安裝:

$ docker plugin install --grant-all-permissions vieux/sshfs

然后通過 vieux/sshfs 驅動創建數據卷,並指定遠程主機的登錄用戶名、密碼和數據存放目錄:

docker volume create --driver vieux/sshfs \
    -o sshcmd=nick@10.32.2.134:/home/nick/sshvolume \
    -o password=yourpassword \
    mysshvolume

注意,請確保你指定的遠程主機上的掛載點目錄是存在的(demo 中是 /home/nick/sshvolume 目錄),否則在啟動容器時會報錯。
最后在啟動容器時指定掛載這個數據卷:

docker run -id \
    --name testcon \
    --mount type=volume,volume-driver=vieux/sshfs,source=mysshvolume,target=/world \
    ubuntu /bin/bash

你在容器中 /world 目錄下操作的文件都存儲在遠程主機的 /home/nick/sshvolume 目錄中。進入容器 testcon 然后在 /world 目錄中創建一個文件,然后打開遠程主機的  /home/nick/sshvolume 目錄進行查看,你新建的文件是不是已經出現在那里了!

 

 

docker volume 使用NFS存儲

 

#NFS服務端,配置nfs共享
yum install nfs-utils rpcbind -y
mkdir -p /data/nfs/docker
echo "/data/nfs *(rw,no_root_squash,sync)">>/etc/exports
exportfs -r
systemctl start rpcbind nfs-server
systemctl enable rpcbind nfs-server
showmount -e localhost


 #nfs客戶端
yum install -y nfs-utils rpcbind

 #創建volume 連接 172.16.50.43:/data/nfs
docker volume create --driver local \
  --opt type=nfs \
  --opt o=addr=172.16.50.43,rw \
  --opt device=:/data/nfs \
  volume-nfs

 #查看
docker volume ls
docker volume inspect volume-nfs

 #容器使用volume-nfs
docker run -dit --name busybox7 -v volume-nfs:/nfs busybox
 #查看
docker inspect -f {{.Mounts}} busybox7
df -h |grep /data/nfs
 #volume目錄/var/lib/docker/volumes/volume-nfs/_data自動掛載到了nfs服務上

 #容器創文件測試
docker exec busybox7 touch /nfs/testfiles.txt

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM