2. Docker 核心架构回顾:Docker Daemon、Containerd、Runc、客户端与服务端通信模型
在深入后端鉴权拦截机制之前,必须重新梳理 Docker 的底层架构。Docker 并非一个单体二进制,而是一组遵循 OCI(Open Container Initiative)标准的模块化组件协作系统。理解这些组件之间的通信边界与职责划分,是定位鉴权失败、连接超时、权限拒绝等故障的前提。
2.1 整体架构分层
Docker 引擎从用户视角到内核视角可划分为四层:
| 层级 | 组件 | 职责 | 通信方式 |
|---|---|---|---|
| 客户端层 | docker CLI / SDK |
解析用户命令,构造 RESTful 请求 | HTTP(S) / Unix Socket |
| 管理守护进程层 | dockerd (Docker Daemon) |
API 鉴权、镜像管理、容器编排、网络存储管理 | gRPC / REST |
| 容器运行时层 | containerd |
容器生命周期管理(创建、启动、停止)、镜像拉取与存储 | gRPC (通过 CRI) |
| 低级运行时层 | runc |
与内核交互,通过 cgroups/namespace 创建隔离进程 | OCI Bundle / exec 调用 |
故障排查要点: 鉴权拦截通常发生在 客户端 → dockerd 的 TLS 握手阶段,以及 dockerd → containerd 的 gRPC 凭证交换阶段。runc 层不参与网络鉴权,但若其权限配置错误(如 AppArmor/SELinux),会导致容器启动后立即退出,误判为鉴权失败。
2.2 客户端与服务端通信模型
Docker 采用典型的 C/S 架构。客户端通过三种方式与服务端建立连接:
- Unix Socket(默认):
unix:///var/run/docker.sock,仅限本地 root 用户或 docker 组用户访问,无网络鉴权开销。 - TCP Socket(远程访问):
tcp://host:2375(未加密)或tcp://host:2376(TLS 加密),必须配置证书鉴权。 - SSH 隧道:
ssh://user@host,依赖 SSH 鉴权,Docker 本身不参与。
当使用 TCP 远程访问时,完整的请求鉴权流程如下:
- 客户端发起 TCP 连接,进行 TLS 握手(若启用)。
- 服务端验证客户端证书的 CA 签名与 Common Name。
- 握手成功后,客户端发送 HTTP 请求(如
POST /containers/create)。 - dockerd 的 HTTP 路由层解析请求,调用 AuthZ 插件(若配置)进行授权检查。
- 通过后,请求被转发至 containerd 或内部模块处理。
常见故障: 客户端证书过期或未配置
--tlscacert 会导致 certificate signed by unknown authority 错误。此时请求在 TLS 层即被拒绝,不会进入 AuthZ 插件阶段。
2.3 Docker Daemon 内部组件协作
dockerd 并非直接调用 runc,而是通过 containerd 作为中间层。这种解耦设计使得 dockerd 可以热升级而不影响运行中的容器。内部协作流程如下:
- dockerd 收到创建容器请求后,通过 gRPC 调用 containerd 的
CreateContainer接口。 - containerd 将请求转换为 OCI 规范格式,生成
config.json和 rootfs,并调用runc create。 - runc 根据 OCI Bundle 配置 cgroups、namespace,最终通过
clone()系统调用启动容器进程。
鉴权拦截点: dockerd 与 containerd 之间的 gRPC 通信默认使用本地 Unix Socket(
/run/containerd/containerd.sock),不经过网络,因此不存在 TLS 鉴权。但若 containerd 被配置为远程模式(如 Kubernetes 中的 CRI 远程运行时),则需要在 gRPC 层配置 mTLS。
2.4 关键通信路径故障排查清单
当遇到“权限拒绝”或“连接超时”类错误时,按以下路径逐层排查:
| 故障现象 | 可能原因 | 排查命令 / 方法 |
|---|---|---|
docker ps 返回 permission denied |
当前用户不在 docker 组,或 socket 权限错误 | ls -l /var/run/docker.sock;groups $USER |
docker -H tcp://host:2376 info 超时 |
TLS 证书未配置或端口未开放 | openssl s_client -connect host:2376;检查防火墙 |
docker run 返回 unauthorized |
AuthZ 插件拒绝,或证书 CN 不匹配 | 查看 dockerd --debug 日志;检查 ~/.docker/config.json |
| 容器创建成功但立即退出 | runc 权限不足(SELinux/AppArmor) | journalctl -u containerd;dmesg | grep -i denied |
最佳实践: 在生产环境中,始终使用
dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376 启动,并配合 AuthZ 插件(如 authz-broker)实现细粒度访问控制。