重学容器23: Containerd容器存储挂载简介
2021-07-21
通过前面14~22节内容,结合Containerd学习了容器网络的一些基础知识,包括容器网络接口CNI以及Calico网络方案的一些内容。 从本节将学习容器持久化存储的相关知识。
容器的本质是一种特殊的进程,它使用namespace进行隔离,使用cgroup进行资源限制,并且以联合文件系统的形式挂载了单独的rootfs。 Containerd默认配置的snapshotter是overlayfs,overlayfs是联合文件系统的一种实现,overlayfs将只读的镜像层成为lowerdir,将读写的容器层成为upperdir,最后联合挂载呈现出mergedir。 容器中新写入的文件默认存储在容器的执行层,当容器被删除时,这些数据也就丢失了。如果想要在容器被删除后保留之前创建的文件,就需要将文件保存在宿主机上。
Containerd最初就被设计为嵌入到一个更大的系统中(如Kubernetes)使用,因此它只包含了专门用于开发和调试的命令行工具ctr
,ctr在使用上不是那么友好,尤其是对于用惯了docker cli的用户来说。
Containerd另外提供了一个与docker cli风格兼容的命令行工具nerdctl
,本节对Containerd容器存储挂载的学习先基于nerdctl。
容器存储挂载的三种模式 #
nerdctl对容器存储挂载的支持基本上与Docker一致,支持bind mounts
, volumes
, tmpfs
三种模式。下图是docker的文档中给的这三种模式的示意图:
当前版本nerdctl(0.11.0)在启动containerd时支持前两种模式:
bind mounts
: 可以将文件数据存储在宿主机上的任意位置,其他的应用程序也有权对这些文件进行修改volumes
: 将文件数据存储在宿主机上nerdctl的数据目录内,此目录应该由nerdctl管理,默认是/var/lib/nerdctl/xxx/volumes/<containerd namespace>
tmpfs
将文件数据存储在宿主机的内存中,并不会写入磁盘中 (当前nerdctl 0.11.0还不支持此模式)。tmpfs的使用场景适用于出于安全考虑,将一些认证信息存储到tmpfs中,或者出于性能考虑需要将一些状态信息存储在内存中同时又不需要持久化的场景
bind mounts #
bind mounts可以将文件数据存储在宿主机上的任意位置,这意味着其他的应用程序也有权对这些文件进行修改。 注意使用bind mounts将宿主机目录挂载到容器中时,容器目录中原有的文件将会被隐藏,在容器内只能看到挂载进来的宿主机目录。
例如使用下面的命令将宿主机上的一个空目录/tmp/mydir
挂载到容器中/etc/profile.d
下,如果进入容器后查看/etc/profile.d会发现该目录为空,容器中的原有文件会被隐藏。
1nerdctl run -d -v /tmp/mydir:/etc/profile.d redis:alpine3.14
volumes #
volumes由nerdctl创建和管理,可以使用nerdctl volume create
命令显示的创建volume。
注意使用volume时,容器目录中原有的文件不会被隐藏容器目录中,原有的文件将被拷贝到volume所在的宿主机目录。
1nerdctl volume create redis-data
上面的命令创建了一个名称为redis-data
的volume,可以使用nerdctl volume ls
查看:
1nerdctl volume ls
2VOLUME NAME DIRECTORY
3redis-data /var/lib/nerdctl/1935db59/volumes/default/redis-data/_data
当我们手动使用nerdctl创建一个volume时,其数据存在了/var/lib/nerdctl/xxx/volumes/<containerd namespace>/<volume name>/_data
下。
下面挂载这个volume,启动一个redis容器:
1nerdctl run -d -v redis-data:/data redis:alpine3.14
进入这个容器并向redis中写入一个key-value数据,然后停止并删除这个redis容器,,再次查看volume在宿主机上的目录,可以看到之前redis容器的dump.rdb数据文件:
1ls /var/lib/nerdctl/1935db59/volumes/default/redis-data/_data
2dump.rdb
另外还可以在Dockefile中通过Volume
指令来设置volume的自动创建,其实redis:alpine3.14
镜像的Dockerfile中已经包含下面的内容:
1.......
2RUN mkdir /data && chown redis:redis /data
3VOLUME /data
4WORKDIR /data
5......
上面的Dockerfile中VOLUME指令表示在启动容器时自动创建一个volume并将其挂载到容器内的/data目录上。 下面直接启动一个redis容器,而并没有显示挂载任何volume:
1nerdctl run -d redis:alpine3.14
2837f4fb997637951d7cece7b2e981c2c274f1864cec25574ad4f7d87f070caef
此时使用查看宿主机上的volume:
1nerdctl volume ls
2VOLUME NAME DIRECTORY
317d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5 /var/lib/nerdctl/1935db59/volumes/default/17d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5/_data
4redis-data /var/lib/nerdctl/1935db59/volumes/default/redis-data/_data
多了一个名称为17d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5
的卷,就是启动redis容器时自动创建的,下面进入这个容器并向redis中写入一个key-value数据,然后停止并删除这个redis容器,自动创建的volume仍将保存下来:
1ls /var/lib/nerdctl/1935db59/volumes/default/17d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5/_data
2dump.rdb
自动创建的这种volume,叫做匿名卷,在删除容器时可以通过指定-v或--volumes
自动删除容器关联的匿名卷。
1nerdctl run -d redis:alpine3.14
289b5dc8969ae103b20a616a42c1e6ac3c3ad8e3b46a74012990c05dd81a18843
3
4nerdctl stop 89b
589b5dc8969ae103b20a616a42c1e6ac3c3ad8e3b46a74012990c05dd81a18843
6
7nerdctl volume ls
8VOLUME NAME DIRECTORY
917d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5 /var/lib/nerdctl/1935db59/volumes/default/17d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5/_data
10e153ad55d34d653dc3bca7ecc643a1e4bbe35114b32c6d4daaeb9d01498f6407 /var/lib/nerdctl/1935db59/volumes/default/e153ad55d34d653dc3bca7ecc643a1e4bbe35114b32c6d4daaeb9d01498f6407/_data
11redis-data /var/lib/nerdctl/1935db59/volumes/default/redis-data/_data
12
13nerdctl rm -v 89b
14
15nerdctl volume ls
16VOLUME NAME DIRECTORY
1717d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5 /var/lib/nerdctl/1935db59/volumes/default/17d54684c7f72807bddad3f7ec24a8c0c1a2af763ec16557ee75e11259c3c0e5/_data
18redis-data /var/lib/nerdctl/1935db59/volumes/default/redis-data/_data