在Docker容器中操作Docker (dind)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Docker容器中操作Docker (dind)相关的知识,希望对你有一定的参考价值。

参考技术A

就是在Docker容器中再次运行一个Docker服务.

在一个容器中操作Docker在CI工具中是很常见的, 如构建一个Docker镜像.

但由于在容器中运行一个Docker服务会有各种问题, 如镜像文件存储, 嵌套的容器也并不容易维护, 后来便衍生出了另一种更实用的方案: 挂载主机上Docker服务的sock

这样将不会遇到嵌套副作用,并且将在多个调用之间共享构建缓存。

ps: 更多知识请阅读 docker 官方提及的这篇文章: do-not-use-docker-in-docker-for-ci

我接下来要写的也是如何使用它, 并记录我的使用场景.

我有一个需求是这样的:

当某个镜像更新之后, 通知docker重新pull并部署. 简单的来说就是当容器更新, 就自动运行

以实现更新部署.

由于自己编写的程序也运行在Docker中, 而不是宿主机, 所有没办法直接执行以上命令, 这就需要Docker In Docker了.

简单来说 你只需要这样:

然后 docker ps 就能看到 宿主机上 的所有容器.

如我的就是

当然 这里的stack.yaml文件需要在构建这个容器时添加进来 或者 挂载进来, 这肯定难不倒你.

如果你要将这段CMD在你的程序中运行也十分简单:

写好程序之后你可以使用这个Dockfile构建你的镜像

而运行这个镜像的stack.yaml文件需要配置挂载

你会看到我又挂载了.docker文件夹, 这个无关紧要, 在后面的疑难杂症会说到这个问题.

此参数是17.9版本之后新加的, 用于解决deploy不pull最新的镜像的问题. 详情看这个ISSUE:
force docker deploy to pull new images

私有仓库必须登录才有访问权限, 所以需要在宿主机上先login, 登录成功后会发现在 ~/.docker有新生成的 配置文件
, 其中存储了认证所需要的信息. 但在Docker容器中拿不到这个信息所以就会报错.

解决办法是将配置文件挂载进容器

问题描述:

网络结构如下:

客户端 -> 服务器上的nginx容器 (反代)-> 应用程序

在Nginx中配置了

在应用程序中得到"HTTP_X_FORWARDED_FOR"头 却是10.255.0.2, 而不是客户端真正的ip.

解决办法:
google : docker 10.255.0.2

得到的信息挺多的, 大多数是Docker3年4年都没有close的ISSUE....

当前可用的解决办法有

在dind中运行docker-compose时Docker容器拒绝通信 - Gitlab CI/CD

【中文标题】在dind中运行docker-compose时Docker容器拒绝通信 - Gitlab CI/CD【英文标题】:Docker containers refuse to communicate when running docker-compose in dind - Gitlab CI/CD 【发布时间】:2021-06-07 13:26:42 【问题描述】:

我正在尝试在 Gitlab CI/CD 中设置一些集成测试 - 为了运行这些测试,我想使用 Gitlab 运行器和 docker-compose up 重建我的系统(几个链接的容器)。我的系统是由几个通过mqtt相互通信的容器和一个被其他容器查询的InfluxDB容器组成的。

我已经设法让跑步者实际执行 docker-compose up 并创建所有相关容器。这是我的 .gitlab-ci.yml 文件:

    image: docker:19.03

    variables:
      DOCKER_DRIVER: overlay2
      DOCKER_TLS_CERTDIR: "/certs"

    services:
      - name: docker:19.03-dind
        alias: localhost

    before_script:
      - docker info

    integration-tests:
      stage: test
      script:
        - apk add --no-cache docker-compose
        - docker-compose -f "docker-compose.replay.yml" up -d --build
        - docker exec moderator-monitor_datareplay_1 bash -c 'cd src ; python integration_tests.py'

如您所见,我正在安装 docker-compose,在我的配置 yml 文件上运行 compose,然后从其中一个容器中执行我的集成测试。当我在本地系统上运行最后一行时,集成测试按预期运行;然而,在 CI/CD 环境中,所有测试都会抛出一些ConnectionRefusedError: [Errno 111] Connection refused 错误。运行 docker-compose ps 似乎显示所有相关容器都正常运行。

我发现问题源于每次一个容器尝试通过self.localClient = InfluxDBClient("influxdb", 8086, database = "replay")client.connect("mosquitto", 1883, 60) 之类的行与另一个容器进行通信。这在我的本地 docker 环境中运行良好,因为地址名称解析为正在运行的其他容器,但似乎在这个 Docker-in-Docker 设置中产生了问题。有没有人有什么建议?这个dind环境中的容器有不同的名字吗?

还值得一提的是,这可能是我的 docker-compose.yml 文件未正确配置以启动健康容器的问题。 docker-compose ps 表示它们已启动,但有没有更好的方法来检查它们是否正常运行?这是我的 docker-compose 文件的摘录:

services:
    datareplay:
      networks:
        - web
        - influxnet
        - brokernet
      image: data-replay
      build:
        context: data-replay
      volumes:
        - ./data-replay:/data-replay

    mosquitto:
      image: eclipse-mosquitto:latest
      hostname: mosquitto
      networks:
        - web
        - brokernet

networks:
  web:
  influxnet:
    internal: true
  brokernet:
    driver: bridge
    internal: true

【问题讨论】:

【参考方案1】:

出现此错误的原因有几种可能:

    Docker 19.03-dind is known to be problematic and unable to create networks when using services without a proper TLS setup 上的一个错误,您是否正确设置了带有 TLS 证书的 Gitlab Runner?我注意到您在您的gitlab-ci.yml 上使用"/certs",您是否安装了您的跑步者以共享存储证书的卷?

    如果您的 Gitlab Runner 未以特权权限运行或未正确配置为使用远程计算机的网络套接字,您将无法创建网络。统一您的网络以在 CI/CD 环境中运行的一个简单解决方案是使用this docker-compose 后跟this script 配置您的机器。 (Source) 它将设置一个本地网络,您可以在其中使用桥接网络驱动程序的网络中的主机名在容器之间进行通信。

    当您执行这部分脚本时,gitlab-ci.yml 也存在问题:

    services:
      - name: docker:19.03-dind
        alias: localhost 
    integration-tests:
      stage: test
      script:
        - apk add --no-cache docker-compose
        - docker-compose -f "docker-compose.replay.yml" up -d --build
        - docker exec moderator-monitor_datareplay_1 bash -c 'cd src ; python integration_tests.py'
    

您将 docker 主机名重命名为 localhost,但您从不使用它,而是直接键入以使用图像中的 dockerdocker-compose,将它们绑定到与创建的网络不同的网络集由 Gitlab 自动生成。

让我们试试这个解决方案(虽然我现在无法测试它,所以如果它不能立即起作用,我深表歉意):

gitlab-ci.yml

image: docker/compose:debian-1.28.5 # You should be running as a privileged Gitlab Runner
services:
  - docker:dind
integration-tests:
  stage: test
  script:
    #- apk add --no-cache docker-compose
    - docker-compose -f "docker-compose.replay.yml" up -d --build
    - docker exec moderator-monitor_datareplay_1 bash -c 'cd src ; python integration_tests.py'

docker-compose.yml

services:
  datareplay:
    networks:
      - web
      - influxnet
      - brokernet
    image: data-replay
    build:
      context: data-replay
  # volumes: You're mounting your volume to an ephemeral folder, which is in the CI pipeline and will be wiped afterwards (if you're using Docker-DIND)
   #  - ./data-replay:/data-replay
  mosquitto:
    image: eclipse-mosquitto:latest
    hostname: mosquitto
    networks:
      - web
      - brokernet

networks:
  web: # hostnames are created automatically, you don't need to specify a local setup through localhost
  influxnet:
  brokernet:
    driver: bridge #If you're using a bridge driver, an overlay2 doesn't make sense
  

这两个命令都会将 Gitlab Runner 安装为 Docker 容器,而无需手动配置它们以允许在您的项目上进行套接字绑定。

(1)

docker run --detach --name gitlab-runner --restart always -v /srv/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest

然后(2)

docker run --rm -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register --non-interactive --description "monitoring cluster instance" --url "https://gitlab.com" --registration-token "replacethis" --executor "docker"  --docker-image "docker:latest" --locked=true  --docker-privileged=true --docker-volumes /var/run/docker.sock:/var/run/docker.sock 

记得在 (2) 命令中更改您的令牌。

【讨论】:

非常感谢您的回复。我是 Gitlab CI/CD 的新手,所以我不明白你的全部答案。我完全按照“配置 TLS”下about.gitlab.com/blog/2019/07/31/… 中的步骤创建了一个具有特权权限的运行器。我不确定我是否将 Gitlab Runners 理解为您概述的 Docker 容器步骤。在我的 CI/CD 工作中,我注意到我的网络已成功创建。我还发现我可以 ping 例如CI/CD 工作期间数据重放的蚊子!对我来说,这表明网络已启动,但配置不正确? 我提到的 ping 步骤可以添加到我的 gitlab-ci.yml 文件:docker exec moderator-monitor_datareplay_1 bash -c 'ping -c 3 mosquitto',它的工作原理是:--- mosquitto ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 35ms。但是,当我在 python 中使用我的 mqtt 客户端连接到 mqtt 代理容器时,我仍然收到连接被拒绝的错误。 好的,最后的评论。我运行了你的两个命令 - 当我包含 -v /var/run/docker.sock:/var/run/docker.sock 时,我在这个问题中得到错误 gitlab.com/gitlab-org/gitlab-runner/-/issues/… 。如果我根据链接删除 --docker-privileged,它会抱怨 root 权限。基本上,可能配置的每一种排列都会在管道中的某个点导致一些错误。

以上是关于在Docker容器中操作Docker (dind)的主要内容,如果未能解决你的问题,请参考以下文章

GitLab Runner Docker Executor 中的缓存层 - 长时间 DinD 容器

docker-in-docker (dind) 服务在 gitlab ci 中的作用

[转帖]Docker里运行Docker docker in docker(dind)

docker-dind

Gradle bootBuildImage 使用 docker:dind 服务在 GitLab CI/CD 中失败并显示“未找到摘要”

使用alpine的docker镜像下 dind 的方式安装dotnet core 的一个非dockerfile的方法