引言
通常我们在使用集群或者容器的时候,都会接触到存储在本地的镜像,也或多或少对本地镜像存储有一定的了解。但是服务端的镜像存储细节呢?本文主要介绍容器镜像的服务端存储结构,对于自建镜像服务或是对容器镜像底层原理或优化有兴趣的同学可以了解一下。
相关开源项目
目前容器镜像服务相关的开源项目主要有以下两个。
- Registry (https://github.com/docker/distribution)
- Harbor (https://github.com/goharbor/harbor)
Registry具有基本的镜像上传、下载以及对接第三方鉴权的能力。Harbor则基于Registry做了相应的企业级扩展的项目。提供了更多权限、审计、镜像等功能,目前是CNCF孵化项目之一。其他详情参考相关文章。这篇文章主要讲解Registry项目的存储细节。
镜像细节
在了解服务端之前,我们来了解一下客户端的镜像容器的存储环境。
联合文件系统 UnionFS(Union File System)
Docker的存储驱动的实现是基于UnionFS。简单列举一下UnionFS下存储镜像的一些特点。
首先,UnionFS是一个分层的文件系统。一个Docker镜像可能有多个层组成(注意他们是有顺序的)。
其次,只有顶层是可写的,其它层都是只读的。这样的机制带来的好处是镜像层可以被多个镜像共享。对于Docker镜像来说,所有层都是只读的。当一个镜像运行时,会在该镜像上增加一个容器层。十个相同的镜像启动,仅仅是增加十个容器层。销毁容器时也仅仅是销毁一个容器层而已。
-
UnionFS是一个分层的文件系统。一个Docker镜像可能有多个层组成(注意他们是有顺序的)。
-
只有顶层是可写的,其它层都是只读的。这样的机制带来的好处是镜像层可以被多个镜像共享。对于Docker镜像来说,所有层都是只读的。当一个镜像运行时,会在该镜像上增加一个容器层。十个相同的镜像启动,仅仅是增加十个容器层。销毁容器时也仅仅是销毁一个容器层而已。
-
- 当容器需要读取文件的时候:从最上层镜像开始查找,往下找,找到文件后读取并放入内存,若已经在内存中了,直接使用。(即,同一台机器上运行的docker容器共享运行时相同的文件)。
- 当容器需要添加文件的时候:直接在最上面的容器层可写层添加文件,不会影响镜像层。
- 当容器需要修改文件的时候:从上往下层寻找文件,找到后,复制到容器可写层,然后,对容器来说,可以看到的是容器层的这个文件,看不到镜像层里的文件。容器在容器层修改这个文件。
- 当容器需要删除文件的时候:从上往下层寻找文件,找到后在容器中记录删除。即,并不会真正的删除文件,而是软删除。这将导致镜像体积只会增加,不会减少。
由此可以思考很多安全和镜像优化上的问题。
- 在镜像构建中记录敏感信息然后再下一个构建指令中删除安全吗?(不安全)
- 在镜像构建中安装软件包然后再下一个构建指令中清理软件包能减小镜像体积吗?(并不能)
Union