• dind(docker in docker)学习


    文章目录

    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
  • 相关阅读:
    Python 接口测试之接口关键字封装
    JVM之方法区
    「零基础从零开始写VO视觉里程计」曲线拟合g2oCurveFitting.cpp(7-3)
    echarts优秀使用案例
    山东涛雒镇万亩水稻 国稻种芯·中国水稻节:日照迎来收割季
    phar反序列化
    【JAVA程序设计】(C00083)基于SSM+uniapp好物分享小程序及管理系统-有文档
    Apache commons exec框架的简介说明
    湖北绝缘监测仪矿业煤炭石油金矿玉矿铁矿铜矿矿井钢厂
    香港闯关相关法律
  • 原文地址:https://blog.csdn.net/m0_67391907/article/details/126327083