DinD 是什么
GitLab CI 里构建容器镜像,本质是需要一个 Docker 守护进程来执行 docker build。DinD(Docker in Docker)方案让作业通过 services 启动一个 docker:dind 容器充当守护进程,作业容器里的 docker 客户端连上它完成构建与推送;官方模板用 DOCKER_TLS_CERTDIR 开启 daemon 的 TLS 端口,并要求 Runner 允许特权模式。它适合流水线里直接跑 docker build 的团队,但隔离边界弱于免守护方案;对安全敏感的团队可换成 rootless 构建、BuildKit 或 kaniko 等不依赖宿主守护进程的方式。
基本信息
| 常见方式 | docker:dind 服务 + DOCKER_TLS_CERTDIR 开启 TLS 端口 |
|---|---|
| 要求 | 通常需要 Runner 开启特权(privileged),或宿主模式加相应安全配置 |
| 替代 | rootless 构建、BuildKit、kaniko 等免特权方案 |
| 缓存 | dind 的本地镜像层随作业销毁,用 registry 或 buildx 缓存导出加速 |
| 版本匹配 | docker 客户端与服务镜像主版本保持一致 |
典型使用场景
- 构建并推送应用镜像:作业内 docker build 后直接 push 到内网仓库,适合起步阶段的简单流水线。
- 需要完整 docker build 能力的场景:多阶段构建、构建参数、Dockerfile 特殊指令在 DinD 下按原语义执行。
- 临时拉起依赖容器:构建或测试时用 docker run 起一个数据库或工具容器,不污染 Runner 主机。
- 无法改造为 kaniko/BuildKit 的存量流水线:保留 DinD 是最小改动路径,先加固 Runner 隔离再谈迁移。
- 内网隔离环境:dind 与作业都在 CI 集群内,构建过程不经过公网。
DinD 模板
DinD 模板
build-image:
image: docker:27
services:
- docker:27-dind
variables:
DOCKER_TLS_CERTDIR: /certs # 开启 daemon TLS
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA构建方案对比
| 方案 | 隔离与前提 | 适用 |
|---|---|---|
| docker:dind | 需特权 Runner,隔离弱 | 存量流水线、需要完整 docker build |
| rootless dind | 免特权,配置更复杂 | 安全敏感环境 |
| kaniko | 免守护进程,不需要特权 | 受限集群、中小镜像 |
| BuildKit | rootless 或守护模式,支持缓存导出 | 追求构建速度的现代流水线 |
特权构建的隔离边界更弱:只在可信网络与专用 Runner 上启用,并限制可见范围。
缓存要显式设计:dind 本地镜像层不跨作业保留,用 registry 拉取缓存或 buildx 缓存导出,否则每次全量构建、流水线时长翻倍。
改了证书目录后请同步检查客户端连接变量:证书路径与端口两端不一致会直接连接失败。