简体   繁体   English

在 docker-compose 中使用主机 ip

[英]Using the host ip in docker-compose

I want to create a docker-compose file that is able to run on different servers.我想创建一个能够在不同服务器上运行的docker-compose文件。

For that I have to be able to specify the host-ip or hostname of the server (where all the containers are running) in several places in the docker-compose.yml .为此,我必须能够在docker-compose.yml 的多个位置指定服务器的主机 IP 或主机名(所有容器都在其中运行)。

Eg for a consul container where I want to define how the server can be found by fellow consul containers.例如,对于 consul 容器,我想定义其他 consul 容器如何找到服务器。

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

I don't want to hardcode 192.168.1.125 obviously.我不想硬编码 192.168.1.125 显然。

I could use env_file : to specify the hostname or ip and adopt it on every server, so I have that information in one place and use that in docker-compose.yml.我可以使用env_file :指定主机名或 ip 并在每台服务器上采用它,因此我将这些信息放在一个地方并在 docker-compose.yml 中使用它。 But this can only be used to specifiy environment variables and not for the advertise parameter.但这只能用于指定环境变量,而不能用于广告参数。

Is there a better solution?有更好的解决方案吗?

docker-compose allows to use environment variables from the environment running the compose command. docker-compose 允许使用来自运行 compose 命令的环境中的环境变量。

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

Assuming you can create a wrapper script, like @balver suggested, you can set an environment variable called EXTERNAL_IP that will include the value of $(docker-machine ip) .假设您可以创建一个包装器脚本,就像@balver 建议的那样,您可以设置一个名为EXTERNAL_IP的环境变量,该变量将包含$(docker-machine ip)

Example:例子:

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

and

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

Unfortunately if you are using random port assignment, there is no way to add EXTERNAL_PORT , so the ports must be linked statically.不幸的是,如果您使用随机端口分配,则无法添加EXTERNAL_PORT ,因此端口必须静态链接。

PS: Something very similar is enabled by default in HashiCorp Nomad, also includes mapped ports. PS:默认情况下,HashiCorp Nomad 中启用了非常相似的功能,还包括映射端口。 Doc: https://www.nomadproject.io/docs/jobspec/interpreted.html#interpreted_env_vars文档: https : //www.nomadproject.io/docs/jobspec/interpreted.html#interpreted_env_vars

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

Is there a better solution?有更好的解决方案吗?

Absolutely!绝对地! You don't need the host ip at all for communication between containers.容器之间的通信根本不需要主机 ip。 If you link containers in your docker-compose.yaml file, you will have access to a number of environment variables that you can use to discover the ip addresses of your services.如果您在docker-compose.yaml文件中link容器,您将可以访问许多可用于发现服务 IP 地址的环境变量。

Consider, for example, a docker-compose configuration with two containers: one using consul , and one running some service that needs to talk to consul.例如,考虑一个带有两个容器的 docker-compose 配置:一个使用consul ,另一个运行一些需要与 consul 对话的服务。

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

First, by starting consul with just -server -bootstrap , consul figures out it's own advertise address, for example:首先,通过仅使用-server -bootstrap启动consulconsul -server -bootstrap算出它自己的广告地址,例如:

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>

In the webserver container, we find the following environment variables available to pid 1: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

There is a set of variables for each port EXPOSE d by the consul image. consul镜像的每个端口EXPOSE d 都有一组变量。 For example, in that second image, we could interact with the consul REST API by connecting to:例如,在第二张图片中,我们可以通过连接到以下内容与 consul REST API 进行交互:

http://${CONSUL_PORT_8500_TCP_ADDR}:8500/

With the new version of Docker Compose ( 1.4.0 ) you should be able to do something like this:使用新版本的 Docker Compose ( 1.4.0 ),您应该能够执行以下操作:

docker-compose.yml docker-compose.yml

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

bash猛击

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

This is thanks to the new feature:这要归功于新功能:

  • Compose can now read YAML configuration from standard input, rather than from a file, by specifying - as the filename.通过指定 - 作为文件名,Compose 现在可以从标准输入而不是从文件中读取 YAML 配置。 This makes it easier to generate configuration dynamically:这使得动态生成配置变得更容易:

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

Environment variables, as suggested in the earlier solution, are created by Docker when containers are linked.正如之前的解决方案中所建议的,环境变量是在链接容器时由 Docker 创建的。 But the env vars are not automatically updated if the container is restarted.但是如果容器重新启动,环境变量不会自动更新。 So, it is not recommended to use environment variables in production.因此,不建议在生产中使用环境变量。

Docker, in addition to creating the environment variables, also updates the host entries in /etc/hosts file. Docker 除了创建环境变量外,还会更新 /etc/hosts 文件中的主机条目。 In fact, Docker documentation recommends using the host entries from etc/hosts instead of the environment variables.事实上,Docker 文档建议使用 etc/hosts 中的主机条目而不是环境变量。

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

Unlike host entries in the /etc/hosts file, IP addresses stored in the environment variables are not automatically updated if the source container is restarted.与 /etc/hosts 文件中的主机条目不同,如果源容器重新启动,则存储在环境变量中的 IP 地址不会自动更新。 We recommend using the host entries in /etc/hosts to resolve the IP address of linked containers.我们建议使用 /etc/hosts 中的主机条目来解析链接容器的 IP 地址。

extra_hosts works, it's hard coded into docker-compose.yml but for my current static setup, at this moment that's all I need. 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:

Create a script to set, every boot, your host IP in an environment variable.创建脚本以在每次启动时在环境变量中设置您的主机 IP。

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

Then copy inside this code:然后在此代码中复制:

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

Now you can use it in your docker-compose.yml file:现在你可以在你的 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 --> to set as system environment var in your docker container环境 --> 在你的 docker 容器中设置为系统环境变量
  • extra_hosts --> to add these hosts to your docker container extra_hosts --> 将这些主机添加到您的 docker 容器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM