在docker-compose中使用主机ip

chr*_*ian 62 docker docker-compose

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

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

例如,对于一个consul容器,我想要定义其他领事容器如何找到服务器.

consul:
  image: progrium/consul
  command: -server -advertise 192.168.1.125 -bootstrap
Run Code Online (Sandbox Code Playgroud)

我不想显然硬编码192.168.1.125.

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

有更好的解决方案吗?

Evg*_*eny 19

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 $@
Run Code Online (Sandbox Code Playgroud)

# docker-compose.yml
version: "2"
services:
  consul:
    image: consul
    environment:
      - "EXTERNAL_IP=${EXTERNAL_IP}"
    command: agent -server -advertise ${EXTERNAL_IP} -bootstrap
Run Code Online (Sandbox Code Playgroud)

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

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

  • 在默认的docker config中有一个'NO_PROXY`环境变量已经包含docker-machine ip,它可以在`docker-compose.yaml`中使用 (2认同)

lar*_*sks 17

有更好的解决方案吗?

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

例如,考虑一个包含两个容器的docker-compose配置:一个使用consul,一个运行一些需要与consul交谈的服务.

consul:
  image: progrium/consul
  command: -server -bootstrap
webserver:
  image: larsks/mini-httpd
  links:
    - consul
Run Code Online (Sandbox Code Playgroud)

首先,从consuljust 开始-server -bootstrap,consul计算出它自己的广告地址,例如:

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>
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

图像的每个端口EXPOSEd 都有一组变量consul.例如,在第二个图像中,我们可以通过连接到以下内容与consul REST API进行交互:

http://${CONSUL_PORT_8500_TCP_ADDR}:8500/
Run Code Online (Sandbox Code Playgroud)

  • 我没有离开`-1`但是从他使用这个名为`--advertise`的命令行选项我猜这个过程是通过其他类型的协议向某个地方报告它的地址到不在docker中的机器或客户端.所以它需要知道它的外部ip是什么(即docker host one),否则它将报告一个docker分配给它.因此,您发布的"这就是链接的工作方式"完全错过了这个问题,因为这些ips在docker容器之外是不可见的. (19认同)
  • 以及如何使用 `external_links` 或 `extra_hosts` 从 Docker 连接到机器主机服务?例如,我在主机上运行 Postfix,但我想从 Docker 容器连接到 Postfix 服务,而无需启动另一个 docker 容器... (2认同)

小智 14

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

泊坞窗,compose.yml

consul:
  image: progrium/consul
  command: -server -advertise HOSTIP -bootstrap
Run Code Online (Sandbox Code Playgroud)

庆典

$ sed -e "s/HOSTIP/${HOSTIP}/g" docker-compose.yml | docker-compose --file - up
Run Code Online (Sandbox Code Playgroud)

这要归功于新功能:

  • Compose现在可以通过指定 - 作为文件名,从标准输入而不是从文件读取YAML配置.这样可以更轻松地动态生成配置:

    $ echo 'redis: {"image": "redis"}' | docker-compose --file - up
    
    Run Code Online (Sandbox Code Playgroud)


use*_*619 13

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

  • 这对外部服务是不可见的,它们需要主机公共ip连接到容器的暴露端口. (5认同)

Ana*_*and 7

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

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

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

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

  • 这个答案是正确的,但是,它没有为被问到的问题提供任何解决方案 - 如何在docker-compose中使用主机IP? (7认同)