服务端

Docker 服务端一般在宿主机后台运行,dockerd 作为服务端接受来自客户的请求,并通过 containerd 具体处理与容器相关的请求,包括创建、运行、删除容器等。

服务端主要包括四个组件:

1. dockerd:为客户端提供 RESTful API,响应来自客户端的请求,采用模块化的架构,通过专门的 Engine 模块来分发管理各个来自客户端的任务。可以单独升级;

2. docker-proxy:是 dockerd 的子进程,当需要进行容器端口映射时, docker-proxy 完成网络映射配置;

3. containerd:是 dockerd 的子进程,提供 gRPC 接口响应来自 dockerd 的请求,对下管理 runC 镜像和容器环境。可以单独升级;

4. containerd-shim:是 containerd 的子进程,为 runC 容器提供支持,同事作为容器内进程的根进程。

runC 是从 Docker 公司开源的 libcontainer 项目演化而来的,目前作为一种具体的开放容器标准实现加入 Open Containers Initiative(OCI)。

runC 已经支持了 Linux 系统中容器相关技术栈,同时正在实现对其他操作系统的兼容。用户也可以通过使用 docker-runc 命令来直接使用 OCI 规范的容器。

dockerd 默认监听本地的 uninx:///var/run/docker.sock 套接字,只允许本地的 root 用户或 docker 用户组成员访问。可以通过 -H 选项来修改监听的方式。

例如,让 dockerd 监听本地的 TCP 连接 1234 端口:dockerd -H 127.0.0.1:1234

客户端

Docker 客户端为用户提供一系列可执行命令,使用这些命令可实现与 Docker 服务端交互。

用户使用的 Docker 可执行命令即为客户端程序。与 Docker 服务端保持运行方式不同,客户端发送命令后,等待服务端返回;一旦收到返回后,客户端立刻执行结束退出。用户执行新的命令,需要再次调用客户端命令。

镜像仓库

镜像是使用容器的基础,Docker 使用镜像仓库(Registry)在大规模场景下存储和分发 Docker 镜像。镜像仓库提供了对不同存储后端的支持,存放镜像文件,并且支持 RESTful API,接收来自 dockerd 的命令,包括拉去、上传镜像等。用户从镜像仓库拉取的镜像文件会存储在本地使用;用户同时也可以上传镜像到仓库,方便其他人获取。使用镜像仓库可以极大地简化镜像管理和分发的流程。

命名空间

命名空间(namespace)是 Linux 内核的一个强大特性,为容器虚拟化的实现带来极大便利。利用这一特性,每个容器都可以拥有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统环境中一样。命名空间机器保证了容器之间彼此互不影响。

在操作系统中,包括内核、文件系统、网络、进程号(Process ID,PID)、用户号(UserID,UID)、进程间通信(InterProcess Communication,IPC)等资源,所有的资源都是应用进程直接共享的。要想实现虚拟化,除了要实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC 等的相互隔离。前者相对容易实现一些,后者则需要宿主主机系统的深入支持。

随着 Linux 系统对于命名空间功能的逐步完善,现在已经可以实现这些需求,让进程在彼此隔离的命名空间中运行。虽然这些进程仍在共用同一个内核和某些运行时环境(runtime,例如一些系统命令和系统库),但是彼此是不可见的,并且认为自己是独占系统的。