在 Docker 容器中控制宿主机 Docker:DoD 与 DinD 的技术原理解析

在构建 CI/CD 平台、发布系统或容器管理工具时,经常会看到如下配置:

plain 复制代码
volumes:
  - /var/run/docker.sock:/var/run/docker.sock

这个配置看似简单,却涉及 Docker 的核心通信机制。本文从底层原理出发,系统梳理:

  • docker.sock 的作用
  • 容器如何控制宿主机 Docker
  • CLI 与 SDK 两种调用方式的区别
  • DoD 与 DinD 架构差异
  • 生产环境需要关注的安全问题

一、docker.sock 的本质

在 Linux 系统中,Docker Daemon 通过 Unix Socket 提供 API 服务:

plain 复制代码
/var/run/docker.sock

Docker CLI(docker 命令)并不直接管理容器,它只是一个客户端工具。

当执行:

plain 复制代码
docker ps

实际发生的是:

plain 复制代码
docker CLI
    ↓
/var/run/docker.sock
    ↓
Docker Daemon
    ↓
返回容器列表

也就是说,真正执行容器操作的是 Docker Daemon,而 CLI 只是 API 调用者。


二、容器挂载 docker.sock 后发生了什么?

当在容器中挂载:

plain 复制代码
- /var/run/docker.sock:/var/run/docker.sock

意味着容器内部也可以访问宿主机的 Docker API。

此时,在容器内执行:

plain 复制代码
docker ps

控制的仍然是宿主机的 Docker Daemon,而不是容器内部的 Docker。

这也是很多发布平台和容器管理工具的实现方式。


三、两种常见调用方式

1️⃣ 通过 Docker CLI

示例:

plain 复制代码
import { exec } from "child_process";

exec("docker ps", (err, stdout) => {
  console.log(stdout);
});

特点:

  • 需要在容器中安装 docker-cli
  • 本质仍然是 CLI 调用 docker.sock
  • 错误处理依赖字符串解析

调用链:

plain 复制代码
Agent
   ↓
docker CLI
   ↓
/var/run/docker.sock
   ↓
Docker Daemon

2️⃣ 通过 Docker SDK(如 dockerode)

示例:

plain 复制代码
import Docker from "dockerode";

const docker = new Docker({
  socketPath: "/var/run/docker.sock",
});

const containers = await docker.listContainers();

调用链:

plain 复制代码
Agent
   ↓
Docker SDK
   ↓
/var/run/docker.sock
   ↓
Docker Daemon

对比:

维度 CLI 方式 SDK 方式
是否需要 docker-cli
调用方式 shell HTTP API
错误处理 字符串 JSON
日志流支持 复杂 原生支持
可扩展性 一般

两种方式最终控制的都是宿主机 Docker,差异仅在调用层。


四、DoD 与 DinD 的区别

Docker outside of Docker(DoD)

特点:

  • 容器内部没有 Docker Daemon
  • 通过挂载 docker.sock 控制宿主机 Docker
  • 资源消耗低
  • 启动速度快

架构模型:

plain 复制代码
Container (Agent)
       ↓
/var/run/docker.sock
       ↓
Host Docker Daemon

常见于:

  • Portainer
  • Watchtower

Docker in Docker(DinD)

特点:

  • 容器内部运行独立 Docker Daemon
  • 通常需要 privileged 模式
  • 适用于 CI 构建隔离环境

架构模型:

plain 复制代码
Container
   ↓
Docker Daemon(容器内部)
   ↓
子容器

常见于:

  • GitLab CI
  • Jenkins

五、安全风险分析

挂载 docker.sock 等价于授予容器对宿主机 Docker 的完全控制权。

通过 Docker API 可以:

  • 启动特权容器
  • 挂载宿主机目录
  • 修改网络配置
  • 删除任意容器

一旦容器被入侵,宿主机安全将受到影响。

常见缓解方式:

  • 不暴露 Agent 至公网
  • 使用内网通信
  • 使用强认证 Token
  • 尽量使用 SDK 而非 shell 执行

六、核心结论

  1. docker.sock 是 Docker Daemon 的通信入口
  2. 挂载 docker.sock 后,容器可以直接控制宿主机 Docker
  3. CLI 与 SDK 本质相同,区别在调用方式
  4. DoD 是生产环境常见方案
  5. DinD 适用于需要隔离 Docker 环境的场景

理解 docker.sock 的通信模型,有助于在设计 CI/CD 或容器管理系统时做出正确的架构选择。

相关推荐
正经教主1 天前
【docker基础】0、系统学习docker之总计划
学习·docker·容器
Yang三少喜欢撸铁1 天前
【Centos7通过kubeadm方式部署kubernetes1.30版本【一主两从】】
docker·kubernetes·container
杨浦老苏1 天前
开源宠物健康护理追踪器EinVault
docker·群晖·宠物·健康管理
@土豆1 天前
基于Docker部署Squid正向代理文档
运维·docker·容器
林润庚1 天前
win 安装openclaw (docker镜像模式),解决18789访问失败问题
docker·openclaw·龙虾
Cyber4K1 天前
【Kubernetes专项】K8s 包工具- Helm 入门到企业实战
云原生·容器·kubernetes
正经教主1 天前
【docker基础】Ubuntu 安装 Docker 超详细小白教程
ubuntu·docker·eureka
Chuncheng's blog1 天前
K8S二进制部署exec unable to upgrade connection: Unauthorized异常解决方案
云原生·容器·kubernetes
FJW0208141 天前
HAProxy+Keepalived实现Kubernetes高可用集群部署
云原生·容器·kubernetes
小江的记录本1 天前
【Swagger】Swagger系统性知识体系全方位结构化总结
java·前端·后端·python·mysql·spring·docker