#作者:鄧偉
文章目錄
- 一、背景:Docker 架構的演進之路
- 1.1 從自研運行時到 OCI 標準化
- 1.2 現行架構分層模型
- 二、核心交互組件解析
- 2.1 通信協議:gRPC 雙向流的應用
- 2.2 鏡像生命周期管理交互
- 2.2.1 鏡像拉取流程(以 docker pull 為例)
- 2.2.2 鏡像存儲格式轉換
- 2.3 容器運行時交互核心流程
- 2.3.1 容器創建階段(docker create)
- 2.3.2 容器啟動階段(docker start)
- 三、源碼級交互關鍵點解析
- 3.1 Docker Engine 到 Containerd 的接口映射
- 3.2 命名空間隔離機制
- 四、典型問題排查與性能優化
- 4.1 交互故障診斷工具鏈
- 4.2 性能優化關鍵點
- 五、未來演進:后 Docker 時代的 Containerd
- 5.1 Kubernetes 對 Containerd 的直接支持
- 5.2 功能對比矩陣
- 六、總結
一、背景:Docker 架構的演進之路
1.1 從自研運行時到 OCI 標準化
2013 年 Docker 誕生時,采用自研的libcontainer作為容器運行時。隨著容器技術標準化推進,2015 年 OCI(Open Container Initiative)成立,定義了容器運行時規范(CRI)和鏡像規范。關鍵轉折點:
- 2017 年 Docker 將libcontainer捐贈給 OCI,更名為runc
- 2019 年 Docker Engine 正式采用Containerd作為底層容器運行時管理組件
1.2 現行架構分層模型
Docker CLI
├─ gRPC通信│ └─ Docker Engine(dockerd)│ ├─ gRPC通信│ │ └─ Containerd(/run/containerd/containerd.sock)│ │ ├─ containerd-shim(容器墊片進程)│ │ └─ runc(OCI運行時)└─ 鏡像倉庫(Docker Hub/私有倉庫)
二、核心交互組件解析
2.1 通信協議:gRPC 雙向流的應用
關鍵接口定義(基于 containerd/api)
// containers/v1/container_service.proto
service ContainerService {rpc Create(CreateContainerRequest) returns (CreateContainerResponse) {}rpc Start(StartContainerRequest) returns (StartContainerResponse) {}rpc Delete(DeleteContainerRequest) returns (DeleteContainerResponse) {}}// images/v1/image_service.proto
service ImageService {rpc Pull(PullRequest) returns (stream PullResponse) {} // 流式拉取鏡像rpc Push(PushRequest) returns (stream PushResponse) {} // 流式推送鏡像
}
通信鏈路抓包驗證
# 監聽containerd socket通信strace -f -e trace=network -p $(pidof containerd)# 使用grpcurl查看服務列表grpcurl -unix /run/containerd/containerd.sock list
2.2 鏡像生命周期管理交互
2.2.1 鏡像拉取流程(以 docker pull 為例)
-
Docker CLI 解析鏡像名稱,發送ImagePull請求到 Docker Engine
-
Docker Engine 調用 Containerd 的ImageService.Pull接口
-
Containerd 執行以下操作:
-
解析鏡像引用(支持docker.io/library/nginx:alpine格式)
-
調用distribution庫從 Registry 拉取鏡像層
-
將鏡像層存儲到/var/lib/containerd/io.containerd.content.v1.content
-
返回鏈路:通過 gRPC 流返回拉取進度,CLI 顯示下載狀態
2.2.2 鏡像存儲格式轉換
Containerd 使用Content Addressable Storage (CAS)存儲鏡像,而 Docker 傳統格式為aufs/overlay2,通過containerd-shim實現格式適配:
# 查看Containerd存儲的鏡像摘要ctr content ls -q | head -n 1
sha256:1a5c2b3d4e5f6789012abc3def456# Docker鏡像與Containerd內容的映射關系/var/lib/docker/image/overlay2/repositories.json <-> containerd的boltdb元數據
2.3 容器運行時交互核心流程
2.3.1 容器創建階段(docker create)
2.3.2 容器啟動階段(docker start)
-
Containerd 通過containerd-shim啟動容器進程
-
containerd-shim負責:
-
保持容器進程與 init 系統的連接
-
傳遞信號(SIGKILL/SIGTERM)
-
收集容器狀態信息
-
1.核心調用鏈:
containerd/runtime/v2/shim/v2/shim.go:Start()└─ runc.Start()└─ syscall.execve() // 執行容器入口進程
三、源碼級交互關鍵點解析
3.1 Docker Engine 到 Containerd 的接口映射
關鍵代碼路徑(Docker 24.0.6 版本)
// docker/daemon/container_engine.go
func (eng *containerEngine) Create(ctx context.Context, req *containerd.CreateContainerRequest) (*containerd.CreateContainerResponse, error) {client, err := eng.client() // 獲取Containerd客戶端連接return client.Containers.Create(ctx, req)}// 客戶端連接初始化
func (eng *containerEngine) client() (*containerd.Client, error) {return containerd.New(eng.config.Containerd.Address, // 默認連接/run/containerd/containerd.sockcontainerd.WithDefaultNamespace("moby"), // Docker專屬命名空間)}
3.2 命名空間隔離機制
Docker 通過moby命名空間與 Containerd 其他租戶隔離:
# 查看Containerd命名空間ctr namespace lsNAME LABELSmoby <none>k8s.io <none> # Kubernetes專用命名空間
四、典型問題排查與性能優化
4.1 交互故障診斷工具鏈
4.2 性能優化關鍵點
-
減少 gRPC 調用開銷:
-
批量處理鏡像操作(如同時拉取多個鏡像層)
-
使用連接池復用 gRPC 通道
-
-
存儲驅動優化:
# /etc/containerd/config.toml
[plugins."io.containerd.runtime.v2.task"][plugins."io.containerd.runtime.v2.task.structs"][plugins."io.containerd.runtime.v2.task.structs.linux"]shim = "containerd-shim-runc-v2" # 使用v2版本墊片runtime = "runc"
- 資源限制傳遞:Docker 通過–cpu-shares/–memory參數傳遞的資源限制,最終由 Containerd 轉換為 cgroups 配置:
// containerd/runtime/v2/runc/options.go
func (o *LinuxOptions) ToSpec() (*specs.Spec, error) {// 解析CPU配額if o.CPUQuota > 0 {spec.Linux.Resources.CPU.CFSQuota = o.CPUQuota}// 解析內存限制if o.MemoryLimit > 0 {spec.Linux.Resources.Memory.Limit = &memory.Limit}}
五、未來演進:后 Docker 時代的 Containerd
5.1 Kubernetes 對 Containerd 的直接支持
自 Kubernetes 1.20 起,可直接使用 Containerd 作為 CRI 運行時,跳過 Docker 中間層:
# kubelet配置文件apiVersion: kubelet.config.k8s.io/v1kind: KubeletConfiguration
runtimeRequestTimeout: "15m"
containerRuntime: remotecontainerRuntimeEndpoint: unix:///run/containerd/containerd.sock
5.2 功能對比矩陣
六、總結
Docker 與 Containerd 的交互本質是標準化接口(OCI)+ 分層架構(管理平面與運行平面分離的典型實踐。理解兩者的通信協議(gRPC)、數據流轉(鏡像存儲 / CAS)和生命周期管理(容器創建 / 啟動流程),是解決容器化部署中復雜問題的關鍵。隨著 Kubernetes 生態對 Containerd 的直接支持,掌握這一交互機制也成為云原生工程師的核心能力之一。