땡글이LAB

[도커/쿠버네티스] 도커 네트워크 본문

Devops/도커, 쿠버네티스

[도커/쿠버네티스] 도커 네트워크

땡글이B 2022. 7. 18. 15:33

도커 네트워크 구조

 컨테이너 내부에서 ifconfig 명령어를 입력하면, 컨테이너의 네트워크 인터페이스에 eth0과 lo 네트워크 인터페이스가 있는 것을 확인할 수 있다. 도커는 컨테이너에 내부 IP를 순차적으로 할당하며, 이 IP는 컨테이너를 재시작할 때마다 변경될 수 있다. 이 내부 IP는 도커가 설치된 호스트, 즉 내부 망에서만 쓸 수 있는 IP이므로 외부와 연결될 필요가 있다. 

 

 도커는 각 컨테이너에 외부와의 네트워크를 제공하기 위해 컨테이너마다 가상 네트워크 인터페이스를 호스트에 생성하며 이 인터페이스의 이름은 veth로 시작한다. veth 인터페이스는 사용자가 직접 생성할 필요는 없고 컨테이너가 생성될 때 도커 엔진이 자동으로 생성한다.

  • veth이 의미하는 바는 'virtual eth' 이다.

 

 도커가 설치된 호스트에서 ifconfig나 ip addr 과 같은 명령어로 네트워크 인터페이스를 확인하면 실행 중인 컨테이너 수만큼 veth로 시작하는 인터페이스가 생성된 것을 알 수 있다. 

 

 eth0는 공인 IP 또는 내부 IP가 할당되어 실제로 외부와 통신할 수 있는 호스트의 네트워크 인터페이스이다. veth로 시작하는 인터페이스는 컨테이너를 시작할 때 생성됐으며, 각 컨테이너의 eth0와 연결되어있다.

 

 veth 뿐만 아니라 docker0라는 브리지도 존재하는데 docker0 브리지는 각 veth 인터페이스와 바인딩돼 호스트의 eth0 인터페이스와 이어주는 역할을 한다. 즉 컨테이너와 호스트의 네트워크는 아래 그림과 같은 구조이다.

 즉, 컨테이너의 eth0 인터페이스는 호스트의 veth...라는 인터페이스와 연결됐으며 veth 인터페이스는 docker0 브리지와 바인딩돼 외부와 통신할 수 있다.

 

 

도커 네트워크 기능

 도커가 자체적으로 제공하는 대표적인 네트워크 드라이버는 브리지(bridge), 호스트(host), 논(none), 컨테이너(container), 오버레이(overlay) 가 있다. 서드파티(third-party) 플러그인 솔루션으로는 weave, flannel, openvswitch 등이 있으며 더 확장된 네트워크 구성을 위해 사용된다.

 

docker network ls 를 입력하면, 이미 bridge, host, none network 가 있다는 것을 알 수 있다. Bridge 네트워크는 컨테이너를 생성할 때 자동으로 연결되는 docker0 bridge를 활용하도록 설정되어 있다. 

 

 docker network inspect 명령어를 이용하면 네트워크의 자세한 정보를 살펴볼 수 있다. docker inspect --type network를 사용해도 동일한 출력 결과를 볼 수 있다.

 

브리지(Bridge) 네트워크

 Bridge 네트워크는 docker0 브리지와 비슷하게 브리지 네트워크는 docker0이 아닌 사용자 정의 브리지를 새로 생성해 각 컨테이너에 연결하는 네트워크 구조이다. 컨테이너는 연결된 브리지를 통해 외부와 통신할 수 있다. 

 

 다음 명령어를 입력해 새로운 브리지 네트워크를 생성한다.

// Bridge 네트워크 생성
$ docker network create --driver bridge mybridge


// 위에서 생성된 Bridge 네트워크롤 사용하는 컨테이너 생성
$ docker run -i -t --name mynetwork_container \
--net mybridge \
ubuntu:14.04

 컨테이너 내부에서 ifconfig를 입력해보면 새로운 IP 대역이 할당된 것을 알 수 있다. Bridge 타입의 네트워크를 생성하면 도커는 IP 대역을 차례대로 할당한다.

 

 이렇게 생성된 사용자 정의 네트워크는 docker network disconnect, connect를 통해 컨테이너에 유동적으로 붙이고 뗄 수 있다. 단, None network, Host network 등과 같은 특별한 네트워크 모드에는 connect, disconnet 명령어를 사용할 수 없다.

 

 네트워크의 서브넷, 게이트웨이, IP 할당 범위 등을 임의로 설정하려면 네트워크를 생성할 때 아래와 같이 --subnet, --ip-range, --gateway 옵션을 추가해야한다. (단, --subnet 옵션과 --ip-range 옵션은 같은 대역이어야 한다.)

 

호스트(Host) 네트워크

 네트워크를 호스트로 설정하려면 호스트의 네트워크 환경을 그대로 쓸 수 있다. 위의 브리지 드라이버 네트워크와 달리 호스트 드라이버의 네트워크는 별도로 생성할 필요 없이 기존의 host라는 이름의 네트워크를 사용한다. (아래 명령어 참고)

$ docker run -i -t --name network_host \
--net host \
ubuntu:14.04

 

 --net 옵션을 통해 호스트를 설정한 컨테이너 내부에서 네트워크 환경을 확인하면 호스트와 같은 것을 알 수 있고, 호스트 이름도 컨테이너가 물려받기 때문에 컨테이너의 호스트 이름도 무작위 16진수가 아닌 도커 엔진이 설치된 호스트 머신의 호스트 이름으로 설정된다.

 

 컨테이너의 네트워크를 호스트 모드로 설정하면, 컨테이너 내부의 애플리케이션을 별도의 포트 포워딩 없이 바로 서비스할 수 있다. 이는 마치 실제 호스트에서 애플리케이션을 외부에 노출하는 것과 같다. 예를 들어, 호스트 모드를 쓰는 컨테이너에서 아파치 웹 서버를 구동한다면 호스트의 IP와 컨테이너의 아파치 웹 서버 포트인 80으로 바로 접근할 수 있다.

 

논(None) 네트워크

 none은 말 그대로 아무런 네트워크를 쓰지 않는 것을 의미한다. 즉, 외부와의 연결이 단절되어 있다.(ifconfig 명령어로 확인해보면, lo 인터페이스만 존재함) 다음과 같이 컨테이너 생성하면 된다.

$ docker run -i -t --name network_none \
--net none \
ubuntu:14.04

 

컨테이너 네트워크

 --net 옵션으로 container를 입력하면 다른 컨테이너의 네임스페이스 환경을 공유할 수 있다. 공유되는 속성은 내부 IP, 네트워크 인터페이스의 맥(MAC) 주소 등이다. --net 옵션의 값으로 container:[다른 컨테이너의 ID]와 같이 입력한다.

$ docker run -i -t -d --name network_container_1 ubuntu:14.04


$ docker run -i -t -d --name network_container_2 \
--net container:network_container_1 \
ubuntu:14.04

 

실제, "docker exec network_container_1 ifconfig" 와 "docker exec network_container_2 ifconfig"를 입력해보면, 두 컨테이너의 eth0 의 정보가 완전히 같은 것을 알 수 있다. 아래의 그림과 같은 구조다.

 

브리지(Bridge) 네트워크와 --net-alias

 Bridge 타입의 네트워크와 run 명령어의 --net-alias 옵션을 함께 쓰면 특정 호스트 이름으로 컨테이너 여러 개에 접근할 수 있다. 위에서 생성한 mybridge 네트워크를 이용해 컨테이너를 3개 생성해본다. 이후, 3개의 컨테이너에 접근할 컨테이너를 생성한 뒤 bog라는 호스트 이름으로 ping 요청을 전송해본다.

// 같은 브리지 네트워크를 가지는 컨테이너 3개 생성 + "--net-alias" 옵션 설정
$ docker run -i -t -d --name network_bog_container1 \
--net mybridge \
--net-alias bog \
ubuntu:14.04


$ docker run -i -t -d --name network_bog_container2 \
--net mybridge \
--net-alias bog \
ubuntu:14.04

$ docker run -i -t -d --name network_bog_container3 \
--net mybridge \
--net-alias bog \
ubuntu:14.04
// 3개의 컨테이너에 접근할 컨테이너 생성
$ docker run -i -t --name network_alias_ping \
--net mybridge \
ubuntu:14.04


// 3개의 컨테이너에 ping 요청보내기
$ ping -c 1 bog
$ ping -c 1 bog
$ ping -c 1 bog

 

ping 요청마다 달라지는 IP는 라운드 로빈(Round-Robin) 방식에 의해 결정되는 것이다. 이것이 가능한 이유는 도커 엔진에 내장된 DNS가 bog 라는 호스트 이름을 --net-alias 옵션으로 bog 를 설정한 컨테이너로 변환(resolve)하기 때문이다. 다음 그림은 도커 네트워크에서 사용하는 내장 DNS와 --net-alias 의 관계를 보여준다. 

 즉, --net-alias 옵션 또한 --link 옵션과 비슷한 원리로 작동한다. 도커는 기본 브리지 네트워크가 아닌 사용자가 정의한 브리지 네트워크에 사용되는 내장 DNS 서버를 가지며, DNS의 IP는 127.0.0.11이다. mybridge 라는 이름의 네트워크에 속한 3개의 컨테이너는 run으로 생성할 때 --net-alias 옵션에 bog 라는 값을 입력했으며, 이 컨테이너의 IP는 DNS 서버에 bog라는 호스트 이름으로 등록된다. 

  • apt-get update -> apt-get install dnsutils -> "dig bog" 입력해주면 반환되는 IP의 리스트 순서가 모두 다른 것을 확인할 수 있다.

 

MacVLAN 네트워크

 MacVLAN 은 호스트의 네트워크 인터페이스 카드를 가상화해 물리 네트워크 환경을 컨테이너에게 동일하게 제공한다. 따라서 MacVLAN을 사용하면 컨테이너는 물리 네트워크상에서 가상의 맥(MAC) 주소를 가지며, 해당 네트워크에 연결된 다른 장치와의 통신이 가능해진다. MacVLAN에 연결된 컨테이너는 기본적으로 할당되는 IP 대역인 172.17.x.x 대신 네트워크 장비의 IP를 할당받기 때문이다.

  위의 그림과 같이, 공유기, 라우터, 스위치와 같은 네트워크 장비에 두 대의 서버가 연결돼있고, 각 서버는 192.168.0.0/24 대역에서 IP를 동적으로 할당받는다고 가정해보겠습니다. MacVLAN 을 사용하면 각 컨테이너에 192.168.0.0/24 대역의 IP를 할당할 수 있다. 따라서 MacVLAN 을 사용하는 컨테이너들과 동일한 IP 대역을 사용하는 서버 및 컨테이너들은 서로 통신이 가능해진다.

 

 

 

 

References

 

시작하세요! 도커/쿠버네티스 - 교보문고

친절한 설명으로 쉽게 이해하는 컨테이너 관리 | ★ 이 책의 구성 ★◎ 도커의 기본 사용 방법을 익힘으로써 컨테이너의 기본 개념을 학습합니다. (1부 1장, 1부 2장)◎ 도커 스웜 모드를 통해 서

www.kyobobook.co.kr

Comments