# Docker引擎

Docker Engine是容器的核心，是容器运行的基础。Docker具有模块化设计，这意味着您可以交换/自定义其某些组件。

![docker-engine-arch](/files/987iiLen8kqvfAiVSWyV)

Docker架构有五个组件：

* docker CLI
* dockerd
* containerd
* containerd-shim
* runc

## runc

[runc](https://github.com/opencontainers/runc)是`libcontainer`的轻量级CLI包装器，用于生成和运行容器。

您可以仅使用CLI运行容器而无需Docker。为此，您必须拥有符合OCI标准的捆绑包。容器的捆绑包是一个包含名为`config.json`的规范文件和根文件系统的目录。`config.json`用于在特定状态下创建容器。

`config.json`示例

```json
{  
  "ociVersion": "0.6.0-dev",  
  "platform": {     
    "os": "linux",     
    "arch": "amd64"   
  },   
  "process": {   
    "terminal": true,   
    "args": ["sh"],   
    "env": ["PATH=/usr/local/sbin:/usr/local/bin:/bin", ...]
  ...
}
```

给定捆绑包，您可以使用`runc`简单运行容器

```bash
# 创建一个空文件夹
mkdir ~/mycontainer
cd ~/mycontainer
# 创建rootfs，一种方法是复用docker导出
mkdir rootfs
docker export $(docker create busybox) | tar -C rootfs -xvf -
# 为捆绑包创建名为"config.json"的新规范文件
runc spec
# 运行容器
runc run mycontainerid
```

Docker是`runc`的更高级抽象，`runc`是`libcontainer`的CLI。此外，您还可以将docker设置为您自己的运行时`dockerd`守护进程[--add-runtime](https://docs.docker.com/engine/reference/commandline/dockerd/)。

## containerd

`containerd`是Docker模块化架构中的一层。当您向`dockerd`发出请求时，`containerd`管理与镜像分发相关的进程，例如将镜像推送/拉取到/从注册表。使用镜像，`containerd`为容器生成OCI捆绑包。

`containerd`管理容器生命周期：启动、停止、暂停或删除它。它还管理镜像分发：将镜像推送/拉取到/从注册表。

> 那么使用containerd实际上能得到什么呢？ 您获得推送和拉取功能以及镜像管理。您获得容器生命周期API来创建、执行和管理容器及其任务。一个专门用于快照管理的完整API。基本上，您需要构建容器平台的一切，而无需处理底层操作系统细节。 更多信息见[Docker containerd integration](https://www.docker.com/blog/docker-containerd-integration/)

## containerd-shim

`containerd-shim`允许您拥有无守护进程的容器。这是如何实现的：

* `containerd`为每个新容器分叉一个`runc`实例
* `runc`进程在容器创建后退出
* 一旦容器由`runc`创建，`containerd-shim`就成为容器进程的新父进程

您可以通过创建docker容器并检查进程来看到这一点。

```bash
$ docker run -d alpine sleep 30
$ ps fxa | grep dockerd -A 3  
2239 ?        Ssl    0:28 /usr/bin/dockerd -H fd://
2397 ?        Ssl    0:19  \_ docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock ...
15476 ?        Sl     0:00      \_ docker-containerd-shim 3de8... /var/run/docker/libcontainerd/3da7.. docker-runc  
15494 ?        Ss     0:00          \_ sleep 30
```

那里没有使用`runc`，因为它被`containerd-shim`替代了。

`containerd-shim`负责`STDIN`/`STDOUT`以及向Docker守护进程报告退出状态。

## dockerd

`dockerd`是一个守护进程和服务器，处理Docker API请求，然后利用`containerd`功能管理容器的生命周期。

## docker CLI

Docker CLI是与Docker服务器`dockerd`通信的方式之一。您可以使用它运行docker命令，如`docker run`或`docker build`。

## 运行容器

![running-container](/files/t3DjlJZj0DdjLuyjzuY0)

1. 用户使用docker CLI执行命令：

   ```bash
   docker container run -it --name <NAME> <IMAGE>:<TAG>
   ```
2. Docker客户端向守护进程的API发送POST请求
3. Docker守护进程接收指令并调用`containerd`启动新容器
4. `containerd`从Docker镜像创建OCI捆绑包
5. `containerd`告诉`runc`使用OCI捆绑包创建容器
6. `runc`与操作系统内核接口创建容器
7. 容器进程作为子进程启动
8. `runc`在启动容器后退出
9. `containerd-shim`接管子进程并成为其父进程
10. 容器正在运行！

## 参考资料

* [Docker引擎架构底层原理](https://medium.com/@yeldos/docker-engine-architecture-under-the-hood-741512b340d5)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.cdxiaodong.life/rong-qi-an-quan/gai-shu/docker-engine.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
