要论云计算领域中,开发者需要具备哪些基本技能?那么 Docker 必是其一。 作为一个开源的应用容器引擎,Docker 能够让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化,方便快捷。

那么你真的足够了解 Docker 吗?

彩蛋:

点击下载docker相关视频教程

Docker是如何工作的?这是一个简单的问题,但答案却是出乎意料的复杂。你可能很多次地听说过“守护进程(daemon)”和“运行时(runtime)”这两个术语,但可能从未真正理解它们的含义以及它们是如何配合在一起的。如果你像我一样,涉过源头去发现真相,那么,在你沉溺于代码之海时,你并不孤单。让我们面对现实吧,假想Docker的源代码是一顿意式大餐,而你正在狼吞虎咽你的美味意面。

就像一把叉子可以把面条送到你的口中,这篇文章会将Docker的技术的方方面面组织在一起并导入你饥饿的大脑。

为了更好地理解现在,我们首先需要回顾过去。2013年,dotCloud公司的Solomon Hykes在那年的Python大会上发表了Linux容器的未来的演讲,第一次将Docker带入了公众的视线。让我们将他的git代码库回溯到2013年1月,这个Docker开发更轻松的时间。

01.Docker 是如何工作的?




Docker由两个主要组件组成,一个供用户使用的命令行应用程序和一个管理容器的守护进程。这个守护进程依赖两个子组件来执行它的任务:在宿主主机文件系统上用来存储镜像和容器数据的存储组件;以及用于抽象原始内核调用来构建Linux容器的LXC接口。

命令行应用程序

Docker命令行应用程序是管理你的Docker运行副本已知的所有镜像和容器的人工界面。它相对简单,因为所有的管理都是由守护进程完成的。应用程序开始于一个main 函数:

它会立即建立一个TCP连接,指向存储在DOCKER这个环境变量中的地址,这是Docker守护进程的地址。用户提供的参数发送给守护进程,然后命令行应用程序等待打印成功答复的结果。

dockerd

Docker守护进程的代码存放在同一个代码库中,这个进程称为dockerd。它运行在后台来处理用户请求和容器清理工作。启动后,dockerd将监听在8080端口上传入的HTTP连接和在4242端口上的TCP连接。

一旦命令接收到后,dockerd将使用反射机制查找并调用要运行的函数。

docker run命令

其中一个运行的函数是CmdRun,它对应这个docker run(注:这个命令创建一个新的容器并运行一个命令)命令。

用户通常会提供一个镜像和一个命令,以便dockerd运行。当它们被省略时,将默认使用镜像base和命令/bin/bash。

查找镜像

然后,我们通过将名称(或ID)映射到文件系统上的一个位置来找到指定的镜像(假设前面已经执行过docker pull (注:这个命令从镜像仓库中拉取或者更新指定镜像)命令,镜像已经生成)。

在这个版本的Docker中,所有镜像都存储在/var/lib/docker/images文件夹中。想进一步了解Docker镜像中有什么,请参阅文章(https://cameronlonsdale.com/2018/11/26/whats-in-a-docker-image/)。

创建容器

接着我们开始创建容器。dockerd创建了一个结构(struct)来保存与这个容器相关的所有元数据,并将它存储在一个列表中以便于访问。


当创建这个struct时,dockerd 会在下列路径为容器创建下面这个唯一目录:/var/lib/docker/containers/。在这个目录下中有两个子目录:/rootfs 只读根文件系统层(来自联合挂载(union mounted)的镜像),/rw提供一个单独的读写层,供容器来创建临时文件。

最后,使用我们新创建的容器数据填充一个模板,用以生成LXC 配置文件。更多关于LXC的信息,请参见下一节。

运行容器

我们的容器终于创建出来了!但它还没有运行,现在让我们启动它。

第一步是确保容器的文件系统已挂载。

使用AUFS 联合挂载文件系统(union mount file system),镜像的各个层以read-only方式挂载在彼此的顶部,以向容器呈现一个一致的视图。read-write路径被挂载在最顶层,为容器提供临时存储。

然后,为了启动容器,dockerd使用刚才生成的LXC模板来运行另一个程序lxc-start。

LXC

LXC(Linux Containers)是一个抽象层,它为用户空间应用程序提供了一个简单的API来创建和管理容器。事实是,容器不是真实的东西,在Linux内核中没有称作容器的对象。容器是一组内核对象的集合,它们协同工作以提供进程隔离。因此,简单的lxc-start命令实际上被翻译成下面的设置和应用:

内核名字空间 (ipc, uts, mount, pid, network 和 user)

Apparmor和 SELinux profiles

Seccomp policies

Chroots (使用 pivot_root)

Kernel capabilities

CGroups (control groups)

容器清理



最后,dockerd将监控容器直到完成,并在容器完成后清理不必要的数据。

总结

概括起来,使用Docker 2013来管理一个容器的运行涉及以下步骤:

02.Docker发生了什么变化?