Overlay FS存储原理:
Overlay FS结构分为三层:LowerDir、UpperDir、MergedDir
LowerDir (只读层) 只读的 image layer,其实就是 rootfs, 在使用 Dockfile 构建镜像的时候, Image Layer 可以分很多层,所以对应的 lowerdir 会很多(源镜像)。
UpperDir (读写层) upperdir 则是在 lowerdir 之上的一层, 为读写层。容器在启动的时候会创建, 所有对容器的修改, 都是在这层。 比如容器启动写入的日志文件,或者是应用程序写入的临时文件。
MergedDir (合并层) merged 目录是容器的挂载点,在用户视角能够看到的所有文件,都是从这层展示的。
WorkDir (工作目录) workdir 是 OverlayFS 内部用于处理写入操作的 临时目录。
LowerDir 镜像中所有的层 /var/lib/docker/overlay2/
UpperDir 容器中可写层 /var/lib/docker/overlay2/
MergedDir 进入容器看到层 /var/lib/docker/overlay2/
/var/lib/docker/overlay2 #存放镜像 容器写的数据 日志
/var/lib/docker/image #存放每一层的数据
/var/lib/docker/containers #存放容器启动的基础信息
数据卷特性:
docker镜像由多个只读层叠加而成,启动容器时docker会加载只读镜像层并在镜像顶部添加一个读写层
写时复制(copy-on-write)机制:在运行中容器里修改文件,该文件会从lowerDir复制到upperDir,修改完成后直接覆盖lowerDir文件
关闭并重启容器,其数据不受影响;但删除docker容器则其数据将会全部丢失
卷是容器上的一个多个"目录",此类目录可绕过联合文件系统,与宿主机上的目录“绑定”
数据卷类型
volumes 存储在宿主机/var/lib/docker/volumes/
bind mounts 可以存储在宿主机系统的任何位置,他们甚至可以是重要的系统文件或目录
tmpfs 仅存储在宿主机的内存中,不会写入主机文件系统
#创建volume [root@linxuan ~]$ docker volume create my-vol my-vol #查看volumes [root@linxuan ~]$ docker volume ls local my-vol [root@linxuan ~]$ ll /var/lib/docker/volumes/ total 36 brw------- 1 root root 253, 1 Jan 4 14:16 backingFsBlockDev -rw------- 1 root root 65536 Jan 8 15:11 metadata.db drwx-----x 3 root root 4096 Jan 8 15:05 my-vol
挂载到容器中 docker run -v
[root@linxuan ~]$ docker run -v my-vol:/data -d nginx:1.22.1 ###my-vol是我们创建的卷;/data是把卷挂载到容器的/data目录 [root@linxuan ~]$ docker exec -it 5963c53eb20bce943df35de45aee6fdf057f4f114947855e23b5ef064ba12005 sh # cd data # pwd /data # touch docker-in [root@linxuan ~]$ cd /var/lib/docker/volumes/my-vol/_data/ [root@linxuan /var/lib/docker/volumes/my-vol/_data]$ ls docker-in ###在容器里创建的文件docker-in,宿主机也有一份 [root@linxuan /var/lib/docker/volumes/my-vol/_data]$ touch docker-out # ls docker-in docker-out ###在外部创建一个文件,容器里也有 [root@linxuan ~]$ docker rm 5963c53eb20b --force [root@linxuan /var/lib/docker/volumes/my-vol/_data]$ ls docker-in docker-out ###容器被删除了,文件也不会丢失
另外,docker run -v 卷:/dir ;-v参数后面跟的卷是可以自动创建的,不需要非得先创建再挂载
自动创建匿名卷(建议少用)
[root@linxuan ~]$ docker run -v /data -d nginx:1.22.1 a63068de1d57d086ec444b06d5000714c415de17fac62999825585766d0cf58c [root@linxuan ~]$ docker volume ls DRIVER VOLUME NAME local 411a9e7c07b3c4e97c4e8e0bca32499df83ef619c85f4877c9fc228cefb4b89c
dockerfile也是创建匿名卷的一种方式
VOLUME [/var/lib/mysql]
效果等同于docker run -v /var/lib/mysql -d -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
也可以挂载到宿主机的目录上
将容器的/var/lib/mysql挂载到宿主机的/data/mysql目录:
[root@linxuan ~]$ docker run -v /data/mysql:/var/lib/mysql -d -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
挂载宿主机任意文件/目录
挂载目录
[root@linxuan ~]$ docker run -v /data/dokcer-docker:/data -d nginx:1.22.1 [root@linxuan ~]$ ll /data/ total 4 drwxr-xr-x 2 root root 4096 Jan 8 16:08 dokcer-docker ##docker会自动创建目录 [root@linxuan ~]$ docker exec -it 09ba4623028a856ba220c4d1444827721c985575a3d5fd161eb769501b3baae4 sh # cd /data # touch docker-in [root@linxuan ~]$ cd /data/dokcer-docker/ [root@linxuan /data/dokcer-docker]$ ls docker-in [root@linxuan /data/dokcer-docker]$ touch docker-out # ls ##容器内 docker-in docker-out
挂载宿主机文件
[root@linxuan ~]$ docker run -v /etc/passwd:/tmp/passwd -it centos:7 bash [root@41809f76446e /]# cd /tmp [root@41809f76446e tmp]# ls ks-script-DrRL8A passwd yum.log ##这种情况在容器里改了passwd文件,宿主机的passwd也会更改! [root@linxuan ~]$ docker run -v /etc/passwd:/tmp/passwd:ro -it centos:7 bash ##加一个:ro就可以把这个文件变成只读,限制挂载后的文件的权限
在使用docker run 或docker create创建新容器时,可以使用多个-v标签为容器添加多个volume
docker run -d -v vol-name:/data1 -v /data2 -v /host/dir:/container/dir:ro nginx:1.22.1
多个容器使用同一个目录
[root@linxuan ~]$ docker run -v /data/dokcer-docker/:/data --name=nginx-01 -d nginx:1.22.1 [root@linxuan ~]$ docker run -v /data/dokcer-docker/:/data --name=nginx-02 -d nginx:1.22.1 ##两种方式 [root@linxuan ~]$ docker run --name=nginx-03 -d --volumes-from nginx-01 nginx:1.22.1 [root@linxuan ~]$ docker exec -it 7b41ce020fa03919efb4c99db8b8964a72a0df71dc6857bc8a0f98edb9e8b884 bash root@7b41ce020fa0:/data# ls /data/ docker-in docker-out
这样就是所有挂载同一个共享卷的容器共享目录下的所有数据!
可以在执行'docker run -v'命令时,指定同一个共享卷,而可以指定被挂载容器的同一个目录下创建不同的子目录,这样就可以用一个共享卷而容器之间的数据不受影响
#启动第一个容器并挂载到共享卷的子目录 docker run -it --name container1 -v mysharedvolume:/data/container1 alpine sh #启动第二个容器并挂载到共享卷的另一个子目录 docker run -it --name container2 -v mysharedvolume:/data/container2 alpine sh ##在这种情况下,container1 对 /data/container1 目录的操作不会影响 container2 的 /data/container2 目录 ##每个容器有自己独立的存储区域,但它们仍然共享同一个卷。
docker volume rm 卷名
docker rm -v 删除匿名卷
用--mount挂载volume
docker run -d --name devtest --mount type=volume,source=myvol2,target=/app nginx:latest ##type= 类型;source= 源(宿主机);target= 目标(容器) 挂载目录 docker run -d \ --name devtest \ --mount type=bind,source=/data/mysql,target=/app \ nginx:latest
-v 或 --volume:由三个字段组成,用冒号字符(:)分隔。这些字段必须按照正确的顺序,并且每个字段的含义不太清晰。
--mount:由多个键值对组成,用逗号分隔,每个键值对由
= 组成。--mount 语法比 -v 或 --volume 更冗长,但键的顺序并不重要,并且该标志的值更易于理解。
docker存储驱动是docker的核心组件,他是docker实现分层镜像的基础
overlayfs:内核3.18overlayfs进入主线,性能和稳定性优异