Allen 谈 Docker 阶段总结(一)

「Allen 谈 Docker 系列」DaoCloud 正在启动 Docker 技术系列文章,每周都会为大家推送一期真材实料的精选 Docker 文章。主讲人为 DaoCloud 核心开发团队成员 Allen 孙宏亮,他是 InfoQ《Docker 源码分析》专栏作者,已出版《Docker 源码分析》一书。Allen 接触 Docker 近两年,爱钻研系统实现原理,及 Linux 操作系统。

《Allen 谈 Docker》系列迄今为止已经连载了 8 篇,通过前面 8 个 section 的讲解,读者应该已经对 Docker 的基础概念有了一个比较系统的认知。而目前我们的讲解主要集中于容器日志和容器镜像。

本篇文章主要想对前面 8 篇文章进行一个系统的梳理,让我们来一同回顾过去 8 篇 Docker 精选文章的概要吧。

1. docker logs 实现剖析

Docker 容器的日志是用户获知应用级运行状态的重要依据。关于 Docker 容器的日志,最为关键的知识点是:

1)应用的标准输出,标准错误:只有容器内应用进程的 stdout 和 stderr,才会被当作容器的日志;

2)日志由 Docker Daemon 接管:对于每一个 Docker 容器的日志,均由 Docker Daemon 负责接收 stdout 以及 stderr,因此容器与 Docker Daemon 存在较大耦合。

image

2. docker exec 与容器日志

命令docker exec可以帮助用户在已有容器的基础上,运行特定的命令,从而在特定的容器环境内完成用户的需求。docker exec与容器日志的关系有:

1)docker exec的新进程属于容器范畴

2)docker exec的新进程 stdout 和 stderr 不会被容器阶段,故不会存在于容器日志中

3)docker exec的新进程打破了容器进程的树状结构

image

3. Docker 容器日志的那些事儿

传统应用 docker 化无法避免的阻力之一就是 Docker 容器的日志。传统应用向磁盘文件打印日志的方式,一旦在容器的世界中直接采用,在会出现管理不便的情况。为了解决这部分内容的问题,我们可以通过以下途径来实现传统应用 docker 化之后的日志管理:

1) 修改传统应用的所有日志处理方式,将写日志文件的操作改为输出至标准输出 stdout 和标准错误 stderr。

2) 通过修改应用的 Dockerfile 中 CMD 的逻辑,使得容器中创建 tail 进程不断将日志文件内容再次转移至标准输出 stdout 和标准错误 stderr。

image

4. 一图看尽 Docker 容器文件系统

从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。

学习 Docker 容器文件系统时,我们可以参考下图,同时也有一些注意点:

1) Docker 镜像分层管理。

2) VOLUME 内容不存在于读写层,而在于宿主机上。

3) Docker 容器内进程只会更新最上层的读写层。

image

5. 深刻理解 Docker 镜像大小

在认识 Docker 镜像的大小时,以下三方面的知识可以认为是关键:

1)Dockerfile 与 Docker 镜像的关系:Dockerfile 中的每一条都会对应于一层镜像。

2)联合文件系统 Union Mount:保证镜像层直接虽然有重复内容,但是容器视角只会看到上层的内容,从而容器视角的文件系统内容大小,不大于所有镜像大小之和。

3)镜像共享关系:多个镜像可以共享同一个基础镜像,从而实现镜像的复用。

6. Docker 镜像内有啥,存哪?

Docker 镜像的内容除了每一层的文件系统内容之外,其实还包含一个非常重要的 json 文件,它的作用是:

1)记录 Docker 镜像中与容器动态信息相关的内容

2)记录父子 Docker 镜像之间真实的差异关系

3)弥补 Docker 镜像内容的完整性与动态内容的缺失

另外,Docker 镜像存在哪呢?那大家有必要看看目录/var/lib/docker/graph/var/lib/docker/aufs 了。

7. 深入理解 Docker 镜像 json 文件

Docker 镜像是静态的,Docker 容器是动态的,如何从静态的镜像转变为动态的容器,那么 Docker 镜像的 json 文件就是不得不深入学习的内容。

image

8. docker build 的 cache 机制

docker build 的 cache 机制: Docker Daemnon 通过 Dockerfile 构建镜像时,当发现即将新构建出的镜像与已有的某镜像重复时,可以选择放弃构建新的镜像,而是选用已有的镜像作为构建结果,也就是采取本地已经 cache 的镜像作为结果。

接触 cache 机制时,我们有两点需要理解:

1) “即将构建出的镜像”属于仍未构建完成的镜像,通过何种方式来标识此镜像?

2)涉及到镜像比较,重复时选择放弃构建,那镜像比较时重复的标准是什么?

此文从假设出发,深入浅出解释了以上问题。并也从原理的角度阐述了使用 cache 机制时的三个注意事项:

  • ADD 命令与 COPY 命令:Dockerfile 没有发生任何改变,但是命令ADD run.sh / 中 Dockerfile 当前目录下的 run.sh 却发生了变化,从而将直接导致镜像层文件系统内容的更新,原则上不应该再使用 cache

  • RUN 命令存在外部依赖:一旦 RUN 命令存在外部依赖,如RUN apt-get update,那么随着时间的推移,基于同一个基础镜像,一年的 apt-get update 和一年后的 apt-get update, 由于软件源软件的更新,从而导致产生的镜像理论上应该不同

  • 树状的镜像关系决定了,一次新镜像的成功构建将导致后续的 cache 机制全部失效

Allen 谈 Docker 前面 8 篇的阶段总结就到这里,欢迎继续关注本系列的后续内容。

下回内容预告:docker commit 的来龙去脉。

Allen 孙宏亮

硕士,浙江大学毕业,现为 DaoCloud 软件工程师,出版有《Docker 源码分析》,目前主要负责企业级容器云平台的研发工作。数年来一直从事云计算、PaaS 领域的研究与实践,是国内较早一批接触 Docker 的先行者,同时也是 Docker 技术的推广者。