重启 Docker 容器后,容器的 IP 地址是否会改变?

5

我是docker的新手,一直在将我的应用程序docker化到单个服务器上。目前为止,一切都很好,也能正常工作。然而,有一件事我不太明白。我使用docker-compose来管理所有内容(尚未为我的项目创建dockerfile),在docker-compose中有一个ports属性。如果我这样写:

ports:
    8085:80

它将在0.0.0.0:8085上监听,这意味着外界可以访问我的服务器。经过一些讨论和谷歌搜索,我发现我可以使用docker桥接网络中的IP地址轻松进行端口映射:

ports:
    172.17.0.1:8085:80

这将仅在172.17.0.1:8085上监听,这很好,因为它只在内部监听并且我的nginx代理流量到必要的端口(例如proxy_pass http://172.17.0.1:8085)。了解更多关于docker和它们的工作方式后,我意识到所有这些容器都有自己的IP地址,只向这些地址公开端口。例如,我的一个“web”容器具有IPv4地址172.17.0.10,端口80已公开。如果我在其中一个容器上执行docker inspect,我将看到容器的IP地址。
现在,我想在我的nginx中使用这些IP地址。不是proxy_pass http://172.17.0.1:8085,我想做的是http://172.17.0.10。我个人认为这是一个更优雅的接口,但有一件事让我担心。如果我重新启动我的机器会发生什么?所有容器将以某种顺序启动。如果我有5个web容器,并且它们以随机顺序启动,我能确定这些容器的IP地址将是相同的吗?还是它们会改变?我应该始终在docker-compose中使用ports供nginx使用吗?如果是,如何使每个容器具有不同的IP而不是具有相同IP的不同端口?如果我创建另一个docker网络接口(假设在子网172.17.1.0中),并为公开的“public”端口分配来自该接口的不同IP,这样可以吗?这意味着在一个容器中使用172.17.1.1:80:80,在另一个容器中使用172.17.1.2:80:80等。
2个回答

6

虽然我不是docker-networking领域的专家,但我会尽力回答你的问题。

问:如果我重启我的机器,会发生什么?所有的容器会以某种顺序启动。
答:除非你使用linksdepends_on关键字,否则无法保证启动顺序。

问:如果我有5个Web容器并且它们以随机顺序启动,我可以确定这些容器的IP地址是相同的吗?
答:我在我的机器上进行了一些实验,记录了我的2个现有容器(PostgresDB和InfluxDB)的IP地址。

它们运行在

  1. Postgres: 172.17.0.2
  2. InfluxDB: 172.17.0.3

关闭再重新启动。可能由于它们以相同的顺序启动,IP地址似乎得到了维护。添加了depends_on关键字来强制InfluxDB容器先于Postgres启动,现在两个容器的IP地址为:

  1. Postgres: 172.17.0.3
  2. InfluxDB: 172.17.0.2

我认为IP是基于先到先服务的原则分配的。如果你没有指定容器启动顺序,我认为有一小部分机会,容器的IP地址可能不同。这真的取决于谁先运行。

问:我应该在docker-compose中始终使用端口供nginx使用吗?
答:是的,如果你想将一个nginx实例的端口转发到外部世界。否则,没有人能够访问该Web服务器。例如,暴露端口443以便让HTTPS流量通过。

问:如何使用不同的IP而不是相同IP的不同端口来运行容器?
答:我不知道是否可能,但是在docker-compose文档上进行了一些研究后,似乎可以使用ipam关键字实现。

参见:
https://docs.docker.com/compose/compose-file/#/ipam

对我来说看起来很可怕,所以我为自己的项目使用了service_name

示例:

container_bbb:
    image: banana

my_nginx:
    image: apple
    environment:
      - MOUNT_SRC0=http://container_bbb:80
      - MOUNT_DEST0=/
    links:
      - container_bbb

对于my_nginx容器中的此实例,服务名称container_bbb将被转换为该容器的主机名。 然后,我将有一个Python脚本,在容器的入口脚本区域使用此信息动态生成ngix配置。
听起来有点繁琐,但这使我能够更好地控制我的nginx。
因此,在我的/etc/nginx/conf.d/default-locations/中,配置将如下所示;
location /container_bbb/ {
    proxy_pass http://container_bbb:3000/;
}

注意: 我正在使用这个nginx服务器实例作为反向代理服务器。

我想说的是,你可以使用主机名而不是IP地址。要访问隔壁的容器,你可以传递http://CONTAINER_SERVICE_NAME:PORT


2

您不能依赖于容器的IP地址。如果所有服务都在同一个docker-compose配置文件中,则它们将自动成为同一内部网络的一部分,您只需使用服务名称作为主机名即可。

例如,如果您的Web应用程序命名为php,则您的nginx代理配置将类似于:

location / {
  proxy_pass  http://php;
  proxy_set_header Host $host;
  proxy_redirect     off;
}

(还要注意,您可能需要启用防火墙,以防端口映射泄漏到主机的公共IP地址。)

1
这是正确的答案,但是当 PHP 容器重新启动时,您将面临一个问题,它可能会使用不同的 IP 地址,而 Nginx 缓存了从 DNS 解析的 PHP IP 地址。 - Amr Ashraf
请参阅 https://serverfault.com/questions/722438/nginx-refresh-upstream-server-ip,了解有关Nginx选择更改主机名的信息。 - ron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接