docker 原理之runC(3)

本文解析了Docker 1.11版本后的模块结构变化,介绍了Docker Daemon、Containerd、RunC等关键组件的作用及相互关系,并展示了如何利用这些组件直接运行容器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自http://www.cnblogs.com/yanjingnan/p/6473831.html

Docker, Containerd, RunC :
从 Docker 1.11 开始, docker 容器运行已经不是简单地通过 Docker Daemon 来启动, 而是集成了Container, RunC 等多个组件.

Docker 服务启动之后, 可以看到系统上启动了 Docker, Docker-container 等进程. 以下介绍 docker(1.11 版本之后每个部分的功能和作用.)

OCI 标准

Linux基金会于2015年6月成立OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准。该组织一成立便得到了包括谷歌、微软、亚马逊、华为等一系列云计算厂商的支持。而runC就是Docker贡献出来的,按照该开放容器格式标准(OCF, Open Container Format)制定的一种具体实现。

docker 模块结构

从Docker 1.11之后,Docker Daemon被分成了多个模块以适应OCI标准。

docker_mod_arch_oci

docker daemon : 独立成单独二进制程序.

docker 1.8 之前, 启动会命令:

$ docker -d

docker 1.8 之后, 启动命令变成了 :

$ docker daemon

docker 1.11 开始, 启动命令变成了 :

$ dockerd

containerd

containerd 是运用 runC(或者任何与 OCI 兼容的程序)来管理容器,通过 gRPC 暴露功能的简易守护进程。相比于 Docker Engine,暴露容器相关的 CRUD 接口使用成熟的 HTTP API,Docker Engine 不仅能暴露容器,还能暴露镜像、数据卷、网络、构建等。

containerd 是容器技术标准化之后的产物, 为了能够兼容 OCI 标准, 将容器运行时及其管理功能从 Docker Daemon 剥离.

理论上, 即使不运行 dockerd 也能直接通过 containerd 来管理容器.(当然, containerd 本身也只是一个守护进程, 容器的实际运行时由 runC 控制.)

container(已开源), 其主要职责是镜像管理(镜像, 元信息等), 容器执行(调用最终运行时组件执行).

container 向上为 docker daemon 提供了 gRPC 接口, 使得 docker daemon 屏蔽下面的结构变化, 确保原有接口向下兼容. 向下通过 container-shim 结合 runC, 使得引起可以独立升级, 避免之前 docker daemon 升级会导致所有容器不可用的问题.(见上面 docker_mod_arch 图)

docker_mod_arch

docker , container , container-shim 之间的关系, 可以通过启动一个 docekr 容器观察之间的管理.

① 启动一个容器:
    $ docker run -d alpine sleep 1000
② 查看docker daemon 的pid
    $ ps aux |grep dockerd  # 1480
③ 查看进程之间的父子关系
    $ pstree -l -a -A 1480
        dockerd -H fd://
          |-docker-containe -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
          |   |-docker-containe 2b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 /var/run/docker/libcontainerd/2b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 docker-runc
          |   |   |-sleep 1000
          |   |   `-7*[{docker-containe}]
          |   `-9*[{docker-containe}]
          `-11*[{dockerd}]              

    当 docker daemon 启动之后, docker 和 docker-container 进程一直存在.
    当启动容器之后, docker-container 进程(container 组件)会创建 docker-containerd-shim 进程. 其中 2b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 就是要启动容器的 ID, 最后 docker-containerd-shim 子进程, 液晶是在容器中运行的进程(sleep 1000)

    其中 /var/run/docker/libcontainerd/2b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 里面内容有 : 
        /var/run/docker/libcontainerd/2b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626
        ├── config.json         # 容器配置
        ├── init-stderr         # 标准错误输出
        ├── init-stdin          # 标准输入
        └── init-stdout         # 标准输出.     

RunC

unC 是一种只专注于运行容器的轻量级工具。如果你了解 Docker Engine 的早期历史,你就知道它曾经用 LXC 来启动和管理容器;后来它演变为 “libcontainer”。“libcontainer” 是一段与 cgroup 和 namespace 这些 Linux 内核交互的代码,这些内核是容器构建的基石。

简言之,runC 基本上是一种无需进入 Docker Engine,直接控制 libcontainer 的小型命令行工具,是一种管理和运行 OCI 容器的单机二进制.

OCI 定义了容器运行时标准, runC 是 Docker 按照 开放容器格式标准(OCF, Open Container Format) 制定的一种具体实现.

runC 是从 Docker 的 libcontainer 中迁移而来的, 实现了容器启停,资源隔离等功能. Docker 默认提懂了 docekr-runc 实现, 事实上, 通过 containerd 的疯转, 可以在 Docker daemon 启动的时候指定 runC 的实现.

可以通过在启动 docker daemon 时, 增加 --add-runtime 参数来选择其他的 runC 实现.
    $ docker daemon --add-runtime "custom=/usr/local/bin/my-runc-replacement"

runC 特征 :

1. 支持所有的Linux namespaces,包括user namespaces。目前user namespaces尚未包含。
2. 支持Linux系统上原有的所有安全相关的功能,包括Selinux、 Apparmor、seccomp、cgroups、capability drop、pivot_root、 uid/gid dropping等等。目前已完成上述功能的支持。
3. 支持容器热迁移,通过CRIU技术实现。目前功能已经实现,但是使用起来还会产生问题。
4. 支持Windows 10 平台上的容器运行,由微软的工程师开发中。目前只支持Linux平台。
5. 支持Arm、Power、Sparc硬件架构,将由Arm、Intel、Qualcomm、IBM及整个硬件制造商生态圈提供支持。
6. 计划支持尖端的硬件功能,如DPDK、sr-iov、tpm、secure enclave等等。
7. 生产环境下的高性能适配优化,由Google工程师基于他们在生产环境下的容器部署经验而贡献。

example : 通过 docker 一些命令, 实现不使用 docker daemon 直接运行一个镜像.

① 创建容器标准包, 由 container 的 bundle 模块实现, 将 docker 镜像转换成容器标准包
    $ mkdir my_container
    $ cd my_container
    $ mkdir rootfs
    $ docker export $(docker create busybox) | tar -C rootfs -xvf -

    上述命令, 将 busybox 镜像解压缩到指定的 rootfs 目录中. 如果本地不存在 busybox 进香港, containerd 会通过 distribution 模块去远程仓库拉取.

② 创建配置文件
    $ docker-runc spec

    # 会生成一个 config.json 的配置文件, 该文件和 docker 容器的配置文件类似, 主要包含容器挂载信息, 平台信息, 进程信息等容器启动以来的所有数据.

③ 通过 runc 命令来启动容器
    $ apt install runc -y
    $ runc run busybox

docker-proxy

docker 的端口转发工具. 实现容器与主机的端口映射.

示例 :

$ docker run -itd -p 8008:80008 busybox /bin/sh 

$ ps aux |grep docker       # 注意查看 docker-proxy 的端口对应.

    root       1498  0.0  0.1 234236 12020 ?        Ssl  312   4:56 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc

    root      88902  0.0  0.0  34464  2936 ?        Sl   11:21   0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8008 -container-ip 172.17.0.3 -container-port 8008

    root      88906  0.0  0.0 198748  2920 ?        Sl   11:21   0:00 docker-containerd-shim 695522643fb8a54ea5d7483ca353c95ed91cba3f2e18ce4b2af286bbc6c3412b /var/run/docker/libcontainerd/695522643fb8a54ea5d7483ca353c95ed91cba3f2e18ce4b2af286bbc6c3412b docker-runc

docker-proxy 命令行

$ docker-proxy --help
    Usage of docker-proxy:
      -container-ip string
            container ip
      -container-port int
            container port (default -1)
      -host-ip string
            host ip
      -host-port int
            host port (default -1)
      -proto string
            proxy protocol (default "tcp")
<think>好的,用户想深入了解Docker的工作原理,特别是容器化技术的实现。首先,我需要整理Docker的核心组件和它们之间的协作方式。根据引用[4],Docker引擎是核心,负责管理镜像、容器、网络等。应该先解释Docker引擎的架构,包括守护进程、REST API和CLI。 接下来是容器运行时,比如containerd和runc。需要说明它们如何与Docker引擎交互,runc如何根据OCI标准创建容器。这部分可能涉及到Linux命名空间和控制组(cgroups),用来实现资源隔离和管理,引用[4]提到了隔离性,这里需要详细展开。 然后是镜像的分层存储结构,引用[3]提到Dockerfile构建镜像的过程,可以解释分层存储的好处,比如每一层只读,通过联合文件系统(如OverlayFS)合并成容器可写的顶层。这样能提高效率和节省空间。 网络模型部分,引用[4]和引用[2]中的docker network相关命令,可能需要说明Docker的网络驱动,如bridge、host、none等,以及容器之间如何通信。 存储驱动方面,引用[4]提到存储驱动解析,需要简要说明不同的存储驱动如何管理镜像层和容器数据。 用户还要求生成相关问题,可能需要围绕Docker组件、隔离机制、镜像构建、网络模型、存储优化等方面提问,确保覆盖用户可能感兴趣的扩展知识点。同时,要确保所有技术细节准确,引用正确的参考文献,比如在讲镜像构建时引用[3],在讲引擎时引用[4]等。 最后检查是否符合系统指令:行内公式用$...$,独立公式用$$...$$,但在这个问题中可能涉及较少数学公式,更多是技术术语。确保使用中文,结构清晰,问题相关且覆盖主要知识点。</think>### Docker 工作原理深入解析 #### 一、核心组件与架构 Docker 的核心架构由三个关键组件构成: 1. **Docker 守护进程 (Docker Daemon)** 负责管理镜像、容器、网络和存储的核心服务,通过 REST API 接收指令[^4]。 2. **容器运行时 (Container Runtime)** 例如 `containerd` 和 `runc`,`runc` 基于 OCI (开放容器倡议) 标准创建容器进程[^4]。 3. **客户端 (Docker CLI)** 用户通过命令行工具发送指令,例如 `docker run` 会触发守护进程创建容器[^2]。 #### 二、容器化技术实现 1. **Linux 命名空间 (Namespaces)** 提供资源隔离,包括: - **PID 命名空间**:隔离进程视图(容器内首个进程 PID=1) - **Network 命名空间**:独立网络栈(每个容器有虚拟网卡) - **Mount 命名空间**:隔离文件系统挂载点 2. **控制组 (cgroups)** 限制容器资源使用,例如: - 内存限制:`cgroup/memory/memory.limit_in_bytes` - CPU 配额:`cgroup/cpu/cpu.cfs_quota_us` 3. **联合文件系统 (UnionFS)** 镜像分层存储的底层支持,例如 OverlayFS 的结构: ``` UpperDir (可写层) LowerDir (只读镜像层) MergedDir (最终视图) ``` #### 三、关键流程解析 1. **镜像构建与分发** - 通过 `docker build` 执行 Dockerfile 指令,每一条命令生成一个只读层[^3] - 镜像推送至仓库时,仅传输新增层(哈希值匹配的层可复用) 2. **容器启动流程** ```mermaid graph TD A[docker run] --> B(检查本地镜像) B -->|不存在| C[从仓库拉取镜像[^2]] B -->|存在| D[创建可写层] D --> E[runc 创建命名空间和 cgroups] E --> F[启动容器进程] ``` 3. **网络通信模型** - **Bridge 模式**:默认创建虚拟网桥 `docker0`,容器通过 veth pair 连接 - 数据包转发通过 iptables 规则实现,例如端口映射: ```bash iptables -t nat -A DOCKER -p tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80 ``` #### 四、优势与性能对比 与虚拟机的差异体现在: | 特性 | Docker 容器 | 虚拟机 | |---------------------|---------------------|----------------------| | 启动速度 | 毫秒级 | 分钟级 | | 资源占用 | 共享内核,占用低 | 独立内核,占用高 | | 隔离性 | 进程级别 | 硬件级别 | | 性能损耗 | <5% | 15%-20% | (数据参考 IBM 对比研究[^1])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值