最新消息:

在gitlabCI中构建docker镜像DinD和DooD

IT技术 ipcpu 809浏览 0评论

一、概述

在使用gitlab CICD的时候,有一项是绕不开的就是需要在构建过程当中执行docker build命令,构建新的docker镜像。

gitlab官方给出了3种方法

  1. The shell executor
  2. The Docker executor with the Docker image (Docker-in-Docker)
  3. Docker socket binding

第一种方法就不多说了,就是在操作系统中安装了一个gitlab runner shell executor ,可以执行当前操作系统的命令,共享当前操作系统的所有资源。
第二和第三种方法都是在docker容器中执行docker build命令,区别在于第二种是DockerinDocker,层次上更加深,更独立。我们接下来重点讨论这两种。

二、DinD(Docker in Docker)

DinD(Docker in Docker),指的是在一个安装有Docker engine的容器内以特权模式和与之--link的docker daemon进行通信,并在容器内构建新的Docker镜像。(嵌套,nested),如下图展示

使用dind的方式,需要安装如下方法注册runner

gitlab-runner register -n \
  --url https://gitlab.com/ \
  --registration-token REGISTRATION_TOKEN \
  --executor docker \
  --description "My Docker Runner" \
  --docker-image "docker:19.03.12" \
  --docker-privileged \
  --docker-volumes "/certs/client"

在gitlab中的.gitlab-ci.yml文件中这样配置

dockerbuild:
  stage: build
  image: docker:stable
  services:
    - name: docker:dind
      command: ["--mtu=1450", "--registry-mirror", "https://mirror.baidubce.com"]
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
    DOCKER_DRIVER: overlay2    
  before_script:
    - docker  info    
  script:
    - docker login -u xxx reg.ipcpu.com 
    - docker  build -t docker build -t my-docker-image  .
    - docker  push my-docker-image

三、DooD(Docker-outside-of-Docker)

DooD(Docker-outside-of-Docker) ,就是通过挂载卷的方式将-p /var/run/docker.sock:/var/run/docker.sock挂载到容器内,通过容器内部的docker engine与这个被挂载进来的docker.sock进行通信,生成新的docker容器。

使用dood的方式,需要安装如下方法注册runner

gitlab-runner register -n \
  --url https://gitlab.com/ \
  --registration-token REGISTRATION_TOKEN \
  --executor docker \
  --description "My Docker Runner" \
  --docker-image "docker:19.03.12" \
  --docker-volumes /var/run/docker.sock:/var/run/docker.sock

在gitlab中的.gitlab-ci.yml文件配置如下

image: docker:19.03.12

before_script:
  - docker info

build:
  stage: build
  script:
    - docker build -t my-docker-image .
    - docker push my-docker-image 

四、三种方法优缺点分析

  1. shell executor方法需要一台独立服务器(当然可以共用,但存在风险),最灵活,可以像使用shell一样,执行机器上的任何程序。但是在CICD时候,会存在一些冲突,例如A项目依赖软件B版本不能升级,但是B项目依赖软件B版本需要用最新的,在构建时就会存在问题,主要原因还是环境隔离性不够引起的。
  2. DinD的方法实现了各个环境的完全隔离,但是runner容器使用了 privileged权限,存在一定安全问题。另外实际使用中发现DinD产生的容器完全是空白的,还不能挂载宿主机资源(隔了一层),碰上需要使用缓存的地方(例如nodejs的缓存目录),性能会特别差,导致构建特别耗费时间。
  3. DooD的方法使用宿主的socket创建容器,也实现各个环境的完全隔离,并且可以使用挂载共享目录的方式共享宿主资源,实现缓存以及镜像的共享,一定程度上可以加快速度。但是直接共享了socket文件,相当于给出了最高docker权限,安全性也是大问题。另外如果需要创建相同名字的docker容器,会产生冲突。

在使用了一段时间的DinD以后,我们投入了DooD的怀抱,理由很简单,我们的nodejs需要共享缓存目录,来提升编译效率。

五、改善DinD特权模式的安全问题

gitlab上有个项目叫,sysbox, https://github.com/nestybox/sysbox 改善了这个问题。
Securing CI/CD pipelines by enabling Docker-in-Docker (DinD) or Kubernetes-in-Docker (KinD) without insecure privileged containers or host Docker socket mounts.

另外Google开源了kaniko, https://github.com/GoogleContainerTools/kaniko
kaniko 使用 Docker-in-Docker 构建 方法解决了两个问题:

Docker-in-Docker 需要特权模式才能运行,这是一个重要的安全问题。
Docker-in-Docker 通常会导致性能损失并且速度可能非常慢。

参考资料

https://docs.gitlab.com/ee/ci/docker/using_docker_build.html
https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/

来自为知笔记(Wiz)

转载请注明:IPCPU-网络之路 » 在gitlabCI中构建docker镜像DinD和DooD

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址