在docker-compose中使用主机ip


70

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

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

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

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

我显然不想对192.168.1.125进行硬编码。

我可以使用 env_file指定主机名或IP,并通过它的每一个服务器上,所以我必须在一个地方的信息和使用,在泊坞窗,compose.yml。但这只能用于指定环境变量,而不能用于advertise参数。

有更好的解决方案吗?


目前,这还不算是开箱即用的东西。您可能可以在Weave上进行此工作,但是您还将需要Powerstrip,但这将需要更多工作。
errordeveloper

Answers:


21

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中启用了非常相似的功能,还包括映射的端口。Doc:https : //www.nomadproject.io/docs/jobspec/interpreted.html#interpreted_env_vars


2
在默认的docker config中,有一个NO_PROXY已经包含docker-machine ip的环境变量,可以在docker-compose.yaml
daggett

如果您正在运行docker system info -f "{{.Swarm.NodeAddr}}"
docker

从正在运行的容器内部?
Evgeny

16

有更好的解决方案吗?

绝对!容器之间的通讯完全不需要主机ip。如果将link容器包含在docker-compose.yaml文件中,则可以访问许多环境变量,可用于发现服务的ip地址。

例如,考虑具有两个容器的docker-compose配置:一个使用consul,另一个运行需要与领事交谈的服务。

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

首先,从consuljust开头-server -bootstrapconsul找出它自己的广告地址,例如:

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

映像的每个端口EXPOSEd都有一组变量consul。例如,在第二张图中,我们可以通过连接到以下命令来与领事REST API进行交互:

http://${CONSUL_PORT_8500_TCP_ADDR}:8500/

20
我没有离开过,-1而是从他使用它作为命令行选项,--advertise我猜测该进程正在通过某种其他协议将其地址报告给不在docker中的机器或客户端。因此,它需要知道外部ip是什么(即docker主机之一),否则它将报告一个docker分配给它的IP。因此,您发布的“这是链接的工作方式”一文完全漏掉了这个问题,因为这些ip在docker容器外部不可见。
罗布·坎农

2
以及如何使用external_linksextra_hosts从Docker连接到机器主机服务?例如,我在主机上运行了Postfix,但是我想从Docker容器连接到Postfix服务,而无需启动另一个Docker容器...
–danger89

1
泊坞窗容器始终可以使用泊坞桥的地址联系主机上的服务。这将是容器内的默认网关地址。
larsks 2013年

1
该解决方案梳理了示例情况,但没有回答使用docker-compose为容器环境提供docker主机IP的问题。
villasv '18

啊! 我的环境变量似乎解析为空字符串:(http://${AUTOSERVICE_PORT_8097_TCP_ADDR}:8097/path/v1/给我:http://:8097/path/v1/
cs94njw


14

使用新版本的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
Ian Wootten

仅从Linux,您可以sed -e "s/HOSTIP/$(hostname --ip-address)/g" docker-compose.yml | docker-compose --file - up
jnovack

6

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

Docker除了创建环境变量外,还更新/ etc / hosts文件中的主机条目。实际上,Docker文档建议使用etc / hosts中的主机条目代替环境变量。

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

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


此答案值得更多
关注-dangra

8
这个答案是正确的,但是,它并没有为所提出的问题提供任何解决方案-如何在docker-compose中使用主机IP?
吉万,2016年

1

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:
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.