概述
当 docker 容器实例启动之后,我们需要对容器内的数据进行管理,主要有两种管理方式:
- 数据卷 - 一种将容器内的数据持久化备份到宿主机目录的方式,也就是目录映射
- 挂载 - 以挂载的方式将容器内的数据持久化备份到宿主机目录
数据卷
上一篇文章提到这样的一条命令:
Shell > docker run -d -p 5000:5000 --name="docker_registry" --restart always \
-v /docker/data/registry:/var/lib/registry registry:latest
选项说明:
-d- 以守护进程即后台运行的方式运行这个容器实例-p 5000:5000- 端口映射,冒号左边为宿主机的端口,冒号右边为容器实例的端口--name="docker_registry"- 定义这个容器实例的名称--restart always- 宿主机重启时,当前容器实例也会自启动-v /docker/data/registry:/var/lib/registry- 目录映射,即容器数据卷。冒号左边为宿主机的目录,冒号右边为容器实例的目录
有时,执行目录映射可能会遇到诸如 "cannot open directory" 之类的权限错误,则需要添加 --privileged=true 选项,表示容器内的 root 是真正意义上 root 用户。
Q:什么是数据卷?有什么用?
前面说过 docker cp 以及容器的导出(docker export)与导入(docker import),虽然也能备份数据,但是它们并不是实时的、可持续的。于是在 Docker 当中引入了一个被称为 「数据卷」 的东西。
比如你在团队中用镜像生成了容器实例,假如有一天某个人手欠将其删除了,里面的数据是找不到的。「数据卷」就是完成容器内数据的实时备份或共享,即将当前宿主机的目录与容器内的目录做一个映射关系,将容器内的数据持久化备份到本地主机目录,即使将容器实例删除了,数据还是存在的。「数据卷」的主要特点有:
- 数据卷可以在容器之间共享或重用数据
- 数据卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
Q:怎么样运行一个带有容器数据卷的容器实例呢?
有两种方式,第一种是命令行;第二种是 Dockerfile。
Q:怎么样查看容器实例的挂载信息?
Shell > docker inspect 容器名称或容器ID
比如:
Shell > docker inspect docker_registry
...
"Mounts": [
{
"Type": "bind",
"Source": "/docker/data/registry",
"Destination": "/var/lib/registry",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
...
如您所见,容器数据卷的权限默认为 RW(可读可写),关于数据卷的权限我们稍后将说明。
数据卷的演示
以 fedora:latest 镜像来举例说明:
Shell > docker pull fedora:latest
Shell > mkdir -p /tmp/fedora44/
Shell > docker run -it --name="f1" -v /tmp/fedora44/:/tmp/data/ --privileged=true fedora:latest /bin/bash
[root@6b036d8b572f /]# cd /tmp/data/
[root@6b036d8b572f data]# echo "fedora44" >> fedora44_file.txt
ctrl + p + q
Shell > ls -l /tmp/fedora44/fedora44_file.txt
-rw-r--r-- 1 root root 9 4月 3 17:40 /tmp/fedora44/fedora44_file.txt
若此时在宿主机的目录中创建文件或新目录,也可以被映射到容器实例中:
Shell > touch /tmp/fedora44/a.txt
Shell > docker exec -it f1 /bin/bash
[root@6b036d8b572f /]# ls -l /tmp/data/
total 4
-rw-r--r-- 1 root root 0 May 30 06:34 a.txt
-rw-r--r-- 1 root root 9 May 30 06:33 fedora44_file.txt
ctrl + p + q
若此时将容器实例停止且删除,数据依然被保留在宿主机的映射目录中:
Shell > docker stop f1 && docker rm f1
Shell > tree -hugp /tmp/fedora44/
/tmp/fedora44/
├── [-rw-r--r-- root root 0] a.txt
└── [-rw-r--r-- root root 9] fedora44_file.txt
0 directories, 2 files
当容器实例停止后,若此时在宿主机的映射目录中创建了新文件或新目录,它们依然可以在容器实例启动之后同步过来。
docker run 单个命令中可以使用多个 -v 选项,用来指定多个数据卷。数据卷的权限
如上面所示,数据卷默认的权限就是读写权限(RW),所以这两条命令是等价的:
Shell > docker run -it --name="f1" -v /tmp/fedora44/:/tmp/data/:rw \
--privileged=true fedora:latest /bin/bash
Shell > docker run -it --name="f1" -v /tmp/fedora44/:/tmp/data/ \
--privileged=true fedora:latest /bin/bash
如果要对容器实例内的数据卷限制,则可以将其修改为只读(ro,read only)。当使用 docker run 或者 docker exec 进入到容器实例里面时,对应的映射目录下不能创建新文件与新目录。当然,这并不影响宿主机在映射目录中创建新目录或新文件并保持与容器实例的目录同步。
来看这样的例子:
Shell > rm -rf /tmp/fedora44/*
Shell > docker run -it --name="f2" -v /tmp/fedora44/:/tmp/data/:ro \
--privileged=true fedora:latest /bin/bash
[root@bf84a5fc84b5 /]# echo "123" >> /tmp/data/tmp.txt
bash: /tmp/data/tmp.txt: Read-only file system
ctrl + p + q
Shell > echo "FEDORA44" > /tmp/fedora44/b.txt
Shell > mkdir /tmp/fedora44/d1/
Shell > docker exec -it f2 /bin/bash
[root@bf84a5fc84b5 /]# ls -lh /tmp/data/
total 8.0K
-rw-r--r-- 1 root root 9 May 30 06:48 b.txt
drwxr-xr-x 2 root root 4.0K May 30 06:48 d1
删除对应的演示数据:
Shell > docker stop f2 && docker rm f2 && rm -rf /tmp/fedora44/
数据卷的继承与共享
利用 feodora:latest 镜像生成名称为 f10 的容器实例:
Shell > mkdir -p /docker/host/data/
Shell > docker pull fedora:latest
Shell > docker run -it --name=f10 -v /docker/host/data/:/tmp/data/:rw \
--privileged=true fedora:latest /bin/bash
[root@9ad2601a08b1 /]# touch /tmp/data/first_file1.txt
ctrl + p + q
Shell > touch /docker/host/data/host_file1.txt
利用 feodora:latest 镜像生成名称为 f20 的容器实例,且继承 f10 的数据卷规则:
Shell > docker run -it --name=f20 --volumes-from f10 --privileged=true fedora:latest /bin/bash
# 继承了数据卷规则且同步了数据
[root@fb48b7953da0 /]# ls -lh /tmp/data/
total 0
-rw-r--r-- 1 root root 0 May 30 06:57 first_file1.txt
-rw-r--r-- 1 root root 0 May 30 06:57 host_file1.txt
# 创建一个新文件
[root@fb48b7953da0 /]# touch /tmp/data/second_file2.txt
ctrl + p + q
由于 f20 容器继承了 f10 的数据卷规则,所以即使 f10 容器停止了,在宿主机中创建的新文件依然可以正常同步到 f20 中,如下:
Shell > docker stop f10
Shell > touch /docker/host/data/host_file2.txt
Shell > docker exec -it f20 /bin/bash
[root@fb48b7953da0 /]# ls -lh /tmp/data/
total 0
-rw-r--r-- 1 root root 0 May 30 06:57 first_file1.txt
-rw-r--r-- 1 root root 0 May 30 06:57 host_file1.txt
-rw-r--r-- 1 root root 0 May 30 07:00 host_file2.txt
-rw-r--r-- 1 root root 0 May 30 06:59 second_file2.txt
ctrl + p + q
将 f10 容器实例启动,正常同步文件:
Shell > docker start f10
Shell > docker exec -it f10 /bin/bash
[root@9ad2601a08b1 /]# ls -lh /tmp/data/
total 0
-rw-r--r-- 1 root root 0 May 30 06:57 first_file1.txt
-rw-r--r-- 1 root root 0 May 30 06:57 host_file1.txt
-rw-r--r-- 1 root root 0 May 30 07:00 host_file2.txt
-rw-r--r-- 1 root root 0 May 30 06:59 second_file2.txt
ctrl + p + q
删除数据卷
数据卷的生命周期一直持续到没有容器使用它为止
当删除了容器实例后,容器实例内的映射目录自动会被删除。但是!宿主机上的映射目录并不会被删除。
挂载
与数据卷能够实现同一效果,只是在 docker 命令当中使用的是 --mount 选项。
比如这样的一个例子:
Shell > mkdir /tmp/data/
Shell > docker run -it --name="Fedora44_Container" \
--mount type=bind,source=/tmp/data/,target=/tmp/data/,ro=true fedora:latest /bin/bash
[root@3d81dd6d9733 /]#
- source 指定宿主机的目录路径;
- target 指定容器实例的目录路径;
- ro 指定是否是只读
--mount 选项时需要注意!宿主机的目录路径必须提前存在,否则 Docker 会报错。










