简体   繁体   English

如何在Docker容器之间建立链接,以便重新启动不会破坏它?

[英]How do I set up linkage between Docker containers so that restarting won't break it?

I have a few Docker containers running like: 我有几个Docker容器运行如下:

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

Since Nginx needs to connect to the web application servers inside web app 1 and 2, and the web apps need to talk to PostgreSQL, I have linkages like this: 由于Nginx需要连接到Web应用程序1和2中的Web应用程序服务器,并且Web应用程序需要与PostgreSQL交谈,我有这样的链接:

  • Nginx --- link ---> Web app 1 Nginx ---链接---> Web应用程序1
  • Nginx --- link ---> Web app 2 Nginx ---链接---> Web应用程序2
  • Web app 1 --- link ---> PostgreSQL Web应用程序1 ---链接---> PostgreSQL
  • Web app 2 --- link ---> PostgreSQL Web应用程序2 ---链接---> PostgreSQL

This works pretty well at first. 这起初效果很好。 However, when I develop a new version of web app 1 and web app 2, I need to replace them. 但是,当我开发新版本的Web应用程序1和Web应用程序2时,我需要替换它们。 What I do is remove the web app containers, set up new containers and start them. 我所做的是删除Web应用程序容器,设置新容器并启动它们。

For the web app containers, their IP addresses at first would be something like: 对于Web应用程序容器,它们的IP地址最初类似于:

  • 172.17.0.2 172.17.0.2
  • 172.17.0.3 172.17.0.3

And after I replace them, they will have new IP addresses: 在我更换它们之后,它们将拥有新的IP地址:

  • 172.17.0.5 172.17.0.5
  • 172.17.0.6 172.17.0.6

Now, those exposed environment variables in the Nginx container are still pointing to the old IP addresses. 现在,Nginx容器中的那些公开的环境变量仍然指向旧的IP地址。 Here comes the problem. 这就是问题所在。 How do I replace a container without breaking linkage between containers? 如何在不破坏容器之间的连接的情况下更换容器? The same issue will also happen to PostgreSQL. PostgreSQL也会出现同样的问题。 If I want to upgrade the PostgreSQL image version, I certainly need to remove it and run the new one, but then I need to rebuild the whole container graph, so this is not ideal for real-life server operation. 如果我想升级PostgreSQL映像版本,我当然需要删除它并运行新的映像版本,但是我需要重建整个容器图,所以这对于真实的服务器操作来说并不理想。

The effect of --link is static, so it will not work for your scenario (there is currently no re-linking, although you can remove links ). --link的效果是静态的,因此它不适用于您的场景(虽然您可以删除链接 ,但目前没有重新链接 )。

We have been using two different approaches at dockerize.it to solve this, without links or ambassadors (although you could add ambassadors too). 我们一直在dockerize.it上使用两种不同的方法来解决这个问题,没有链接或大使(尽管你也可以添加大使)。

1) Use dynamic DNS 1)使用动态DNS

The general idea is that you specify a single name for your database (or any other service) and update a short-lived DNS server with the actual IP as you start and stop containers. 一般的想法是,您为数据库(或任何其他服务)指定单个名称,并在启动和停止容器时使用实际IP更新短期DNS服务器。

We started with SkyDock . 我们从SkyDock开始。 It works with two docker containers, the DNS server and a monitor that keeps it updated automatically. 它适用于两个docker容器,DNS服务器和一个自动更新的监视器。 Later we moved to something more custom using Consul (also using a dockerized version: docker-consul ). 后来我们使用Consul (也使用了一个dockerized版本:docker -consul )转向了一些更自定义的东西。

An evolution of this (which we haven't tried) would be to setup etcd or similar and use its custom API to learn the IPs and ports. 这个(我们还没有尝试过)的演变是设置etcd或类似的,并使用其自定义API来学习IP和端口。 The software should support dynamic reconfiguration too. 该软件也应该支持动态重新配置。

2) Use the docker bridge ip 2)使用docker bridge ip

When exposing the container ports you can just bind them to the docker0 bridge, which has (or can have) a well known address. 暴露容器端口时,您只需将它们绑定到docker0网桥,该网桥具有(或可以拥有)众所周知的地址。

When replacing a container with a new version, just make the new container publish the same port on the same IP. 使用新版本替换容器时,只需使新容器在同一IP上发布相同的端口即可。

This is simpler but also more limited. 这更简单但也更有限。 You might have port conflicts if you run similar software (for instance, two containers can not listen on the 3306 port on the docker0 bridge), etcétera… so our current favorite is option 1. 如果你运行类似的软件可能会有端口冲突(例如,两个容器无法监听docker0网桥上的3306端口),等等...所以我们当前最喜欢的是选项1。

Links are for a specific container, not based on the name of a container. 链接用于特定容器,而不是基于容器的名称。 So the moment you remove a container, the link is disconnected and the new container (even with the same name) will not automatically take its place. 因此,当您删除容器时,链接将断开连接,新容器(即使具有相同名称)也不会自动取代它。

The new networking feature allows you to connect to containers by their name, so if you create a new network, any container connected to that network can reach other containers by their name. 新的网络功能允许您按名称连接到容器,因此,如果您创建新网络,则连接到该网络的任何容器都可以通过其名称访问其他容器。 Example: 例:

1) Create new network 1)创建新网络

$ docker network create <network-name>       

2) Connect containers to network 2)将容器连接到网络

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

or 要么

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

3) Ping container by 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

See this section of the documentation; 请参阅文档的部分;

Note: Unlike legacy links the new networking will not create environment variables, nor share environment variables with other containers. 注意:与旧links不同,新网络不会创建环境变量,也不会与其他容器共享环境变量。

This feature currently doesn't support aliases 此功能目前不支持别名

You can use an ambassador container . 您可以使用大使容器 But do not link the ambassador container to your client, since this creates the same problem as above. 但是不要将大使容器链接到您的客户端,因为这会产生与上面相同的问题。 Instead, use the exposed port of the ambassador container on the docker host (typically 172.17.42.1). 而是使用docker主机上的ambassador容器的公开端口(通常为172.17.42.1)。 Example: 例:

postgres volume: postgres卷:

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

postgres-container: Postgres的容器:

$ docker run -d --name postgres --volumes-from PGDATA -e USER=postgres -e PASS='postgres' paintedfox/postgresql

ambassador-container for postgres: postgres的大使容器:

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

Now you can start a postgresql client container without linking the ambassador container and access postgresql on the gateway host (typically 172.17.42.1): 现在,您可以启动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=# 

Now you can restart the ambassador container whithout having to restart the client. 现在您可以重新启动大使容器,而无需重新启动客户端。

If anyone is still curious, you have to use the host entries in /etc/hosts file of each docker container and should not depend on ENV variables as they are not updated automatically. 如果有人仍然好奇,你必须使用每个docker容器的/ etc / hosts文件中的主机条目,不应该依赖于ENV变量,因为它们不会自动更新。

There will be a host file entry for each of the linked container in the format LINKEDCONTAINERNAME_PORT_PORTNUMBER_TCP etc.. 每个链接容器都有一个主机文件条目,格式为LINKEDCONTAINERNAME_PORT_PORTNUMBER_TCP等。

The following is from docker docs 以下内容来自docker docs

Important notes on Docker environment variables 关于Docker环境变量的重要说明

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地址。

These environment variables are only set for the first process in the container. 这些环境变量仅为容器中的第一个进程设置。 Some daemons, such as sshd, will scrub them when spawning shells for connection. 某些守护进程(如sshd)会在生成shell进行连接时擦除它们。

This is included in the experimental build of docker 3 weeks ago, with the introduction of services: https://github.com/docker/docker/blob/master/experimental/networking.md 这包括在3周前docker的实验版本中,引入了服务: https//github.com/docker/docker/blob/master/experimental/networking.md

You should be able to get a dynamic link in place by running a docker container with the --publish-service <name> arguments. 您应该能够通过使用--publish-service <name>参数运行--publish-service <name>容器来获得动态链接。 This name will be accessible via the DNS. 该名称可通过DNS访问。 This is persistent on container restarts (as long as you restart the container with the same service name that is of course) 这在容器重启时是持久的(只要你重启具有相同服务名称的容器,当然)

You may use dockerlinks with names to solve this. 您可以使用具有名称的dockerlinks来解决此问题。

Most basic setup would be to first create a named database container : 最基本的设置是首先创建一个命名数据库容器:

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

then create a web container connecting to db : 然后创建一个连接到db的Web容器:

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

With this, you don't need to manually connect containers with their IP adresses. 这样,您无需手动将容器与其IP地址连接。

with OpenSVC approach, you can workaround by : 使用OpenSVC方法,您可以通过以下方式解决:

  • use a service with its own ip address/dns name (the one your end users will connect to) 使用具有自己的IP地址/ DNS名称的服务(最终用户将连接到的服务)
  • tell docker to expose ports to this specific ip address ("--ip" docker option) 告诉docker将端口暴露给这个特定的ip地址(“--ip”docker选项)
  • configure your apps to connect to the service ip address 配置您的应用程序以连接到服务IP地址

each time you replace a container, you are sure that it will connect to the correct ip address. 每次更换容器时,您都确定它将连接到正确的IP地址。

Tutorial here => Docker Multi Containers with OpenSVC 这里的教程=> 使用OpenSVC的Docker多容器

don't miss the "complex orchestration" part at the end of tuto, which can help you start/stop containers in the correct order (1 postgresql subset + 1 webapp subset + 1 nginx subset) 不要错过tuto末尾的“复杂编排”部分,它可以帮助您以正确的顺序启动/停止容器(1个postgresql子集+ 1个webapp子集+ 1个nginx子集)

the main drawback is that you expose webapp and PostgreSQL ports to public address, and actually only the nginx tcp port need to be exposed in public. 主要缺点是您将webapp和PostgreSQL端口暴露给公共地址,实际上只需要公开暴露nginx tcp端口。

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

You can bind the connection ports of your images to fixed ports on the host and configure the services to use them instead. 您可以将映像的连接端口绑定到主机上的固定端口,并配置服务以使用它们。

This has its drawbacks as well, but it might work in your case. 这也有其缺点,但它可能适用于您的情况。

Another alternative is to use the --net container:$CONTAINER_ID option. 另一种方法是使用--net container:$CONTAINER_ID选项。

Step 1: Create "network" containers 第1步:创建“网络”容器

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

Step 2: Inject services into "network" containers 第2步:将服务注入“网络”容器

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

As long as you do not touch the "network" containers, the IP addresses of your links should not change. 只要您不触摸“网络”容器,就不应更改链接的IP地址。

Network-scoped alias is what you need is this case. 在这种情况下,您需要网络范围的别名 It's a rather new feature, which can be used to "publish" a container providing a service for the whole network, unlike link aliases accessible only from one container. 这是一个相当新的功能,可用于“发布”为整个网络提供服务的容器,而不像只能从一个容器访问的链接别名。

It does not add any kind of dependency between containers — they can communicate as long as both are running, regardless of restarts and replacement and launch order. 它不会在容器之间添加任何类型的依赖关系 - 只要两者都在运行,它们就可以进行通信,无论重启和替换以及启动顺序如何。 It uses DNS internally, I believe, instead of /etc/hosts 我相信它在内部使用DNS而不是/ etc / hosts

Use it like this: docker run --net=some_user_definied_nw --net-alias postgres ... and you can connect to it using that alias from any container on the same network. 像这样使用它: docker run --net=some_user_definied_nw --net-alias postgres ...你可以使用同一网络上任何容器的别名连接到它。

Does not work on the default network, unfortunately, you have to create one with docker network create <network> and then use it with --net=<network> for every container ( compose supports it as well ). 在默认网络上不起作用,遗憾的是,您必须使用--net=<network> docker network create <network>创建一个,然后将其与--net=<network>用于每个容器( compose也支持它 )。

In addition to container being down and hence unreachable by alias multiple containers can also share an alias in which case it's not guaranteed that it will be resolved to the right one. 除了容器被关闭并且因此别名无法访问之外,多个容器也可以共享别名,在这种情况下,不能保证它将被解析为正确的别名。 But in some case that can help with seamless upgrade, probably. 但在某些情况下,可能有助于无缝升级。

It's all not very well documented as of yet, hard to figure out just by reading the man page. 到目前为止还没有很好的文档记录,只是通过阅读手册页难以弄明白。

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

相关问题 不同Docker容器上的Rails和Nginx(如何在容器之间共享数据) - Rails and Nginx on different Docker containers (how share data between containers) 如何在不重新启动整个服务的情况下更新 Tomcat webapp? - How do I update a Tomcat webapp without restarting the entire service? Docker:使用套接字在2个容器之间进行通信 - Docker: Use sockets for communication between 2 containers 如何在许可下部署 docker 容器 - How to deploy docker containers on permise 如何在 Ufizzi 上设置我的 API 服务? - How do I set up my API service on Uffizzi? 如何在PhpStorm中设置部署部分? - How do I set up the deployment section in PhpStorm? 如何设置 register 变量以在 ansible 的播放之间保持不变? - How do I set register a variable to persist between plays in ansible? 容器(即docker)和封装包装(即flatpack,snap)之间的概念和实际差异是什么? - What are conceptual and practical differences between containers (i.e. docker) and encapsulated packages (i.e. flatpack, snap)? 如何让 ECS 容器访问私有 git 存储库? - How do I give ECS containers access to a private git repo? 如何正确重启Docker容器进行部署过程? - How to correctly restart Docker containers for deployment process?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM