Docker 컨테이너도 물론 VM처럼 각 공간마다 다른 IP주소를 할당받을 수 있다. 하이퍼바이저의 GUI 창에서 마우스만 깔딱거리다 Docker의 까만 터미널을 마주했다고 해도 사실 크게 다른 점은 없다. 걱정하지 말고 이번 포스트를 쭉 읽으며 실용적인 Docker에서의 네트워크 설정법에 대해 알아가자.

기본 Docker 네트워크


위 간단히 만들어본 이미지가 바로 Docker의 기본적인 네트워크 구성이다. Docker를 설치한 호스트 컴퓨터에는 docker0라는 가상 브릿지 인터페이스가 생긴다. 새로운 컨테이너를 생성하면 이 docker0vethxxxx 인터페이스로 시작하는 터널이 쭉 파져서 컨테이너의 eth0 인터페이스와 연결되는 것이다. 컨테이너는 브릿지 네트워크를 통해 결국 호스트 컴퓨터의 네트워크 인터페이스로 외부로 통신함으로 iptables를 사용해 포트 접근 등의 제어가 가능하다.(물론 iptables를 사용하지 않는 환경을 위해 docker-proxy라는 프로세스가 또 존재하긴 한다.)

Docker에서는 추가로 호스트 컴퓨터와 같은 네트워크 환경을 사용하는 설정이나, 다른 컨테이너의 네트워크 환경을 공유하는 설정 등이 존재하지만, 위의 기본 설정만으로도 많은 서비스 환경을 커버할 수 있으니 이 포스트에서는 따로 설명하지 않겠다. 이 부분 관련하여 자세한 내용을 원하는 분들은 이 블로그 참고를 추천한다.

Docker 네트워크

그럼 여기서 하나 궁금증이 생긴다. 평소 필자는 VM을 사용할 때 호스트 컴퓨터의 네트워크 인터페이스와 브릿지로 묶고 같은 네트워크에 접속하여 사용하는 것을 좋아한다. 무슨 말이냐면 내 공유기의 IP 대역이 192.168.0.0/24일때, 호스트 컴퓨터는 192.168.0.1, VM은 192.168.0.2 주소를 사용하는 것이다. 이런 구성방식을 ‘Flat 네트워크’라 한다. 물론 모든 VM이 같은 브로드캐스트 영역에 놓이게 되어 규모가 커지게 되면 절대 사용이 권장되지 않는 구성법이지만, 개인적인 용도로 굴릴때 이것보다 간단한 방법은 없어 자주 애용한다. 그럼 이 Flat 네트워크 구성법을 Docker 컨테이너와는 사용할 수 없는 것인가? 정답은 ‘가능하다’ 이다.

이 구성을 위해 우리는 브릿지 설정 도구인 bridge-utils을 사용할 것이다. CentOS 기준 sudo yum install -y bridge-utils 명령어로 간단하게 설치할 수 있다. 원래 OpenVSwitch를 이용해 DHCP로 공유기에서 IP를 받아오는 설정을 구성하려 했지만, 어디에서 꼬였는지 계속 필자를 괴롭혀서 결국 고정 대역을 미리 잡아놓고 공유기 네트워크와 연결하는 방법으로 경로를 수정했다. 삽질로 날라간 몇시간과 고통받은 몸에 묵념을.


필자의 테스트 환경은 아래 위 이미지와 같다. 그럼 바로 시작해보자.

sudo brctl addbr br0 # br0 브릿지 생성.
sudo brctl addif br0 enpxxxx # br0에 enpxxxx(연결할 네트워크 어댑터 이름) 연결.
sudo brctl setfd br0 0 # br0 초기화.
ifconfig br0 192.168.2.2 netmask 255.255.255.0 # br0의 IP 주소를 192.168.2.1, 서브넷 마스크를 /24로 설정.

여기까지 끝났으면 이제 CentOS 기준 /etc/sysconfig/network-scripts 로 이동해 브릿지와 네트워크 인터페이스의 설정 스크립트를 만져주자. 파일 이름은 브릿지의 경우 ifcfg-br0, 네트워크 인터페이스는 ifcfg-enpxxxx 로 잡혀 있을 것이다. 많이 파일이 보이지 않는다고 해도 걱정하지 말고 새로 하나 만들어주면 된다.

DEVICE=br0
TYPE=Bridge
IPADDR=192.168.2.2
NETMASK=255.255.255.0
ONBOOT=yes
BOOTPROTO=none
NM_CONTROLLED=no
DELAY=0

위는 레드헷 홈페이지에서 직접 제공하는 모범적인 브릿지 스크립트의 예시이다. 적당히 참조해 고쳐 쓰면 된다.

DEVICE=enp0000
TYPE=Ethernet
HWADDR=AA:BB:CC:DD:EE:FF
BOOTPROTO=none
ONBOOT=yes
NM_CONTROLLED=no
BRIDGE=br0

마찬가지로 네트워크 인터페이스 스크립트다. 참고로 저기 적힌 NM_CONTROLLED는 RHEL 7(CentOS 7)부터 달린 골칫덩이 NetworkManager가 손댈 수 없게 해주는 설정이다.

모두 작성하였으면, sudo systemctl restart network로 네트워크 서비스를 재시작 해준다. 잘 하셨다. 이제 브릿지의 준비는 끝났다. 마지막으로 Docker가 이 브릿지를 받아먹게 설정해주면 끝.

sudo docker network create --driver=bridge --ip-range=192.168.2.0/24 --subnet=192.168.2.0/24 --aux-address='ip1=192.168.2.10' -o "com.docker.network.bridge.name=br0" br0

내가 사용한 새로운 Docker 네트워크를 생성하는 명령어다. 나머지는 대충 읽어도 무슨 의미인지 알겠는데, --aux 옵션이나 -o는 무슨 의미잇지 햇갈릴 것이다. 전자는 내가 등록한 네트워크 인터페이스 (브릿지)가 사용하는 추가적인 IP 주소. 대충 내 네트워크 대역 안의 안 사용중인 주소를 입력해주면 될 것 같다. 후자는 추가적인 네트워크 인터페이스 옵션이다. 실제 브릿지 br0와 연결해주는 역할이라고 생각하면 편하다. 마지막 br0은 이 Docker 네트워크의 이름을 br0으로 하겠다는 말이다.

이제 브릿지와 연결되는 Docker 네트워크 생성도 끝났다. 한번 컨테이너를 생성해보자.

sudo docker run -i -t --network=br0 ubuntu

--network 깃발로 어떤 Docker 네트워크를 사용할 것인지 지정해줄 수 있다. 위처럼 입력하면 당연히 br0을 사용하게 된다. 아무것도 지정하지 않으면 기본 설정인 docker0에 연결한다.

생성한 컨테이너에 들어가 인터넷 연결은 제대로 되는지, 내 네트워크 안에 있는 다른 기기와 ping은 잘 주고받아 지는지 확인해보자. 아마 별 문제 없을 것이다. 물론 이 방법이 완전히 정답은 아니지만 (오버레이 네트워크를 만들어 다른 서버들과 통신할 수도 있다. 더 확실하고 ‘힙’한 방법. 나중에 이 포스트 아래에 추가해 두겠다.), 중/소규모 환경에서 깔끔하게 하나의 네트워크로 컨테이너와 여러 서버들을 연결시키는 용도로는 훌륭하다. 가장 시스템 엔지니어들이 스트레스 안 받는 방법이라 할 수 있겠다. 하고보면 복잡할 것 없고 금방 끝날 설정인데, 이상하게 필자는 삼천포를 헤매다 와서 몇시간이 걸렸다. 분명 제대로 설정한 것 같은데 외부 연결이 안되고 난리가 아니였다. 브릿지 설정을 모두 밀고 다시 해보았더니 언제 그랬냐는듯 깔끔하게 해결… 다른 분들은 이런 실수를 반복하지 않기를.

일단 거의 대부분의 환경에서 동작하는 Docker는 위 두가지 설정법으로도 커버가 가능할 것이다. 다만, 아까 언급한 오버레이 네트워크 같은 것도 있고, 조금 더 다루고 싶은 내용들이 존재할 수 있으니 이 포스트는 시간날 때 틈틈히 업데이트 할 예정이다. 삽질에 고통받은 필자와 읽느라 수고한 독자 모두 수고하셨다.