我有几个像#/ p>一样运行的码头工人集装箱
由于Nginx需要连接Web应用程序1和2中的Web应用程序服务器,并且Web应用程序需要与postgresql对话,所以我有这样的链接
这在开始时效果很好,但是,当我开发新版本的Web应用程序1和Web应用程序2时,我需要替换它们。我所做的是删除Web应用程序容器,设置新容器并启动它们。
对于Web应用程序容器,它们的IP地址最初将类似于
在我更换它们之后,它们现在有了新的IP地址
此时,Nginx容器中的那些公开环境变量仍指向旧IP地址。这就出现了问题,如何在不破坏其他容器之间的连接的情况下更换容器?同样的问题也会发生在PostgreSQL上,如果我想升级PostgreSQL图像版本,我当然需要删除它并运行新版本,但后来我需要重建整个容器图,这对于真正的不是一个好主意生活服务器操作。
答案 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地址。
这里的教程=&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
选项。
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
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)。
除了容器被关闭而且因此别名无法访问时,多个容器也可以共享别名,在这种情况下,不能保证它将被解析为正确的别名。但在某些情况下,可能有助于无缝升级。
目前还没有很好的记录,只是通过阅读手册页难以弄明白。