programing

다시 시작해도 중단되지 않도록 Docker 컨테이너 간의 연결을 어떻게 설정합니까?

nasanasas 2020. 10. 8. 08:06
반응형

다시 시작해도 중단되지 않도록 Docker 컨테이너 간의 연결을 어떻게 설정합니까?


다음과 같이 실행되는 몇 가지 Docker 컨테이너가 있습니다.

  • Nginx
  • 웹 앱 1
  • 웹 앱 2
  • PostgreSQL

Nginx는 웹 앱 1과 2 내의 웹 애플리케이션 서버에 연결해야하고 웹 앱은 PostgreSQL과 통신해야하므로 다음과 같은 링크가 있습니다.

  • Nginx --- 링크 ---> 웹 앱 1
  • Nginx --- 링크 ---> 웹 앱 2
  • 웹 앱 1 --- 링크 ---> PostgreSQL
  • 웹 앱 2 --- 링크 ---> PostgreSQL

이것은 처음에는 꽤 잘 작동합니다. 하지만 웹앱 1과 웹앱 2의 새 버전을 개발할 때이를 교체해야합니다. 내가하는 일은 웹 앱 컨테이너를 제거하고 새 컨테이너를 설정 한 다음 시작하는 것입니다.

웹 앱 컨테이너의 경우 처음에 해당 IP 주소는 다음과 같습니다.

  • 172.17.0.2
  • 172.17.0.3

그리고 그것들을 교체하면 새 IP 주소를 갖게됩니다.

  • 172.17.0.5
  • 172.17.0.6

이제 Nginx 컨테이너에 노출 된 환경 변수는 여전히 이전 IP 주소를 가리 킵니다. 여기에 문제가 있습니다. 컨테이너 간의 연결을 끊지 않고 컨테이너를 교체하려면 어떻게해야합니까? PostgreSQL에서도 동일한 문제가 발생합니다. PostgreSQL 이미지 버전을 업그레이드하려면 확실히 제거하고 새 버전을 실행해야하지만 전체 컨테이너 그래프를 다시 빌드해야하므로 실제 서버 운영에는 적합하지 않습니다.


의 효과 --link는 정적이므로 시나리오에서 작동하지 않습니다 (현재는 다시 연결되지 않지만 링크제거 할 수 있음 ).

우리는 dockerize.it에서 두 가지 다른 접근 방식을 사용하여 링크 나 대사없이이 문제를 해결했습니다 (대사도 추가 할 수 있지만).

1) 동적 DNS 사용

일반적인 아이디어는 데이터베이스 (또는 다른 서비스)에 대해 단일 이름을 지정하고 컨테이너를 시작 및 중지 할 때 실제 IP로 수명이 짧은 DNS 서버를 업데이트하는 것입니다.

우리는 SkyDock으로 시작했습니다 . 두 개의 도커 컨테이너, DNS 서버 및 자동 업데이트를 유지하는 모니터와 함께 작동합니다. 나중에 우리는 Consul을 사용하여보다 맞춤화 된 것으로 이동했습니다 (도 커화 된 버전 : docker-consul 사용 ).

이것의 진화 (우리가 시도하지 않은)는 etcd 또는 이와 유사한 것을 설정하고 사용자 정의 API를 사용하여 IP와 포트를 학습하는 것입니다. 소프트웨어는 동적 재구성도 지원해야합니다.

2) 도커 브리지 IP 사용

컨테이너 포트를 노출 할 때 docker0잘 알려진 주소가 있거나 가질 수있는 브리지에 연결하기 만하면 됩니다.

컨테이너를 새 버전으로 교체 할 때 새 컨테이너가 동일한 IP에 동일한 포트를 게시하도록합니다.

이것은 더 간단하지만 더 제한적입니다. 유사한 소프트웨어 (예 : 두 개의 컨테이너가 docker0브리지 의 3306 포트에서 수신 대기 할 수 없음)를 실행하는 경우 포트 충돌이 발생할 수 있으므로 현재 가장 선호하는 옵션은 1입니다.


링크 는 컨테이너 이름을 기반으로하지 않고 특정 컨테이너에 대한 것입니다. 따라서 컨테이너를 제거하는 순간 링크 연결이 끊어지고 새 컨테이너 (이름이 같더라도)가 자동으로 자리를 차지하지 않습니다.

새로운 네트워킹 기능을 사용하면 이름으로 컨테이너에 연결할 수 있으므로 새 네트워크를 만들면 해당 네트워크에 연결된 모든 컨테이너가 이름으로 다른 컨테이너에 연결할 수 있습니다. 예:

1) 새 네트워크 생성

$ docker network create <network-name>       

2) 컨테이너를 네트워크에 연결

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

또는

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

3) 이름 별 핑 컨테이너

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

문서 의이 섹션을 참조하십시오 .

참고 : 레거시와 달리 links새 네트워킹 환경 변수를 생성하지 않으며 다른 컨테이너와 환경 변수를 공유하지 않습니다.

이 기능은 현재 별칭을 지원하지 않습니다.


앰배서더 컨테이너를 사용할 수 있습니다 . 그러나 위와 동일한 문제가 발생하므로 앰배서더 컨테이너를 클라이언트에 연결하지 마십시오. 대신 Docker 호스트 (일반적으로 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-container :

$ 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 클라이언트 컨테이너를 시작하고 게이트웨이 호스트 (일반적으로 172.17.42.1)에서 postgresql에 액세스 할 수 있습니다.

$ 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.

There will be a host file entry for each of the linked container in the format LINKEDCONTAINERNAME_PORT_PORTNUMBER_TCP etc..

The following is from docker docs

Important notes on Docker environment variables

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. We recommend using the host entries in /etc/hosts to resolve the IP address of linked containers.

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.


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

You should be able to get a dynamic link in place by running a docker container with the --publish-service <name> arguments. This name will be accessible via the 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.

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 :

$ 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.


with OpenSVC approach, you can workaround by :

  • use a service with its own ip address/dns name (the one your end users will connect to)
  • tell docker to expose ports to this specific ip address ("--ip" docker option)
  • configure your apps to connect to the service ip address

each time you replace a container, you are sure that it will connect to the correct ip address.

Tutorial here => Docker Multi Containers with OpenSVC

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)

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.


You could also try the ambassador method of having an intermediary container just for keeping the link intact... (see https://docs.docker.com/articles/ambassador_pattern_linking/ ) for more info


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.

Step 1: Create "network" containers

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

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.


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

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.

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).

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.

참고URL : https://stackoverflow.com/questions/24252598/how-do-i-set-up-linkage-between-docker-containers-so-that-restarting-wont-break

반응형