容器是当今IT运维的关键部分。容器镜像包含打包的应用程序及其依赖关系,以及有关启动时所运行的进程的信息。
你可以通过提供一组特殊格式的指令来创建容器镜像,这些指令可以提交到注册表或Dockerfile。例如,此Dockerfile为PHP web应用程序创建一个容器:
FROM registry.access.redhat.com/ubi8/ubi:8.1
RUN yum --disableplugin=subscription-manager -y module enable php:7.3 \
&& yum --disableplugin=subscription-manager -y install httpd php \
&& yum --disableplugin=subscription-manager clean all
ADD index.php /var/www/html
RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf \
&& sed -i 's/listen.acl_users = apache,nginx/listen.acl_users =/' /etc/php-fpm.d/www.conf \
&& mkdir /run/php-fpm \
&& chgrp -R 0 /var/log/httpd /var/run/httpd /run/php-fpm \
&& chmod -R g=u /var/log/httpd /var/run/httpd /run/php-fpm
EXPOSE 8080
USER 1001
CMD php-fpm & httpd -D FOREGROUND
此文件中的每个指令都会向容器镜像添加一个层。每个层只添加与它下面的层的差异,然后将所有这些层堆叠在一起以形成只读容器镜像。
如何工作的?
你需要了解一些关于容器镜像的知识,按照以下顺序理解概念非常重要:
1. Union File Systems
2. Copy-on-Write
3. Overlay File Systems
4. Snapshotters
Union File Systems(Aufs)
Union File Systems(UnionFS)内置于Linux内核中,它允许一个文件系统的内容与另一个文件系统的内容合并,同时保持“物理”内容的分离。结果是形成了一个统一的文件系统,即使数据实际上是以分支的形式构造的。
这里的想法是,如果你有多个具有相同数据的镜像,不是将这些数据重新复制,而是将通过使用称为层的东西共享。
每一层都是一个可以跨多个容器共享的文件系统,例如,httpd基本层是官方Apache镜像,可以跨任意数量的容器使用。想象一下,我们刚刚节省了多少磁盘空间,因为所有的容器都使用相同的底层。
这些镜像层总是只读的,但是当我们从这个镜像创建一个新的容器时,我们会在上面添加一个薄的可写层。此可写层用于创建/修改/删除或对每个容器进行所需的其他更改。
Copy-on-Write
启动容器时,容器似乎有自己的整个文件系统。这意味着你在系统中运行的每个容器都需要自己的文件系统副本。这会不会占用大量磁盘空间,也会占用容器启动的大量时间?不需要,因为每个容器不需要自己的文件系统副本!
容器和镜像使用写时拷贝机制来实现这一点。“写时复制”策略不复制文件,而是将同一个数据实例共享给多个进程,并且仅在进程需要修改或写入数据时才进行复制。所有其他进程将继续使用原始数据。在运行的容器中执行任何写入操作之前,将要修改的文件的副本放置在容器的可写层上。这就是写的地方。现在你知道为什么叫“copy-on-write”。
此策略优化了镜像磁盘空间的使用和容器启动时间的性能,并与UnionFS配合使用。
Overlay File System
覆盖层位于现有文件系统的顶部,将上下目录树组合在一起,并将它们表示为单个目录。这些目录称为层。下层保持不变。每一层只增加它下面层的差异(计算术语中的差异),这个过程称为union mount。
最低的目录或镜像层称为lowerdir,较高的目录称为upperdir。最后的叠加或统一层称为merged。
通用术语包括以下层定义:
——基本层是文件系统的文件所在的位置。就容器镜像而言,该层将是你的基础镜像。
——覆盖层通常称为容器层,因为对正在运行的容器所做的所有更改(如添加、删除或修改文件)都会写入该可写层。对该层所做的所有更改都存储在下一层中,并且是基本层和差异层的联合视图。
——差异层包含覆盖层中所做的所有更改。如果你写入的内容已经在基础层中,则覆盖文件系统会将该文件复制到差异层,并进行你想要写入的修改。这被称为copy-on-write。
Snapshotter
容器可以使用层和镜像驱动程序作为容器文件系统的一部分来构建、管理和分发更改。但是使用图形驱动程序非常复杂,而且容易出错。Snapshotter不同于图形驱动程序,因为它们不了解镜像或容器。
Snapshotter的工作原理与Git非常相似,例如拥有树的概念,并跟踪每次提交时对树的更改。快照表示文件系统状态。快照使用一组目录拥有父子关系。可以在父对象与其快照之间得到差异以创建层。
Snapshotter提供了一个API,用于分配、快照和挂载抽象的分层文件系统。
小结
恭喜你,现在你对什么是容器镜像以及它们的分层方法如何使容器具有可移植性有了很好的了解。
本文暂时没有评论,来添加一个吧(●'◡'●)