了解联合文件系统后,我们知道,镜像是只读的,类似共享文件形式让多个容器使用。如果要在容器里修改文件,即镜像里的文件,那该如何修改?
为了解决这个问题,docker 引入了 写时复制(copy-on-write),需要修改文件操作时,会先从镜像里把要写的文件复制到自己的文件系统中进行修改。
1.容器的数据卷
1.1.什么是数据卷
数据卷是经过特殊设计的目录,可以绕过联合文件系统(UFS),为一个或者多个容器提供访问,数据卷设计的目的,在于数据的永久存储,它完全独立于容器的生存周期,因此,docker 不会在容器删除时删除其挂载的数据卷,也不会存在类似的垃圾收集机制,对容器引用的数据卷进行处理,同一个数据卷可以只支持多个容器的访问。
1.2.数据卷特点
数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,这些数据会被拷贝到新初始化的数据卷中
数据卷可以在容器之间共享和重用
可以对数据卷里的内容直接进行修改
数据卷的变化不会影像镜像的更新
卷会一直存在,即使挂载数据卷的容器已经被删除
1.3.Docker 提供三种方式将数据从宿主机挂载到容器
Volumes: Docker 管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。
Bind mounts: 将宿主机的任意位置的文件或者目录挂载到容器中。
tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用tmps,同时避免写入容器可写层提高性能。
2.volume 持久化方案
2.1.volume 简介
volume是Docker官方推荐的持久化方案,默认情况下,volume的存储空间来自于宿主机文件系统中的某个目录,如/var/lib/docker/volumes/,docker系统外的程序无权限修改其中的数据。
一个volume可以同时供多个container使用,如果没有container使用volume,其不会自动删除,用户需运行docker volume prune明确删除。
如果用户显式创建volume,则需要给其指定一个名称;如果是隐式创建volume,Docker会自动为其分配一个在宿主机范围内唯一的名字。
2.2.volume 特点
docker volume create -v 创建 volume 时,宿主机目录路径必须以/或~/开头,否则 Docker 会将其当成volume 而不是bind mount。
如果容器中的目录不存在,docker会自动创建目录;如果容器中的目录已有内容,docker会使用宿主机上目录的内容覆盖容器目录的内容。
2.3.常用命令与实操
## 管理卷
sudo docker volume create test-vol # docker volume ls
sudo docker volume inspect test-vol
## 用卷创建一个容器
sudo docker run -itd --rm --name centos7-zlm-image-container -v test-vol:/home/volume centos7-zlm-image /bin/bash
sudo docker run -itd --rm --name centos7-zlm-image-container --mount type=volume,src=test-vol,dst=/home/volume centos7-zlm-image /bin/bash
## 进入容器
sudo docker exec -it centos7-zlm-image-container /bin/bash
## 清理
sudo docker stop centos7-zlm-image-container # docker rm test-test
## 删除卷
sudo docker volume rm test-vol
## 注意:如果没有指定卷,自动创建。
创建数据卷,启动容器使用 test-vol 这个数据卷
# 清空无用的卷
[test@localhost ~]$ sudo docker volume prune
[sudo] test的密码:
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
09d989283ec5e1c70b0825fff898d57128a04cff7d9a3b5ca26cf9730fe5a7a5
97f2c76715724f2a4695db654df39aa304bbeff10289595ac1d4ff1a967c4e62
ed750105d8244db3d5d5f7a468bec397807edd70934986725dbc6d04e4cd5557
......
Total reclaimed space: 0B
# 创建卷
[test@localhost ~]$ sudo docker volume create test-vol
test-vol
# 查看卷信息
[test@localhost ~]$ sudo docker volume inspect test-vol
[
{
"CreatedAt": "2023-07-04T09:59:31+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/test-vol/_data",
"Name": "test-vol",
"Options": {},
"Scope": "local"
}
]
# 查看/var/lib/docker/volumes 多了一个目录
[test@localhost ~]$ sudo ls /var/lib/docker/volumes
backingFsBlockDev metadata.db test-vol
# 创建容器,绑定卷到容器目录
[test@localhost ~]$ sudo docker run -itd --rm --name centos7-zlm-image-container -v test-vol:/home/volume centos7-zlm-image /bin/bash
6c4f9e398ec446777613b599f0182a902d01ba3af468f8f865ba6dd6fcfb7169
# 进入容器
[test@localhost ~]$ sudo docker exec -it centos7-zlm-image-container /bin/bash
# 容器内创建文件
[root@6c4f9e398ec4 /]# cd /home/volume/
[root@6c4f9e398ec4 volume]# ls
[root@6c4f9e398ec4 volume]# touch hello.txt
[root@6c4f9e398ec4 volume]# exit
exit
# 查看本地卷,多了了hello.txt文件
[test@localhost ~]$ sudo ls /var/lib/docker/volumes/test-vol/_data
hello.txt
# 停止容器
[test@localhost ~]$ sudo docker stop centos7-zlm-image-container
centos7-zlm-image-container
# 删除卷
[test@localhost ~]$ sudo docker volume rm test-vol
test-vol
# 删除本地目录
[test@localhost ~]$ sudo ls /var/lib/docker/volumes/test-vol/_data
ls: 无法访问/var/lib/docker/volumes/test-vol/_data: 没有那个文件或目录
[test@localhost ~]$
2.4.volume 使用场景
通过使用第三方提供的volume driver,用户可以将数据持久到远程主机或者云存储中。
(1)多个容器间共享数据。
(2)宿主机不保证存在固定目录结构。
(3)持久化数据到远程主机或者云存储而非本地。
(4)需要备份、迁移、合并数据时。停止container,将volume整体复制,用于备份、迁移、合并等
其实跟命名卷类似,参考docker学习(六)卷Volume
3.Bind Mounts 持久化方案
3.1.bind mount 简介
bind mount 持久化方式将宿主机中的文件、目录挂载到容器上,相应文件、目录可以被宿主机读写,也可以被容器读写。
bind mount 持久化方式可以将数据存储在宿主机器任何地方,但会依赖宿主机的目录结构,因此不能通过docker CLI直接管理,并且非Docker 进程和 Docker 进程都可以修改。
3.2.bind mount 特点
(1)性能最好
(2)Docker容器与宿主机耦合过于紧密,移植性较差。
3.3.常用命令与实操
#用卷创建一个容器:
sudo docker run -itd --rm --name centos7-zlm-image-container --mount type=bind,src=/opt/bind,dst=/home/bind centos7-zlm-image /bin/bash
sudo docker run -itd --rm --name=centos7-zlm-image-container -v /opt/bind:/home/bind centos7-zlm-image /bin/bash
# 验证绑定:
sudo docker inspect centos7-zlm-image-container
# 清理:
sudo docker stop centos7-zlm-image-container
sudo docker rm centos7-zlm-image-container
[test@localhost ~]$ sudo docker run -itd --rm --name centos7-zlm-image-container --mount type=bind,src=/opt/bind,dst=/home/bind centos7-zlm-image /bin/bash
bb9c7a1a48ee44462449bddb32749e4cbd4a9a675d26dcc600db2999820479e0
[test@localhost ~]$ sudo docker exec -it centos7-zlm-image-container /bin/bash
[root@bb9c7a1a48ee /]# cd home/bind/
[root@bb9c7a1a48ee bind]# touch hello.txt
[root@bb9c7a1a48ee bind]# exit
exit
[test@localhost ~]$ ls /opt/bind/
hello.txt
[test@localhost ~]$
[test@localhost ~]$ sudo docker inspect centos7-zlm-image-container
[
{
......
"HostConfig": {
"Binds": null,
......
"Mounts": [
{
"Type": "bind",
"Source": "/opt/bind",
"Target": "/home/bind"
}
],
......
},
......
"Mounts": [
{
"Type": "bind",
"Source": "/opt/bind",
"Destination": "/home/bind",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
......
}
]
[test@localhost ~]$
3.4.bind mount 使用场景
(1)container共享宿主机配置文件,如docker将宿主机文件/etc/resov.conf文件bind mount到容器上,两者会使用相同的DNS服务器。
(2)开发环境中build容器化。开发过程中将build过程container化,将宿主机上源代码目录bind mount到build container中。修改代码后,运行build container的build命令,build container则将build结果写入另一个bind mount的目录中。
(3)监控服务container化。读取宿主机固定文件中的数据实现监控。
3.5.bind mount 注意事项
(1)-v 宿主机目录路径必须以/或~/开头,否则docker会将其当成是volume 而不是bind mount。
(2)如果宿主机上的目录不存在,docker会自动创建目录(多级的绝对路径好像不行)。
(3)如果容器中的目录不存在,docker会自动创建目录。
(4)如果容器中目录已有内容,那么docker会使用宿主机上目录的内容覆盖容器目录的内容。
4.tmpfs mount 持久化方案
4.1.tmpfs 简介
tmpfs mount只在Linux主机内存中持久化,是临时性的。当容器停止,tmpfs mount会被移除,通常用于临时存放敏感文件。
tmpfs mounts 可选选项:
–tmpfs-size: 挂载的tmpfs的字节数,默认不受限制
–tmpfs-mode: tmpfs的文件模式,例如700或1700.默认值为1777,这意味着任何用户都有写入权限
使用–tmpfs参数无法指定任何其他的可选项,并且不能用于Swarm Service(集群节点服务)。
4.2.tmpfs 特点
(1)只能在Linux主机内存中,不会持久化到磁盘。
(2)不支持多容器间共享。与卷和绑定装入不同,您无法tmpfs在容器之间共享装载。只有在Linux上运行Docker时才能使用此功能。
4.3.常用命令与实操
sudo docker run -itd --rm --name centos7-zlm-image-container --tmpfs /home/tmpfs centos7-zlm-image /bin/bash
sudo docker run -itd --rm --name centos7-zlm-image-container --tmpfs /home/tmpfs:size=512M,mode=1777 centos7-zlm-image /bin/bash
sudo docker run -itd --rm --name centos7-zlm-image-container --mount type=tmpfs,destination=/home/tmpfs,tmpfs-mode=1770 centos7-zlm-image /bin/bash
sudo docker stop centos7-zlm-image-container
[test@localhost ~]$ sudo docker run -itd --rm --name centos7-zlm-image-container --tmpfs /home/tmpfs centos7-zlm-image /bin/bash
[sudo] lianaipeng 的密码:
44521bf7c2ef4cf01b0b0b0e66d8f8ab9ef98cef3c0e45cf5477988e030332f8
[test@localhost ~]$
[test@localhost ~]$ sudo docker exec -it centos7-zlm-image-container /bin/bash
[root@44521bf7c2ef /]# ls /home/tmpfs/
[root@44521bf7c2ef /]# exit
exit
[test@localhost ~]$ sudo docker inspect centos7-zlm-image-container
[
{
......
"HostConfig": {
......
"Tmpfs": {
"/home/tmpfs": ""
},
......
},
......
}
]
[test@localhost ~]$
4.4.tmpfs 使用场景
Docker可将用户名与密码等敏感数据保存在某个数据库中,当启动需要访问这些敏感数据的container或者service时,docker会在宿主机上创建一个tmpfs,然后将敏感数据从数据库读出写到tmpfs中,再将tmpfs mount到container中,安样能保证数据安全。当容器停止运行时,则相应的tmpfs也从系统中删除。
5.mount 总结
–mount:由多个键值对组成,以逗号分隔,每个键=组由一个元组组成。
该type安装件,其可以是bind,volume,或 tmpfs。
将安装在容器中destination的路径作为挂载的值。可以指定为destination,dst或target。也支持source,src。
sudo docker run -itd --rm --name centos7-zlm-image-container --mount type=volume,src=test-vol,dst=/home/volume centos7-zlm-image /bin/bash
sudo docker run -itd --rm --name centos7-zlm-image-container --mount type=bind,src=/opt/bind,dst=/home/bind centos7-zlm-image /bin/bash
sudo docker run -itd --rm --name centos7-zlm-image-container --mount type=tmpfs,destination=/home/tmpfs,tmpfs-mode=1770 centos7-zlm-image /bin/bash