首页 > 解决方案 > Docker-in-Docker GitLab CI 幽灵容器

问题描述

在我的组织中,我们使用 GitLab CI,我们的管道包含一个在 Docker 映像中运行的作业。

Job 在 Docker 镜像中运行一个脚本,该脚本本身会启动一个 Docker 容器以进行测试,这使得这成为 Docker-in-Docker 的情况。GitLab 作业定义与以下内容非常相似:

job:
  image: docker:20.10.7
  tags:
    - our-custom-gitlab-runner-services
  script:
    # print some info
    - docker ps
    - docker network ls
    # build and run
    - docker network create my-net
    - docker build -t my-image .
    - docker run --rm --detach --net my-net --name my-container my-image
    # test
    # (run some tests here)
    # cleanup
    - docker stop my-container
    - docker network rm my-net

现在这似乎工作了一段时间。我正在试验,我尝试删除--rm标志和清理步骤,认为这并不重要,因为这项工作是独立的(哦,我错了)。

然后所有的地狱都崩溃了。

重新运行脚本后,docker psanddocker network ls命令会在不应该出现的情况下显示my-containermy-net存在。在构建和运行部分之前添加额外的命令以删除这些工作作为一种解决方法,但docker psdocker network ls在后续运行中重复显示这些重影。就像被创造出来之后它们现在永远存在一样。

问题是为什么会发生这种情况?对这篇文章的正确答案可以清楚地解释这种现象。

标签: dockergitlabgitlab-cigitlab-ci-runnerdocker-in-docker

解决方案


这部分是因为您使用主机 docker 套接字安装作为 docker-in-docker 执行器机制。也就是说,您的作业直接连接到主机上的 docker 守护进程。

当您在作业中运行 docker 命令时,您将直接从作业容器与主机的 docker 守护进程进行通信。因此,GitLab 运行程序无法知道您创建了哪些容器或网络,甚至无法知道是否需要进行任何清理。它无法将您的作业创建的网络/容器与其他运行者或出于任何其他原因在主机上创建的容器区分开来。因此,GitLab Runner(明智地)不会做出任何努力来删除它没有直接创建的网络/容器。

一种可以防止这种情况发生的方法,这将使您的 docker-in-docker 构建更加封闭,是利用 dind 服务架构。不是将 docker 套接字直接安装到作业中,而是运行一个独立的 docker 守护程序作为作业的服务。这样,您的作业就有了自己的docker 守护进程,并且该守护进程由运行程序清理(当它清理时,您的作业创建的所有网络/容器也会这样做)。您必须相应地配置 GitLab 运行器和作业。这与GitLab 文档中的设置说明一起进行了进一步描述。

正确配置运行器后,作业定义可能如下所示:

myjob:
  image: docker
  services:
    - docker:dind  # <-- your own independent daemon!
  variables:
    # tell the docker client in your job
    # to communicate with the service daemon
    # instead of /var/run/docker.sock
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""

  script:
    - docker network ls 
    # won't ever include my-net because 
    # it is destroyed along with the docker:dind service 
    # when your job ends!
    - docker network create my-net
    - docker info
    # ...

这也是 docker-in-docker 与 GitLab 的更好设置,以使您的构建系统更安全并(帮助)防止作业逃离其容器。当不同的项目使用相同的底层主机时,这一点尤其重要。


推荐阅读