Docker 容器网络与 Docker-in-Docker

Posted

技术标签:

【中文标题】Docker 容器网络与 Docker-in-Docker【英文标题】:Docker Container Networking with Docker-in-Docker 【发布时间】:2017-12-03 11:33:09 【问题描述】:

我想通过 docker-in-docker 设置与父 docker 容器中的子 docker 容器建立网络。

假设我正在尝试连接到一个简单的 Apache httpd 服务器。当我在主机上运行 httpd 容器时,一切正常:

asnyder:~$ docker run -d -p 8080:80 httpd:alpine
asnyder:~$ curl localhost:8080
<html><body><h1>It works!</h1></body></html>

但是,当我在 docker-in-docker 设置中执行相同操作时,我会收到 Connection refused 错误:

asnyder:~$ docker run -d --name mydind --privileged docker:dind
asnyder:~$ docker run -it --link mydind:docker docker:latest sh
/ # docker run -d -p 8080:80 httpd:alpine
/ # curl localhost:8080
curl: (7) Failed to connect to localhost port 8080: Connection refused

我尝试了几次更改,但都没有运气。指定0.0.0.0 接口:

asnyder:~$ docker run -d --name mydind --privileged docker:dind
asnyder:~$ docker run -it --link mydind:docker docker:latest sh
/ # docker run -d -p 0.0.0.0:8080:80 httpd:alpine
/ # curl 0.0.0.0:8080
curl: (7) Failed to connect to 0.0.0.0 port 8080: Connection refused

使用主机网络:

asnyder:~$ docker run -d --name mydind --privileged docker:dind
asnyder:~$ docker run -it --link mydind:docker docker:latest sh
/ # docker run -d --network host httpd:alpine
/ # curl localhost:80
curl: (7) Failed to connect to localhost port 80: Connection refused

令人惊讶的是,我找不到任何关于此的现有文章。这里有人有一些见解吗?

谢谢!

【问题讨论】:

我先问你是否确定要使用 docker-in-docker 设置?请先阅读this 博文。 @JonesV 我避免进入问题中的特定场景以保持一般性,但既然你问了......我正在写GitLab CI Pipeline Job。 GitLab CI 中的作业在您可以指定的 docker 容器中运行。我正在编写一个基于某些 HTML 生成 PDF 报告的作业,并且我想利用现有的 Docker 映像来执行此操作。所以,我有一个码头工人的情况。我希望这有助于澄清:) 恐怕我无法帮助进行 docker-in-docker 设置。我只是想确保您了解博文中提到的要点 =)。 我自己也遇到了同样的问题——GitLab CI 使用docker 图像和docker:dind 服务,我也可以从我自己的主机连接,但不能在docker 容器内连接。非常清晰和恰当的问题! 【参考方案1】:

DinD 和绑定安装 Docker 套接字各有利弊,而且两者肯定都有用例。例如,查看this set of blog posts,它很好地解释了其中一个用例。

鉴于上述 docker-in-docker 设置示例,您可以通过以下两种方式之一访问 Apache httpd 服务器:

1) 在docker:dind 容器内,它将在localhost:8080 上可用。

2) 从您最初尝试访问它的docker:latest 容器内部,它可以在为docker:dind 容器设置的任何主机名上使用。在本例中,您使用了--name mydind,因此curl mydind:8080 将为您提供标准的Apache &lt;html&gt;&lt;body&gt;&lt;h1&gt;It works!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;

希望这是有道理的!

【讨论】:

你们俩都很棒!谢谢! 什么会导致子容器无法从主机容器访问,例如localhost:8080 连接失败,连接被拒绝(curl)? 这很好地描述了我在尝试从主机容器的暴露端口访问子容器时看到的问题:edureka.co/community/12457/… 我还在为此苦苦挣扎。父容器和dind容器之间是否需要链接或网络?【参考方案2】:

以Yuriy's answer为基础:

2) 从docker:latest container 内部,[...] 它可以在为docker:dind 容器设置的任何主机名上使用。在这种情况下,您使用了--name mydind,因此curl mydind:8080 [...]

在 Gitlab CI 配置中,你可以address the DinD container by the name of its image(除了它的容器名称,它是自动生成的):

访问服务


假设您需要一个 Wordpress 实例来测试与您的应用程序的某些 API 集成。

然后,您可以在 .gitlab-ci.yml 中使用 tutum/wordpress 图像:

services:
- tutum/wordpress:latest

如果你不specify a service alias,当作业运行时,tutum/wordpress 将被启动,你将可以在两个主机名下从你的构建容器中访问它:

tutum-wordpress tutum__wordpress

使用

service:
- docker:dind

将允许您以 docker:8080 的身份访问该容器:

  script:
  - docker run -d -p 8080:80 httpd:alpine
  - curl docker:8080

编辑:如果您想要更明确的主机名,可以as the documentation states,使用alias

services:
- name: docker:dind
  alias: dind-service

然后

  script:
  - docker run -d -p 8080:80 httpd:alpine
  - curl dind-service:8080

第, dtk

【讨论】:

如果我在 GitlabCI 中使用这个脚本:docker-compose -f docker-compose.yml up 并且如果我有一个名为 mongodb 的服务会发生什么?我好像不能用mongodb 作为主机名。【参考方案3】:

我非常确信@Yuriy Znatokov 的答案是我想要的,但我已经理解了很长时间。为了方便后人理解,我把完整的步骤导出了。

1) 从 docker:dind 容器内部

docker run -d --name mydind --privileged docker:dind
/ # docker run -d -p 8080:80 httpd:alpine
/ # curl localhost:8080
<html><body><h1>It works!</h1></body></html>

2) 从 docker:latest 容器内部

docker run -d --name mydind --privileged docker:dind
docker run -it --link mydind:docker docker:latest sh
/ # docker run -d -p 8080:80 httpd:alpine
/ # curl mydind:8080
<html><body><h1>It works!</h1></body></html>

【讨论】:

以上是关于Docker 容器网络与 Docker-in-Docker的主要内容,如果未能解决你的问题,请参考以下文章

Docker网络与容器互联

Docker网络与容器互联

Docker基本命令与使用 —— Docker容器的网络连接

docker存储与网络

docker与宿主通信突然断了

Docker知识点翻阅手册--Docker常用命令DockererfileCompose网络等整理合集