컨테이너를 구동할 때 -p 옵션을 이용해서 컨테이너의 포트와 연결된 호스트 포트를 설정했다.
docker run --name mysqldb \
-e MYSQL_ROOT_PASSWORD=rootpw \
-p 33060:3306 -d mysql:5.7
실행한 MySQL에 접속하려면 호스트IP:33060으로 연결하면 된다.
도커 컨테이너 간에 연결할 경우에는 어떻게 할까? 각 컨테이너마다 환경 변수를 이용해서 연결할 호스트의 IP와 포트를 설정할 수 있을 것이다. 이 방법이 안 되는 것은 아니지만 이보다 좋은 방법은 도커 네트워크를 이용하는 것이다.
도커 네트워크
docker network ls 명령어를 사용하면 도커가 제공하는 네트워크 목록을 확인할 수 있다.
vagrant@ubuntu-bionic:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
e83fd9260276 bridge bridge local
f6a428e9d599 host host local
2e3d5809c8ac none null local
도커는 기본으로 세 개의 네트워크를 제공한다. 각 네트워크는 다음과 같다.
- bridge 네트워크 : bridge 드라이버로 제공하는 네트워크로 컨테이너간 연결을 제공하며 컨테이너를 구동하는 호스트 네트워크가 구분된다.
- host 네트워크 : host 드라이버로 제공하는 네트워크로 컨테이너를 위한 별도 네트워크없이 호스트와 동일한 네트워크를 사용한다.
- none 네트워크 : null 드라이버를 사용하며 네트워크 연결을 갖지 않는다.
네트워크 SCOPE는 네트워크의 범위를 의미하며 다음의 세 가지 범위가 존재한다.
- local : 컨테이너간 연결은 네트워크가 존재하는 호스트로 제한된다.
- global : 클러스터의 모든 노드에 네트워크가 존재하지만 호스트 간 라우팅은 지원하지 않는다.
- swarm : 도커 스웜에 참여하는 모든 호스트로 연결을 확장한다.
이 글에서는 단일 호스트에서 네트워크를 연결하는 방법을 살펴본다. 여러 호스트에서 실행 중인 컨테이너 간의 연결은 도커 스웜을 설명할 때 살펴볼 것이다.
컨테이너 간 연결 : 기본 bridge 네트워크 이용
컨테이너 간에 연결하는 가장 쉬운 방법은 기본으로 제공하는 bridge 네트워크를 이용하는 것이다. 먼저 다음 명령을 이용해서 mysqldb 컨테이너를 생성하자. -p 옵션을 사용하지 않았으므로 호스트에서 컨테이너의 MySQL DB에 연결할 수 없다.
$ docker run --name mysqldb --rm \
-e MYSQL_ROOT_PASSWORD=rootpw \
-d mysql:5.7
이제 웹 기반 DB 관리도구 중 하나인 adminer를 다음 명령어를 이용해서 구동하자. Ctrl+C를 누르면 컨테이너가 종료되니 주의한다.
$ docker run --rm --name dbadmin --link mysqldb:db -p 8080:8080 adminer
PHP 7.3.10 Development Server started at Sun Sep 29 08:50:22 2019
여기서 --link 옵션이 중요하다. --link 옵션의 값으로 "mysqldb:db"를 주었는데 여기서 앞의 mysqldb는 컨테이너의 이름이며 뒤의 db는 컨테이너 내부에서 사용할 식별자이다. 즉 dbadmin 컨테이너 내부에서 db라는 이름으로 mysqldb 컨테이너에 접근할 수 있다는 것을 의미한다.
실제로 그런지 http://호스트IP:8080으로 연결해서 확인해보자. adminer 첫 화면에 연결하면 DB 로그인 폼이 표시되는데 여기서 서버에 "db:3306"이라고 입력한다. 사용자이름과 비밀번호는 각각 "root", "rootpw"를 입력한다(앞서 mysqldb 컨테이너를 구동할 때 MYSQL_ROOT_PASSWORD 환경 변수의 값으로 rootpw를 주었다).
로그인 버튼을 눌러보자. 다음과 같이 DB에 연결한 결과를 볼 수 있다.
dbadmin 컨테이너에서 db:3306으로 연결한 DB가 실제 mysqldb 컨테이너가 제공하는 DB인지 확인해보자. 먼저 mysqldb 컨테이너의 mysql db에 연결해서 이름이 test인 DB를 생성한다.
vagrant@ubuntu-bionic:~$ docker exec -it mysqldb mysql -u root -p
Enter password: (암호입력)
Welcome to the MySQL monitor. Commands end with ; or \g.
...생략
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> exit
Bye
vagrant@ubuntu-bionic:~$
그런 뒤 adminer 웹 화면에서 데이터베이스를 새로 고침해보자. 그러면 생성한 test DB가 목록에 표시될 것이다.
컨테이너 간 연결 : bridge 네트워크를 생성해서 연결
bridge 네트워크를 직접 생성할 수도 있다.
$ docker network create \
--driver bridge \
--attachable \
--scope local \
--subnet 10.0.7.0/24 \
--ip-range 10.0.7.0/24 \
mynet
mynet 네트워크는 bridge 네트워크로 --attachable 옵션은 컨테이너가 언제든지 네트워크에 연결하거나 떨어질 수 있게 설정한다. --subnet과 --ip-range는 서브넷과 할당 가능한 IP 범위를 지정한다.
네트워크를 생성했다면 컨테이너를 네트워크에 붙일 수 있다. 컨테이너를 실행할 때 --network 옵션을 사용하면 된다.
docker run --name mysqldb \
--network mynet \
-e MYSQL_ROOT_PASSWORD=rootpw \
-d mysql:5.7
같은 네트워크에 참여하는 컨테이너는 이름을 사용해서 다른 컨테이너에 연결할 수 있다. 아래 코드를 보자.
vagrant@ubuntu-bionic:~$ docker run --name cent7 -it --network mynet centos:7 bash
[root@fc0936cc3177 /]# ping mysqldb
PING mysqldb (10.0.7.2) 56(84) bytes of data.
64 bytes from mysqldb.mynet (10.0.7.2): icmp_seq=1 ttl=64 time=0.183 ms
64 bytes from mysqldb.mynet (10.0.7.2): icmp_seq=2 ttl=64 time=0.136 ms
^C
--- mysqldb ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.136/0.159/0.183/0.026 ms
이 코드는 mynet 네트워크에 참여하는 cent7 컨테이너를 생성하고 bash 명령어를 실행한다. mynet 네트워크에 mysqldb 컨테이너도 참여했으므로 cent7 컨테이너는 컨테이너 이름을 사용해서 mysqldb에 연결할 수 있다. ping 명령어를 실행할 때 표시된 IP 주소는 10.0.7.2인데 이 IP 주소는 mynet 네트워크를 생성할 때 지정한 IP 범위에 속한다.
이미 생성한 컨테이너에 네트워크를 연결하고 싶거나 연결된 네트워크를 끊고 싶을 때에는 docker network connect 명령어나 docker network disconnet 명령어를 사용한다.
관련 글