在 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 或容器管理系统时做出正确的架构选择。

相关推荐
Patrick_Wilson4 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
Suroy5 天前
DockerView-Go:用 Go 写一个终端 Docker 监控工具,顺便做了个 Web 仪表盘
docker
云恒要逆袭5 天前
运行你的第一个Docker容器
后端·docker·容器
宋均浩6 天前
# Docker 镜像瘦身实战:从 1.2G 到 80MB 的五个优化步骤
ci/cd·docker
程序员老赵6 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程
WangMingHua1117 天前
LM Studio Docker 部署——本地大模型一键启动
docker
曲幽8 天前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate
武子康9 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
Alsn8612 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker
JLWcai2025100912 天前
铸造领域树脂砂轮|金利威多场景解决方案,20 + 配方覆盖全需求
mongodb·zookeeper·eureka·spark·rabbitmq·memcached·storm