【问题标题】:Using the host ip in docker-compose在 docker-compose 中使用主机 ip
【发布时间】:2015-05-17 15:14:00
【问题描述】:

我想创建一个能够在不同服务器上运行的 docker-compose 文件。

为此,我必须能够在 docker-compose.yml 的多个位置指定服务器的主机 IP 或主机名(所有容器都在其中运行)。

例如对于一个领事容器,我想在其中定义其他领事容器如何找到服务器。

consul:
  image: progrium/consul
  command: -server -advertise 192.168.1.125 -bootstrap

我显然不想硬编码 192.168.1.125。

我可以使用 env_file: 指定主机名或 ip 并在每台服务器上采用它,因此我将这些信息放在一个地方并在 docker-compose.yml 中使用。但这只能用于指定环境变量,不能用于广告参数。

有没有更好的解决方案?

【问题讨论】:

  • 目前这不是开箱即用的大量组合句柄。您可能可以在 Weave 上完成这项工作,但您也需要 Powerstrip,但这需要更多的工作。

标签: docker docker-compose


【解决方案1】:

创建一个脚本以在每次启动时在环境变量中设置您的主机 IP。

sudo vi /etc/profile.d/docker-external-ip.sh

然后在里面复制这段代码:

export EXTERNAL_IP=$(hostname -I | awk '{print $1}')

现在您可以在 docker-compose.yml 文件中使用它:

version: '3'
services:
  my_service:
    container_name: my-service
    image: my-service:latest
    environment:
    - EXTERNAL_IP=${EXTERNAL_IP}
    extra_hosts:
    - my.external-server.net:${EXTERNAL_IP}

    ...
  • environment --> 在你的 docker 中设置为系统环境变量 容器
  • extra_hosts --> 将这些主机添加到您的 docker 容器中

【讨论】:

  • export EXTERNAL_IP=$(hostname -I | awk '{print $1}') thsi 不提供外部 ip
【解决方案2】:

extra_hosts 有效,它被硬编码到docker-compose.yml 但对于我当前的静态设置,此刻我只需要这些。

version: '3'
services:
  my_service:
    container_name: my-service
    image: my-service:latest
    extra_hosts:
      - "myhostname:192.168.0.x"

    ...

    networks:
      - host
networks:
  host:

【讨论】:

  • 我使用您的解决方案制作了一个动态解决方案。我希望它能像你的静态一样修复到其他人。
  • 我的最新设置包括一个私有本地 DNS 绑定服务器。
【解决方案3】:

我使用的 docker 内部网络 IP 似乎是静态的:172.17.0.1

【讨论】:

  • 这对外部服务是不可见的,它们需要主机公共 ip 连接到容器的暴露端口。
  • 也为我工作。它是默认桥接网络的 IP:docs.docker.com/v17.09/engine/userguide/networking/…。但是 - 请记住,在生产环境中有更好的方法来解决这个问题......! :-)
【解决方案4】:

docker-compose 允许使用运行 compose 命令的环境中的环境变量。

请参阅https://docs.docker.com/compose/compose-file/#variable-substitution 上的文档

假设您可以创建一个包装脚本,就像@balver 建议的那样,您可以设置一个名为EXTERNAL_IP 的环境变量,其中将包含$(docker-machine ip) 的值。

例子:

#!/bin/sh
export EXTERNAL_IP=$(docker-machine ip)
exec docker-compose $@

# docker-compose.yml
version: "2"
services:
  consul:
    image: consul
    environment:
      - "EXTERNAL_IP=${EXTERNAL_IP}"
    command: agent -server -advertise ${EXTERNAL_IP} -bootstrap

不幸的是,如果您使用随机端口分配,则无法添加EXTERNAL_PORT,因此端口必须静态链接。

PS:在 HashiCorp Nomad 中默认启用了非常相似的功能,还包括映射端口。文档:https://www.nomadproject.io/docs/jobspec/interpreted.html#interpreted_env_vars

【讨论】:

  • 在默认的 docker 配置中有一个 NO_PROXY 环境变量已经包含了 docker-machine ip 并且可以在 docker-compose.yaml 中使用
  • 如果你正在运行一个 docker swarm,你可以通过以下方式获取节点地址:docker system info -f "{{.Swarm.NodeAddr}}"
  • 从正在运行的容器中?
【解决方案5】:

使用新版本的 Docker Compose (1.4.0),您应该能够执行以下操作:

docker-compose.yml

consul:
  image: progrium/consul
  command: -server -advertise HOSTIP -bootstrap

重击

$ sed -e "s/HOSTIP/${HOSTIP}/g" docker-compose.yml | docker-compose --file - up

这要归功于新功能:

  • Compose 现在可以通过将 - 指定为文件名,从标准输入而不是从文件中读取 YAML 配置。这使得动态生成配置变得更加容易:

    $ echo 'redis: {"image": "redis"}' | docker-compose --file - up
    

【讨论】:

  • 从 docker-machine 中检索 ip 并作为单行执行 - sed -e "s/HOSTIP/$(docker-machine ip your-machine-name)/g" docker-compose.yml | docker-compose --file - up
  • 仅限Linux,您可以sed -e "s/HOSTIP/$(hostname --ip-address)/g" docker-compose.yml | docker-compose --file - up
【解决方案6】:

环境变量,如之前的解决方案中所建议的,是在容器链接时由 Docker 创建的。但是如果容器重新启动,环境变量不会自动更新。所以,不建议在生产环境中使用环境变量。

Docker 除了创建环境变量外,还会更新 /etc/hosts 文件中的主机条目。事实上,Docker 文档建议使用来自 etc/hosts 的主机条目而不是环境变量。

参考:https://docs.docker.com/userguide/dockerlinks/

与 /etc/hosts 文件中的主机条目不同,如果源容器重新启动,存储在环境变量中的 IP 地址不会自动更新。我们建议使用 /etc/hosts 中的主机条目来解析链接容器的 IP 地址。

【讨论】:

  • 这个答案值得更多关注
  • 这个答案是对的,但是,它并没有为所提出的问题提供任何解决方案——如何在 docker-compose 中使用主机 IP?
【解决方案7】:

有没有更好的解决方案?

绝对!容器之间的通信根本不需要主机 ip。如果您在 docker-compose.yaml 文件中使用 link 容器,您将可以访问许多环境变量,您可以使用这些变量来发现服务的 IP 地址。

例如,考虑一个带有两个容器的 docker-compose 配置:一个使用 consul,另一个运行一些需要与 consul 对话的服务。

consul:
  image: progrium/consul
  command: -server -bootstrap
webserver:
  image: larsks/mini-httpd
  links:
    - consul

首先,以-server -bootstrap 开头consulconsul 算出它自己的广告地址,例如:

consul_1    | ==> Consul agent running!
consul_1    |          Node name: 'f39ba7ef38ef'
consul_1    |         Datacenter: 'dc1'
consul_1    |             Server: true (bootstrap: true)
consul_1    |        Client Addr: 0.0.0.0 (HTTP: 8500, HTTPS: -1, DNS: 53, RPC: 8400)
consul_1    |       Cluster Addr: 172.17.0.4 (LAN: 8301, WAN: 8302)
consul_1    |     Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false
consul_1    |              Atlas: <disabled>

webserver 容器中,我们发现以下可用于 pid 1 的环境变量:

CONSUL_PORT=udp://172.17.0.4:53
CONSUL_PORT_8300_TCP_START=tcp://172.17.0.4:8300
CONSUL_PORT_8300_TCP_ADDR=172.17.0.4
CONSUL_PORT_8300_TCP_PROTO=tcp
CONSUL_PORT_8300_TCP_PORT_START=8300
CONSUL_PORT_8300_UDP_END=udp://172.17.0.4:8302
CONSUL_PORT_8300_UDP_PORT_END=8302
CONSUL_PORT_53_UDP=udp://172.17.0.4:53
CONSUL_PORT_53_UDP_ADDR=172.17.0.4
CONSUL_PORT_53_UDP_PORT=53
CONSUL_PORT_53_UDP_PROTO=udp
CONSUL_PORT_8300_TCP=tcp://172.17.0.4:8300
CONSUL_PORT_8300_TCP_PORT=8300
CONSUL_PORT_8301_TCP=tcp://172.17.0.4:8301
CONSUL_PORT_8301_TCP_ADDR=172.17.0.4
CONSUL_PORT_8301_TCP_PORT=8301
CONSUL_PORT_8301_TCP_PROTO=tcp
CONSUL_PORT_8301_UDP=udp://172.17.0.4:8301
CONSUL_PORT_8301_UDP_ADDR=172.17.0.4
CONSUL_PORT_8301_UDP_PORT=8301
CONSUL_PORT_8301_UDP_PROTO=udp
CONSUL_PORT_8302_TCP=tcp://172.17.0.4:8302
CONSUL_PORT_8302_TCP_ADDR=172.17.0.4
CONSUL_PORT_8302_TCP_PORT=8302
CONSUL_PORT_8302_TCP_PROTO=tcp
CONSUL_PORT_8302_UDP=udp://172.17.0.4:8302
CONSUL_PORT_8302_UDP_ADDR=172.17.0.4
CONSUL_PORT_8302_UDP_PORT=8302
CONSUL_PORT_8302_UDP_PROTO=udp
CONSUL_PORT_8400_TCP=tcp://172.17.0.4:8400
CONSUL_PORT_8400_TCP_ADDR=172.17.0.4
CONSUL_PORT_8400_TCP_PORT=8400
CONSUL_PORT_8400_TCP_PROTO=tcp
CONSUL_PORT_8500_TCP=tcp://172.17.0.4:8500
CONSUL_PORT_8500_TCP_ADDR=172.17.0.4
CONSUL_PORT_8500_TCP_PORT=8500
CONSUL_PORT_8500_TCP_PROTO=tcp

consul为每个端口EXPOSEd 有一组变量 图片。例如,在第二张图片中,我们可以通过以下连接与 consul REST API 进行交互:

http://${CONSUL_PORT_8500_TCP_ADDR}:8500/

【讨论】:

  • 我没有离开-1,但是从他将其用于名为--advertise的命令行选项我猜该进程正在通过某种其他协议向机器报告它的地址或不在 docker 中的客户。所以它需要知道它的外部 ip 是什么(即 docker 主机),否则它会报告 docker 分配给它的一个。因此,您发布的“这就是链接的工作方式”完全忽略了这个问题,因为这些 ip 在 docker 容器之外不可见。
  • 以及如何使用external_linksextra_hosts从Docker连接到机器主机服务?例如,我在主机上运行了 Postfix,但我想从 Docker 容器连接到 Postfix 服务而不启动另一个 Docker 容器...
  • 一个 docker 容器总是可以使用 docker 桥的地址联系宿主机上的服务。这将是容器内的默认网关地址。
  • 本方案对示例情况进行了梳理,但没有回答使用docker-compose将docker主机IP提供给容器环境的问题。
  • 呃!我的环境变量似乎解析为空字符串:(http://${AUTOSERVICE_PORT_8097_TCP_ADDR}:8097/path/v1/给我:http://:8097/path/v1/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多