1. docker volume 簡介
文章 介紹了 docker image,它由一系列只讀層構成,通過 docker image 可以提高鏡像構建,存儲和分發的效率,節省時間和存儲空間。然而 docker image 還是存在一些問題,如下:
- 多個容器之間的數據無法共享。
- 當刪除容器時,容器產生的數據將丟失。
基於這幾點 Docker 引入了 volume 機制。 volume 是存在於一個或多個容器中的特定文件或文件夾,這個目錄以獨立於聯合文件系統的形式在宿主機上存在。volume 機制的主要優點如下:
- volume 能在不同容器間共享數據。
- volume 的生存周期獨立於容器,刪除容器,volume 依然存在。
- volume 中數據的操作不會影響到鏡像。
2. 創建 volume
創建 volume,將 volume attach 到容器中,刪除容器,查看 volume 的使用情況。
查看創建 volume 使用的驅動:
[root@k8s-master-node-1 centos]# docker info | grep -i volume
Volume: local
創建 volume:
[root@k8s-master-node-1 centos]# docker volume create chunqiu
chunqiu
[root@k8s-master-node-1 centos]# docker volume inspect chunqiu
[
{
"CreatedAt": "2021-05-10T09:09:49Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/chunqiu/_data",
"Name": "chunqiu",
"Options": {},
"Scope": "local"
}
]
volume 在宿主機上的目錄 (Mountpoint) 是 /var/lib/docker/volumes/<volume_name>/_data。將 volume attach 到容器 ubuntu 上:
[root@k8s-master-node-1 centos]# docker run -it -v chunqiu:/data --name=ubuntu ubuntu /bin/bash
root@8c4611b025f6:/# ls /data/
root@8c4611b025f6:/#
使用 -v 選項將 volume attach 到容器內,並指定容器的目錄為 /data。寫文件到 data 目錄:
/* 容器內寫文件 */
root@8c4611b025f6:/# cd data/
root@8c4611b025f6:/data# touch chunqiu
[root@k8s-master-node-1 _data]# ls -l /var/lib/docker/volumes/chunqiu/_data/
total 0
-rw-r--r-- 1 root root 0 May 10 09:44 chunqiu
/* 容器外寫文件 */
[root@k8s-master-node-1 _data]# touch handsomeBoy
root@8c4611b025f6:/data# ls -l
total 0
-rw-r--r-- 1 root root 0 May 10 09:44 chunqiu
-rw-r--r-- 1 root root 0 May 10 09:49 handsomeBoy
容器和宿主機上目錄建立映射。刪除容器,查看 volume 是否存在:
[root@k8s-master-node-1 _data]# docker rm ubuntu
ubuntu
[root@k8s-master-node-1 _data]# ls -l
total 0
-rw-r--r-- 1 root root 0 May 10 09:44 chunqiu
-rw-r--r-- 1 root root 0 May 10 09:49 handsomeBoy
刪除容器 volume 依然存在。
3. volume 與 image
探索 volume 與 image 的關系,volume 映射的文件/文件夾會反映在“讀寫層”,和靜態的 image 沒有關系。當 volume 映射的文件/文件夾和 image 同名時,image 中內容將被隱藏,從而保持 volume 和宿主機上文件/文件夾的一致性。
創建 volume 映射到容器內的 /home 目錄,查看 home 目錄下文件變化情況:
[root@k8s-master-node-1 _data]# docker run -it b9fd190d76e0 /bin/bash
root@c536d00399fa:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
root@c536d00399fa:/# ls home/
demo
root@c536d00399fa:/home# exit
[root@k8s-master-node-1 _data]# docker run -it -v chunqiu:/home b9fd190d76e0 /bin/bash
root@faebe07c5405:/# cd home/
root@faebe07c5405:/home# ls
chunqiu handsomeBoy
home 目錄下的 demo 文件被隱藏,取而代之的是宿主機上 volume 的 MountPoint 下的文件。
思考:如果取代的是 /etc 目錄會怎么樣?
4. 容器間共享目錄
volume 能在不同容器間共享數據,新建一個容器使它和 ubuntu 共享 volume chunqiu:
[root@k8s-master-node-1 centos]# docker run -it --volumes-from ubuntu ubuntu /bin/bash
root@a66c276b1954:/# ls data/
chunqiu handsomeBoy
5. docker commit
將容器 commit 為鏡像,容器內的 volume 數據會保存到鏡像中嗎?做個小實驗如下:
[root@k8s-master-node-1 centos]# docker commit ubuntu
sha256:e938f5251682f9b48ce344f1372d39b2ef6b7b4b6f8160afa38fe94492de158e
[root@k8s-master-node-1 centos]# docker image ls | grep e938
<none> <none> e938f5251682 12 seconds ago 72.7MB
[root@k8s-master-node-1 centos]# docker run -it e938f5251682 /bin/bash
root@11f74c3587e1:/# ls
bin boot data dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
root@11f74c3587e1:/# ls data/
root@11f74c3587e1:/data#
可以看到,data 目錄下並沒有 volume 的文件,這是因為 docker commit 不會對掛載的 volume 進行保存。這也說明了為什么在 dockerfile 中這么寫找不到文件 file:
FROM ubuntu
RUN useradd foo
VOLUME /data
RUN touch /data/file
RUN chown -R foo:foo /data
6. docker volume 原理
docker 創建 volume 的過程實際上是在 mount namespace 添加做 mount 操作的過程,具體可看這里了解更多,這里就不做贅述啦~