06C. 다른 서버의 Docker 컨테이너에 연결하기
06C. 다른 서버의 Docker 컨테이너에 연결하기 관련
앞에서 설명한 --lin
k 옵션은 같은 서버의 컨테이너끼리 연결하는 옵션입니다. 이번에는 앰배서더 컨테이너(Ambassador Container)라는 것을 이용하여 다른 서버에 있는 컨테이너에 연결해보겠습니다.
앰배서더 컨테이너는 특별한 컨테이너가 아닌 그냥 일반적인 Docker 컨테이너입니다. 앰배서더 컨테이너는 socat
이라는 프로그램을 이용하여 TCP 연결을 다른 곳으로 전달하도록 구성되어 있습니다.
앰배서더 컨테이너의 Dockerfile을 보면 상당히 복잡하게 보이지만 생각보다 간단합니다. docker run
명령을 실행할 때 전달한 환경 변수를 이용하여 socat
을 실행하는 셸 스크립트입니다.
CMD env | grep _TCP= | \
sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat \
TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' \
| sh && top
docker run
명령에서 --link
옵션을 사용하거나 -e EXAMPLE_PORT_1234_TCP=tcp://192.168.0.10:1234
라고 설정해주면 다음과 같이 환경 변수에 포트 정보가 설정됩니다.
env
명령으로 환경 변수를 출력하고, grep
명령으로 _TCP=
를 포함하는 문자열을 찾습니다. 그리고 sed
명령으로 정규표현식을 사용하여 문자열에서 포트 번호와 IP 주소를 추출합니다. 그 뒤 추출한 포트 번호와 IP 주소를을 이용하여 socat
명령을 실행합니다.
EXAMPLE_PORT=tcp://192.168.0.10:1234
EXAMPLE_PORT_1234_TCP_ADDR=192.168.0.10
EXAMPLE_NAME=/example_ambassador/example
HOSTNAME=0cf479687cb0
EXAMPLE_PORT_1234_TCP_PORT=1234
HOME=/
EXAMPLE_PORT_1234_TCP_PROTO=tcp
EXAMPLE_PORT_1234_TCP=tcp://192.168.0.10:1234
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
위 예제 환경에서는 socat
명령으로 로컬의 TCP 프로토콜 1234
번 포트를 192.168.0.10
의 1234
번 포트로 데이터를 전달하도록 설정합니다. 이러한 구조를 앰배서더 패턴(Ambassador Pattern)이라 합니다.
그냥 다른 서버의 컨테이너에서 포트를 노출시키고, 해당 포트에 연결하면 간단한데 왜 이렇게 복잡한 방법을 사용할까요? 컨테이너에서 포트를 노출시키면 해당 서버의 IP 주소나 도메인을 알아야 합니다. 이렇게 되면 작성한 애플리케이션의 소스 레벨에서 IP 주소나 도메인을 설정해주어야 합니다. 만약 서버의 IP주소, 도메인이 바뀌면 소스를 수정해야 하는데, 앰배서더 컨테이너를 이용하면 별칭으로 접근하므로 소스를 수정하지 않아도 됩니다. 즉 외부에 있는 서버라도 같은 서버의 Docker 내부망에 있는 것과 같은 효과가 납니다.
socat
socat은 SOcket CAT을 뜻하며 소켓 통신을 다른 채널로 전달하는 프로그램입니다. 채널은 파일, 파이프, 장치(시리얼, pseudo 터미널 등), 소켓(유닉스 소켓, TCP, UDP 등)이 있습니다.
이제 앰배서더 컨테이너를 이용해서 다른 서버의 컨테이너에 연결해보겠습니다. 그리고 원활한 테스트를 위해 Redis를 사용하겠습니다.
먼저 Redis 서버로 쓸 컴퓨터에서 Redis 컨테이너를 생성합니다. 이 서버의 IP 주소는 192.168.0.10
이라 하겠습니다.
sudo docker pull redis:latest
sudo docker run -d --name redis redis:latest
--name redis
옵션으로 컨테이너 이름을 redis
로 지정합니다.
.Redis 컨테이너를 위한 앰배서더 컨테이너를 생성합니다. svendowideit
는 앰배서더 패턴을 만든 사람 이름입니다.
sudo docker run -d --link redis:redis --name redis_ambassador \
-p 6379:6379 svendowideit/ambassador
-d
옵션으로 컨테이너를 백그라운드로 실행합니다.--link redis:redis
옵션으로redis
컨테이너를redis
별칭으로 연결합니다.--name redis_ambassador
옵션으로 컨테이너 이름을redis_ambassador
로 지정합니다.-p 6379:6379
옵션으로 컨테이너의6379
번 포트와 호스트의6379
연결하고 외부에 노출합니다.- Docker Hub에 있는
svendowideit/ambassador
이미지를 받은 뒤 컨테이너로 생성합니다(docker run
명령은 로컬에 이미지가 없으면 자동으로 이미지를 받아옵니다).
이제 Redis 클라이언트를 사용할 컴퓨터에서 앰배서더 컨테이너를 생성합니다. Redis 서버의 IP 주소는 192.168.0.10
입니다.
sudo docker run -d --name redis_ambassador --expose 6379 \
-e REDIS_PORT_6379_TCP=tcp://192.168.0.10:6379 svendowideit/ambassador
-d
옵션으로 컨테이너를 백그라운드로 실행합니다.--name redis_ambassador
옵션으로 컨테이너 이름을redis_ambassador
로 지정합니다.--expose 6379
옵션으로 다른 컨테이너에서6379
번 포트에 연결할 수 있도록 설정합니다. 즉 Redis 클라이언트가 이redis_ambassador
컨테이너의6379
포트에 접속하게 됩니다.--expose
옵션은-p
옵션과는 달리 호스트의 포트를 외부에 노출하지 않습니다.-e REDIS_PORT_6379_TCP=tcp://192.168.0.10:6379
옵션으로 IP 주소와 포트를 설정하여 다른 서버에 있는redis_ambassador
컨테이너에 연결합니다.- Docker Hub에 있는
svendowideit/ambassador
이미지 받은 뒤 컨테이너로 생성합니다.
이제 Redis 클라이언트를 이용하여 redis_ambassador
컨테이너에 접속합니다.
sudo docker run -i -t --rm --link redis_ambassador redis:latest redis-cli -h redis_ambassador
-i -t
옵션으로 콘솔에서 입출력을 할 수 있도록 설정합니다.--rm
옵션으로 컨테이너를 실행만 하고 컨테이너 자체는 삭제합니다. Redis 클라이언트처럼 1회성으로 사용할 때 편리합니다.--link redis_ambassador
옵션으로redis_ambassador
컨테이너를 연결합니다.redis:latest redis-cli -h redis_ambassador
는redis:latest
이미지를 받은 뒤redis-cli
로redis_ambassador
컨테이너에 연결합니다.
.Redis 클라이언트가 실행되면 ping
명령을 입력합니다. 결과로 PONG
이 출력되면 다른 서버의 Redis 컨테이너에 정상적으로 연결된 것입니다.
ping
#
# PONG