如何设置docker容器之间的链接,以便重新启动不会破坏它?

时间:2014-06-16 21:33:42

标签: deployment docker

我有几个像#/ p>一样运行的码头工人集装箱

  • Nginx的
  • 网络应用1
  • 网络应用2
  • 的PostgreSQL

由于Nginx需要连接Web应用程序1和2中的Web应用程序服务器,并且Web应用程序需要与postgresql对话,所以我有这样的链接

  • Nginx ---链接--->网络应用1
  • Nginx ---链接--->网络应用2
  • 网络应用1 ---链接--->的PostgreSQL
  • 网络应用2 ---链接--->的PostgreSQL

这在开始时效果很好,但是,当我开发新版本的Web应用程序1和Web应用程序2时,我需要替换它们。我所做的是删除Web应用程序容器,设置新容器并启动它们。

对于Web应用程序容器,它们的IP地址最初将类似于

  • 172.17.0.2
  • 172.17.0.3

在我更换它们之后,它们现在有了新的IP地址

  • 172.17.0.5
  • 172.17.0.6

此时,Nginx容器中的那些公开环境变量仍指向旧IP地址。这就出现了问题,如何在不破坏其他容器之间的连接的情况下更换容器?同样的问题也会发生在PostgreSQL上,如果我想升级PostgreSQL图像版本,我当然需要删除它并运行新版本,但后来我需要重建整个容器图,这对于真正的不是一个好主意生活服务器操作。

11 个答案:

答案 0 :(得分:53)

--link的效果是静态的,因此它不适用于您的方案(目前没有重新链接,尽管您可以remove links)。

我们一直在dockerize.it上使用两种不同的方法来解决这个问题,没有链接或大使(虽然你也可以添加大使)。

1)使用动态DNS

一般的想法是,您为数据库(或任何其他服务)指定一个名称,并在启动和停止容器时使用实际IP更新短期DNS服务器。

我们从SkyDock开始。它适用于两个docker容器,DNS服务器和一个自动更新的监视器。之后,我们使用Consul(也使用dockerized版本:docker-consul)转移到更自定义的内容。

这个(我们还没有尝试过)的演变是设置etcd或类似的,并使用其自定义API来学习IP和端口。该软件也应该支持动态重新配置。

2)使用docker bridge ip

当暴露容器端口时,您可以将它们绑定到docker0网桥,该网桥具有(或可以拥有)众所周知的地址。

使用新版本替换容器时,只需让新容器在同一IP上发布相同的端口。

这更简单但也更有限。如果你运行类似的软件可能会有端口冲突(例如,两个容器无法监听docker0网桥上的3306端口),等等...所以我们当前最喜欢的是选项1.

答案 1 :(得分:20)

链接适用于特定容器,而不是基于容器的名称。因此,当您移除容器时,链接将断开连接,新容器(即使具有相同名称)也不会自动取代。

新的网络功能允许您通过连接到容器 他们的名字,所以如果你创建一个新的网络,任何连接到的容器 该网络可以通过其名称到达其他容器。例如:

1)创建新网络

$ docker network create <network-name>       

2)将容器连接到网络

$ docker run --net=<network-name> ...

$ docker network connect <network-name> <container-name>

3)按名称Ping容器

docker exec -ti <container-name-A> ping <container-name-B> 

64 bytes from c1 (172.18.0.4): icmp_seq=1 ttl=64 time=0.137 ms
64 bytes from c1 (172.18.0.4): icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from c1 (172.18.0.4): icmp_seq=3 ttl=64 time=0.074 ms
64 bytes from c1 (172.18.0.4): icmp_seq=4 ttl=64 time=0.074 ms

请参阅文档的this部分;

注意:与旧版links不同,新网络不会创建环境变量,也不会与其他容器共享环境变量。

此功能目前不支持别名

答案 2 :(得分:10)

您可以使用ambassador container。但是不要将大使容器链接到您的客户端,因为这会产生与上面相同的问题。而是使用docker主机上的ambassador容器的公开端口(通常为172.17.42.1)。例如:

postgres卷:

$ docker run --name PGDATA -v /data/pgdata/data:/data -v /data/pgdata/log:/var/log/postgresql phusion/baseimage:0.9.10 true

postgres的容器:

$ docker run -d --name postgres --volumes-from PGDATA -e USER=postgres -e PASS='postgres' paintedfox/postgresql
postgres的大使容器:

$ docker run -d --name pg_ambassador --link postgres:postgres -p 5432:5432 ctlc/ambassador

现在你可以启动一个postgresql客户端容器而无需链接大使容器并访问网关主机上的postgresql(通常是172.17.42.1):

$ docker run --rm -t -i paintedfox/postgresql /bin/bash
root@b94251eac8be:/# PGHOST=$(netstat -nr | grep '^0\.0\.0\.0 ' | awk '{print $2}')
root@b94251eac8be:/# echo $PGHOST
172.17.42.1
root@b94251eac8be:/#
root@b94251eac8be:/# psql -h $PGHOST --user postgres
Password for user postgres: 
psql (9.3.4)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

postgres=#
postgres=# select 6*7 as answer;
 answer 
--------
     42
(1 row)

bpostgres=# 

现在您可以重新启动大使容器,而无需重新启动客户端。

答案 3 :(得分:2)

如果有人仍然好奇,你必须使用每个docker容器的/ etc / hosts文件中的主机条目,不应该依赖于ENV变量,因为它们不会自动更新。

每个链接容器都有一个主机文件条目,格式为LINKEDCONTAINERNAME_PORT_PORTNUMBER_TCP等。

以下内容来自docker docs

  

关于Docker环境变量的重要说明

     

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

     

这些环境变量仅为第一个进程设置   容器。某些守护进程(如sshd)会在产卵时擦洗它们   用于连接的外壳。

答案 4 :(得分:2)

这包含在3周前docker的实验版本中,并引入了服务:https://github.com/docker/docker/blob/master/experimental/networking.md

您应该能够通过运行带有--publish-service <name>参数的docker容器来获取动态链接。该名称可通过DNS访问。这在容器重启时是持久的(只要你重新启动具有相同服务名称的容器)

答案 5 :(得分:1)

您可以使用dockerlinks名称来解决此问题。

最基本的设置是首先创建一个名为的数据库容器:

$ sudo docker run -d --name db training/postgres

然后创建一个连接到db:

的Web容器
$ sudo docker run -d -P --name web --link db:db training/webapp python app.py

使用此功能,您无需手动将容器与其IP地址连接。

答案 6 :(得分:1)

使用OpenSVC方法,您可以通过以下方式解决:

  • 使用具有自己的IP地址/ DNS名称的服务(最终用户将连接到的服务)
  • 告诉docker将端口暴露给此特定IP地址(&#34; - ip&#34; docker option)
  • 配置您的应用以连接到服务IP地址

每次更换容器时,您都确定它将连接到正确的IP地址。

这里的教程=&gt; Docker Multi Containers with OpenSVC

不要错过&#34;复杂的编排&#34;部分在tuto的末尾,它可以帮助您以正确的顺序启动/停止容器(1个postgresql子集+ 1个webapp子集+ 1个nginx子集)

主要缺点是您将webapp和PostgreSQL端口公开到公共地址,实际上只需要公开公开nginx tcp端口。

答案 7 :(得分:1)

你也可以尝试使用中间容器的大使方法来保持链接的完整性......(参见https://docs.docker.com/articles/ambassador_pattern_linking/)了解更多信息

答案 8 :(得分:0)

您可以将图像的连接端口绑定到主机上的固定端口,并配置服务以使用它们。

这也有它的缺点,但它可能适用于你的情况。

答案 9 :(得分:0)

另一种方法是使用--net container:$CONTAINER_ID选项。

第1步:创建&#34;网络&#34;容器

docker run --name db_net ubuntu:14.04 sleep infinity
docker run --name app1_net --link db_net:db ubuntu:14.04 sleep infinity
docker run --name app2_net --link db_net:db ubuntu:14.04 sleep infinity
docker run -p 80 -p 443 --name nginx_net --link app1_net:app1 --link app2_net:app2 ubuntu:14.04 sleep infinity

第2步:将服务注入&#34;网络&#34;容器

docker run --name db --net container:db_net pgsql
docker run --name app1 --net container:app1_net app1
docker run --name app2 --net container:app1_net app2
docker run --name nginx --net container:app1_net nginx

只要您不触及&#34;网络&#34;容器,链接的IP地址不应更改。

答案 10 :(得分:0)

Network-scoped alias就是这种情况所需要的。这是一个相当新的功能,可用于“发布”为整个网络提供服务的容器,而不像只能从一个容器访问的链接别名。

它不会在容器之间添加任何类型的依赖关系 - 只要两者都在运行,它们就可以进行通信,无论重启和替换以及启动顺序如何。我认为它在内部使用DNS而不是/ etc / hosts

使用它:docker run --net=some_user_definied_nw --net-alias postgres ...,您可以使用同一网络上任何容器中的别名连接到它。

不适用于默认网络,遗憾的是,您必须使用docker network create <network>创建一个,然后将其与--net=<network>一起用于每个容器(compose supports it as well)。

除了容器被关闭而且因此别名无法访问时,多个容器也可以共享别名,在这种情况下,不能保证它将被解析为正确的别名。但在某些情况下,可能有助于无缝升级。

目前还没有很好的记录,只是通过阅读手册页难以弄明白。