【问题标题】:Access Docker daemon on Host without knowing Host OS在不知道主机操作系统的情况下访问主机上的 Docker 守护进程
【发布时间】:2020-03-29 14:21:18
【问题描述】:

我使用 docker-compose 来启动一些容器,作为我正在开发的应用程序的一部分。其中一个容器需要在主机上启动一个 docker swarm 服务。在适用于 Windows 的 Docker 和适用于 Mac 的 Docker 上,我可以使用 REST Api 通过使用“host.docker.internal”DNS 名称连接到主机 docker 守护程序,这非常有效。但是,如果我在 linux 上运行相同的 compose 文件,“host.docker.internal”将不起作用(但似乎它可能会出现在下一个版本的 docker 中)。更糟糕的是,在 Linux 上,我可以使用“主机”的网络模式来解决这个问题,但 Windows 或 Mac 不支持。

我该怎么做:

  1. 无需创建多个 docker-compose.yml 文件或不同的应用程序代码,即可创建 docker-compose 文件或构建容器化应用程序,使其根据主机平台 (windows|mac|linux) 略有不同?
  2. 无论主机操作系统如何,都以一致的方式访问主机 docker 守护进程?

如果重要的话,正在访问主机的 docker 守护进程的容器正在使用 docker python sdk 并在没有 TLS 的情况下通过 tcp 对 docker 进行 api 调用(这仅用于开发)。

更新解决方案详情

对于更多背景知识,有一个允许用户上传 zip 文件的 Web 应用程序 (aspnet core/C#)。除其他外,该 zip 文件包含一个导出的 docker 映像文件。在所有这些前面还有一个 nginx 容器,以允许 ssl 终止和负载平衡。 Web 应用程序拉出 docker 映像,然后使用 docker 守护进程的 http api,加载映像,重新标记映像,然后将其推送到私有 docker 存储库(该存储库在开发人员网络的某个位置运行,在 docker 外部)。之后,它将消息发布到消息队列,其中一个单独的 python 应用程序使用 python docker 库将 docker 映像部署到 docker swarm。

出于开发目的,应用程序都作为容器运行,因此需要与运行在主机上的 docker 作为独立的 swarm 节点进行交互。 SoftwareEngineer 的回答让我走上了正确的道路。我首先将主机中的 docker 套接字映射到 Web 应用程序容器中,但遇到了 .net 核心的限制,直到 .net 5 才能解决,即没有通过 unix 套接字执行 http 的干净方法。

我最终意识到 nginx 可以将代理 http 流量反向到 unix 套接字,从而解决了这个问题。我将所有容器(包括从 zip 中动态加载的 swarm 服务)设置为覆盖网络的一部分,以使它们能够相互访问,并允许我访问 http 端点以通过 http 控制主机的 docker/swarm 守护进程。

我遇到的最后一个障碍是 nginx 无法写入 /var/run/docker.sock 文件中的映射,因此我修改了 nginx.conf 以允许它在容器中以 root 身份运行。

【问题讨论】:

  • /var/run/docker.sock 映射到/var/run/docker.sock 在所有主机平台上都适用于我
  • Windows 没有任何 /var/run/docker.sock 的概念,除非有一些我不知道的新东西。
  • 几分钟前,我在 wsl2 (ubuntu) 中使用 docker-desktop 完成了这项工作,效果很好。我还使用标准的 windows cli (cmd) 进行了尝试,它也可以在那里工作。我想有一些你不知道的:)
  • 不幸的是,这些机器还不能访问 wsl2,该技术是否适用于 wsl(1)?
  • 另外,如果映射了 /var/run/docker.sock,那么 api 调用的 uri 会是什么样子?

标签: docker docker-compose


【解决方案1】:

据我所知,docker 套接字在所有系统的路径 /var/run/docker.sock 上都可用。我已经使用最近的 Linux 发行版 (Ubuntu)、运行 Docker for Windows (2.2.0) 的 Windows 10 Pro 以及 WSL2(Ubuntu 和 Alpine)以及 windows cmd (cli) 和 powershell 亲自验证了这一点。从内存来看,它也适用于 OSX,我曾经在 WSL1 中做同样的事情。

在任何带有-v--volume--mount 标志的终端上都可以将其映射到容器中。所以,

docker container run -v /var/run/docker.sock:/var/run/docker.sock

将套接字安装到容器内的相同路径中。这意味着您可以使用标准 docker 客户端 (docker) 从容器内访问套接字,而无需额外配置。建议在 Linux 容器中使用此路径,因为这是标准位置,并且可能不会让将来维护您的代码的任何人(包括您自己)感到困惑。

【讨论】:

  • 所以我在这方面取得了一些进展,但不幸的是遇到了一个很大的障碍。因为这只是映射套接字,我不能点击“http://:2375”来利用来自 C# 的 docker 的 http api,这是我最终需要做的:(
  • 我很想了解为什么 C# 对于你正在做的事情(或任何事情)来说都是一个坏主意,但你是否考虑过使用 bash 而只是使用码头工人客户端?并且,请阅读:stackoverflow.com/questions/37178824/…
  • 我们有一个 aspnetcore (c#) web api,可以将 zip 文件上传到它。 zip 中的内容之一是导出的 docker 映像。然后该图像被加载到主机上运行的 docker 实例,为我们的私有存储库重新标记,然后推送。之后,一条消息被放置在消息队列中,一个单独的 python 应用程序(也在容器中运行)使用该图像部署一个 docker swarm 服务。让这一切变得非常棘手的关键是它必须在没有连接到互联网的情况下 100% 离线运行。在 windows/mac 上运行良好。
  • 您可以试试https://<docker_host>:2375 uri,如果超时,请尝试使用 Unix 套接字 (unix:///var/run/docker.sock) 来代替?
  • 顺便说一句,我刚刚尝试从一个高山容器内卷曲 unix 套接字并且它工作(curl --unix-socket /var/run/docker.sock http:/containers/json),我尝试了 host.docker.internal dns 方法(@987654331 @) 来自 wsl2/ubuntu windows10-docker-desktop 并且也有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
  • 2017-06-06
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
相关资源
最近更新 更多