频道
bg

Docker in Docker

coding一月 08, 20241mins
Docker OP

Docker in Docker是指在容器中运行Containerd,使用docker:dind 镜像并设置为privilege 模式运行。

console

$docker run --privileged --name some-docker -d \
--network some-network --network-alias docker \
-e DOCKER_TLS_CERTDIR=/certs \
-v some-docker-certs-ca:/certs/ca \
-v some-docker-certs-client:/certs/client \
docker:dind

TLSH2

从18.09+开始, 如果设置了DOCKER_TLS_CERTDIR 环境变量,dind默认会启用TLS,并降证书生成到DOCKER_TLS_CERTDIR 指定的目录。

启用了TLS后Docker进行会以下面的方式启动:

bash

--host=tcp://0.0.0.0:2376 --tlsverify

否则

bash

--host=tcp://0.0.0.0:2375

客户端容器需要访问dind,就需要传入证书

bash

```console
$ docker run --rm --network some-network \
-e DOCKER_TLS_CERTDIR=/certs \
-v some-docker-certs-client:/certs/client:ro \
docker:latest version
Client: Docker Engine - Community
Version: 18.09.8
API version: 1.39
Go version: go1.10.8
Git commit: 0dd43dd87f
Built: Wed Jul 17 17:38:58 2019
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.8
API version: 1.39 (minimum version 1.12)
Go version: go1.10.8
Git commit: 0dd43dd87f
Built: Wed Jul 17 17:48:49 2019
OS/Arch: linux/amd64
Experimental: false

Gitlab CIH2

Gitlab CI中使用service可以额外运行一个dind容器来实现容器、镜像相关的操作

default:

image: docker:24.0.5
services:
- docker:24.0.5-dind
before_script:
- docker info
variables:
# When you use the dind service, you must instruct Docker to talk with
# the daemon started inside of the service. The daemon is available
# with a network connection instead of the default
# /var/run/docker.sock socket. Docker 19.03 does this automatically
# by setting the DOCKER_HOST in
# https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03/docker-entrypoint.sh#L23-L29
#
# The 'docker' hostname is the alias of the service container as described at
# https://docs.gitlab.com/ee/ci/services/#accessing-the-services.
#
# Specify to Docker where to create the certificates. Docker
# creates them automatically on boot, and creates
# `/certs/client` to share between the service and job
# container, thanks to volume mount from config.toml
DOCKER_TLS_CERTDIR: "/certs"
build:
stage: build
script:
- docker build -t my-docker-image .
- docker run my-docker-image /script/to/run/tests

这里DOCKER_TLS_CERTDIR就是dind 文档中提到的。另外对于作为client的docker镜像,讲道理是需要设置DOCKER_HOST 变量来连接到外部的docker进程的。默认的entrypoint 已经做了相关设置

bash

# if DOCKER_HOST isn't set and we don't have the default unix socket, let's set DOCKER_HOST to a sane remote value
if [ -z "${DOCKER_HOST:-}" ] && [ ! -S /var/run/docker.sock ]; then
if _should_tls || [ -n "${DOCKER_TLS_VERIFY:-}" ]; then
export DOCKER_HOST='tcp://docker:2376'
else
export DOCKER_HOST='tcp://docker:2375'
fi
fi

可以看到,如有没有unix socket以及DOKCER_HOST的话,默认的设置docker 未host名,而gitlab CI的serivce的默认别名正好是根据镜像的名称来的(也可以手动指定alias)

参考: 1: docker - Official Image | Docker Hub 2: Use Docker to build Docker images | GitLab

自定义的镜像的DIND初始化H2

Dockerfile

bash

FROM eclipse-temurin:17
ENV TZ="Asia/Shanghai" \
DOCKER_VERSION="24.0.5" \
apkArch="x86_64"
# Install base packages
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
git; \
rm -rf /var/lib/apt/lists/*; \
echo "https://download.docker.com/linux/static/stable/${apkArch}/docker-${DOCKER_VERSION}.tgz" && \
wget -qO "/tmp/docker-${DOCKER_VERSION}-ce.tgz" \
"https://download.docker.com/linux/static/stable/${apkArch}/docker-${DOCKER_VERSION}.tgz" && \
tar zxf "/tmp/docker-${DOCKER_VERSION}-ce.tgz" -C /tmp && \
mv /tmp/docker/docker /usr/bin
COPY docker-entrypoint.sh /usr/local/bin/
RUN /__cacert_entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]

entrypoint.sh

bash

#!/bin/sh
set -eu
_should_tls() {
[ -n "${DOCKER_TLS_CERTDIR:-}" ] \
&& [ -s "$DOCKER_TLS_CERTDIR/client/ca.pem" ] \
&& [ -s "$DOCKER_TLS_CERTDIR/client/cert.pem" ] \
&& [ -s "$DOCKER_TLS_CERTDIR/client/key.pem" ]
}
# if we have no DOCKER_HOST but we do have the default Unix socket (standard or rootless), use it explicitly
if [ -z "${DOCKER_HOST:-}" ] && [ -S /var/run/docker.sock ]; then
export DOCKER_HOST=unix:///var/run/docker.sock
elif [ -z "${DOCKER_HOST:-}" ] && XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" && [ -S "$XDG_RUNTIME_DIR/doc
ker.sock" ]; then
export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock"
fi
# if DOCKER_HOST isn't set (no custom setting, no default socket), let's set it to a sane remote value
if [ -z "${DOCKER_HOST:-}" ]; then
if _should_tls || [ -n "${DOCKER_TLS_VERIFY:-}" ]; then
export DOCKER_HOST='tcp://docker:2376'
else
export DOCKER_HOST='tcp://docker:2375'
fi
fi
if [ "${DOCKER_HOST#tcp:}" != "$DOCKER_HOST" ] \
&& [ -z "${DOCKER_TLS_VERIFY:-}" ] \
&& [ -z "${DOCKER_CERT_PATH:-}" ] \
&& _should_tls \
; then
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH="$DOCKER_TLS_CERTDIR/client"
fi
exec "$@"

评论


新的评论

匹配您的Gravatar头像

Joen Yu

@2022 JoenYu, all rights reserved. Made with love.