当前位置:   article > 正文

dind(docker in docker)学习_hood docker-in-docker (dind)

hood docker-in-docker (dind)

文章目录

docker in docker

说白了,就是在docker容器内启动一个docker daemon,对外提供服务。
每个运行中的容器,都是一个进程;这个进程都托管在docker daemon中。
优点在于:

  1. 镜像和容器都在一个隔离的环境,保持宿主机的环境。
  2. 想到了再补充 :)

一、实现方式

dind一般分两种方式:

  1. 一种是使用宿主机的docker.sock,通过docker run -v /var/run/docker.sock:/var/run/docker.sock,将宿主机sock引入到容器内。这样当容器内使用docker命令时,实际上调用的是宿主机的docker daemon,这种方式速度快,但是安全性不够。
  2. 另一种是启动一个docker:dind容器a,再启动一个docker容器b,容器b指定host为a容器内的docker daemon;

二、低版本启动及访问

启动1.12.6-dind

docker run --privileged -d --name mydocker docker:1.12.6-dind

在其他容器访问

docker run --rm --link mydocker:docker docker:1.12.6 version

在宿主机访问

docker -H 172.17.0.2:2375 version
docker -H 0.0.0.0:${hostport} version

三、18.09以上dind镜像,加入了tls

19.03+默认tls模式,通过DOCKER_TLS_CERTDIR=‘’,可以关闭

#启动stable 19.03.1版本
docker run --privileged --name some-docker -d 
  • 1
  • 2

#–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:stable-dind

#其他容器内访问
docker run --rm 
  • 1
  • 2

#–network some-network
-e DOCKER_TLS_CERTDIR=/certs
-v some-docker-certs-client:/certs/client:ro
–link some-docker:docker
docker:stable version

四、dind实现原理

  • build时,使用的docker cli版本是dind内的版本

  • 传递数据到dind容器,然后再编译

  • 编译压力在dind容器内

  • 通过抓包,可以其实这是一个http请求

  • 代码:

    func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
    query, err := cli.imageBuildOptionsToQuery(options)
    if err != nil {
    return types.ImageBuildResponse{}, err
    }

    headers := http.Header(make(map[string][]string))
    buf, err := json.Marshal(options.AuthConfigs)
    if err != nil {
        return types.ImageBuildResponse{}, err
    }
    //这两句比较重要
    headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
    headers.Set("Content-Type", "application/x-tar")
    
    serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
    if err != nil {
        return types.ImageBuildResponse{}, err
    }
    
    osType := getDockerOS(serverResp.header.Get("Server"))
    
    return types.ImageBuildResponse{
        Body:   serverResp.body,
        OSType: osType,
    }, nil
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    }

四:19.03.1-dind Dockerfile

FROM alpine:3.10

RUN apk add --no-cache 
	ca-certificates

# set up nsswitch.conf for Go's "netgo" implementation (which Docker explicitly uses)
# - https://github.com/docker/docker-ce/blob/v17.09.0-ce/components/engine/hack/make.sh#L149
# - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275
# - docker run --rm debian:stretch grep '^hosts:' /etc/nsswitch.conf
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf

ENV DOCKER_CHANNEL stable
ENV DOCKER_VERSION 19.03.1
# todo ENV DOCKER_SHA256
# https://github.com/docker/docker-ce/blob/5b073ee2cf564edee5adca05eee574142f7627bb/components/packaging/static/hash_files !!
# (no SHA file artifacts on download.docker.com yet as of 2017-06-07 though)

RUN set -eux; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

this “case” statement is generated via “update.sh”

	apkArch="$(apk --print-arch)"; 
case "$apkArch" in 
  • 1
  • 2

amd64

		x86_64) dockerArch='x86_64' ;; 
  • 1

arm32v6

		armhf) dockerArch='armel' ;; 
  • 1

arm32v7

		armv7) dockerArch='armhf' ;; 
  • 1

arm64v8

		aarch64) dockerArch='aarch64' ;; 
	*) echo >&2 "error: unsupported architecture ($apkArch)"; exit 1 ;;
esac; 

if ! wget -O docker.tgz "https://download.docker.com/linux/static/${DOCKER_CHANNEL}/${dockerArch}/docker-${DOCKER_VERSION}.tgz"; then 
	echo >&2 "error: failed to download 'docker-${DOCKER_VERSION}' from '${DOCKER_CHANNEL}' for '${dockerArch}'"; 
	exit 1; 
fi; 

tar --extract 
	--file docker.tgz 
	--strip-components 1 
	--directory /usr/local/bin/ 
; 
rm docker.tgz; 

dockerd --version; 
docker --version

COPY modprobe.sh /usr/local/bin/modprobe
COPY docker-entrypoint.sh /usr/local/bin/

# https://github.com/docker-library/docker/pull/166
#   dockerd-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-generating TLS certificates
#   docker-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-setting DOCKER_TLS_VERIFY and DOCKER_CERT_PATH
# (For this to work, at least the "client" subdirectory of this path needs to be shared between the client and server containers via a volume, "docker cp", or other means of data sharing.)
ENV DOCKER_TLS_CERTDIR=/certs
# also, ensure the directory pre-exists and has wide enough permissions for "dockerd-entrypoint.sh" to create subdirectories, even when run in "rootless" mode
RUN mkdir /certs /certs/client && chmod 1777 /certs /certs/client
# (doing both /certs and /certs/client so that if Docker does a "copy-up" into a volume defined on /certs/client, it will "do the right thing" by default in a way that still works for rootless users)

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["sh"]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

五:docker-entrypoint.sh

#!/bin/sh
set -eu

# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
	set -- docker "$@"
fi

# if our command is a valid Docker subcommand, let's invoke it through Docker instead
# (this allows for "docker run docker ps", etc)
if docker help "$1" > /dev/null 2>&1; then
	set -- docker "$@"
fi

_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/docker.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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

; then
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH="$DOCKER_TLS_CERTDIR/client"
fi

if [ "$1" = 'dockerd' ]; then
	cat >&2 <<-'EOW'
		?? Hey there!  It looks like you're trying to run a Docker daemon.
		   You probably should use the "dind" image variant instead, something like:
		     docker run --privileged --name some-docker ... docker:dind ...
		   See https://hub.docker.com/_/docker/ for more documentation and usage examples.
	EOW
	sleep 3
fi

exec "$@"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/427936
推荐阅读
相关标签
  

闽ICP备14008679号