IT Technology/Cloud

Docker Network 개요

by빵수 2021. 7. 30. 20:24
728x90
반응형

Docker Network Overview

 

  • 도커는 호스트 서버의 물리적 네트워크와, 도커의 가상 네트워크가 혼합되어 네트워크가 이루어진다. 
  • 아래 그림의 예시와 같은 네트워크가 구성된다.

 

 

 

  • 이 그림에서 eth-0은 실제 서버에서 eth0 이며이며, vth-0은 실제 서버에서 vethXXXXXXX(무작위로생성된이름) 이다.
  • 그림 우측 제일 하단의 eth-0 은 서버의 물리적 인터넷 포트이며, 이 포트가 인터넷에 연결되어 있다고 가정한다. 
  • 이 인터넷 포트가 iptables를 통해 docker0 또는 다른 사용자가 직접 만든 가상 브릿지(위 그림에서 좌측 Mybridge)와 통신이 된다. 
  • 또한 이 가상 브릿지는 각각의 컨테이너와 통신하게 된다.
  • 컨테이너를 생성하면, 자동으로 컨테이너에 eth0 interface가 생기며 (물론 옵션을 통해 더 추가할 수도 있음) 생성된 컨테이너의 eth0 과 1:1 매치(pair)되는 vethXXXXXX interface가 생성된다. 
  • 이 가상 interface는 OSI 참조 모델의 레이어2 (데이터링크 계층)인 가상 네트워크 인터페이스로, pair인 컨테이너의 eth0과 터널링 통신을 한다.
  • 이렇게 pair로 구성된 두개의 interface를 통해 격리된 네트워크 환경(namespace)이 제공되며, MAC주소와 Private ip가 부여된다. 
  • 마치 직접 다이렉트로 케이블을 연결한 두 대의 PC가 서로 패킷을 주고받는 형태와 같다.
  • 또한 따로 옵션을 주지 않았다면 컨테이너의 eth0와 한 쌍인 vethXXXXXX은 docker0 가상 브릿지 네트워크에 연결된다. 
  • 이 가상 네트워크는 컨테이너끼리 통신할 수 있도록 한다. 
  • 도커는 1서비스당 1컨테이너를 권고하므로, 한 컨테이너에 여러 서비스를 포함하지 않고 각각 컨테이너로 하나씩 만들고 이 가상 브리지 네트워크로 연결되는 것이 권고된다.
  • 예를들어 데이터베이스 컨테이너와, 웹서버 컨테이너는 각각 다른 컨테이너야 한다는 것. 
  • 결론적으로 컨테이너(eth0) <-> vethXXXXXX(호스트) <-> docker0(호스트) <-> 외부네트워크 이런식으로 네트워크가 연결된다.

 

도커의 기본 가상 브리지 네트워크 : docker0

 

  • 도커 설치 시, default 로 docker0라는 가상 브리지 네트워크가 생성된다. 
  • Docker0 가상 브리지 네트워크는 소프트웨어적인 스위치방식으로, 일반적인 스위치 개념과는 다르게 DHCP로 연결된 container에게 사전에 정의된 IP pool을 할당한다.
  • Docker0 는 default로 172.17.0.0/16 서브넷을 가진 IP 대역을 가진다.
  • 컨테이너가 특별한 옵션 없이 생성된다면 docker0 에 기본으로 연결된다.
  • Docker0 는 default 브리지 네트워크일 뿐이고, 사용자가 얼마든지 추가로 가상 브리지 네트워크를 생성할 수 있다.

Docker0와 사용자 정의 네트워크

  • Docker0는 도커 설치시 자동으로 만들어지며, 컨테이너 생성시 명시적으로 지정하지 않고 run 하는 경우 이 네트워크로 컨테이너가 시작된다. 
  • Docker0 의 문제점은, DNS를 사용해 자동으로 서비스를 찾아주는 기능이 비활성화 되어있다. 
  • 즉, 이름식별이 안되므로 통신이 되지 않는다. IP로만 통신이 가능한 상태이다. 컨테이너는 일종의 프로세스이므로, 내렸다 올리면 아이피가 바뀌는 등의 유동성이 있다. 따라서 문제가 된다.
  • 컨테이너끼리 연동을 하려면 IP 기반의 설정은 좋지 않으며, link 옵션을 사용하여 연동한다.
  • 즉 docker container run 할 때 --link 옵션을 지정하야 한다. --link 옵션을 지정한다는 것은 컨테이너 안에 있는 /etc/hosts 파일에 컨테이너명과 컨테이너에 할당된 IP가 등록되고 이를 통해 통신이 가능하게 된다.
  • link를 하지 않으면 당연히 그 정보는 없다.
  • link가 걸린상태에서 컨테이너가 재기동하면 IP가 바뀔 수 있는데, 바뀐 IP값이 자동으로 /etc/hosts에 등록되어서 container의 ip정보가 바뀌어도 서로간 문제없이 통신이 가능하다.

 

 

  • 사용자 정의 네트워크는 도커 데몬에 내장된 내부 DNS 서버에 의해 이름 해결이 이루어진다. 
  • 내부 DNS 서버를 사용하면, link 기능과 같이 /etc/hosts 파일에 의존하지 않고 이름 해결을 할 수 있다. 
  • 따라서 docker0 에 연결된 컨테이너들은 ping을 할 때 IP만 가능하지만, 사용자 정의 네트워크에 연결된 컨테이너들은 컨테이너명(docker container run --name 으로 생성되는 컨테이너명)뿐만 아니라 컨테이너 시작 시 지정한  --net-alias 옵션을 사용한 에일리어스 명칭으로도 통신이 가능하다. 
  • 사용자 정의 네트워크를 쓰는 편이 보다 유연하고 쉽게 네트워크 구성관리를 할 수 있어서 이쪽이 권고된다. 

 

※ 아래와 같이 link는 legacy 기능으로써 조만간 제거될 수 있다.

 

 

 

 

네트워크 상태 예시

 

 

도커를 설치한 직후 네트워크 상태

  • lo : 루프백 네트워크. 서버 자기 자신을 의미하며 물리적인 네트워크가 아닌 가상으로 생성된 네트워크이다. 
  • enp0s3 : 해당 서버의 물리적인 네트워크 포트. CentOS7 이전에는 eth0 이었으나, CentOS7 부터는 이러한 형식을 가진다. 
  • docker0 : 도커를 설치하고 생성된 가상 브릿지. 도커에서 생성된 컨테이너와 통신하며, 이 서버의 물리적 네트워크와 부릿지 되어 있다.

 

컨테이너 2개를 설치 후 네트워크 상태

nginx 와 centos 컨테이너 설치 되어 있다.

  • 2개의 가상 네트워크 장치가 생긴것을 볼 수 있다. 
  • 또한, 각 컨테이너는 eth0 을 가지고 있다. 
  • 바로 아래 " 참고" 에서 각각 컨테이너의 ip a 명령 결과를 확인할 수 있다.

 

가상 브릿지 docker0 와 컨테이너의 연결상태 

  • 그렇다면 각 컨테이너의 eth와 매핑되는 vethXXXXX은 어디에 연결되어 있을까? 
  • 호스트 서버에서 brctl show 명령을 사용하면, 가상 네트워크 interface가 어디에 연결되어 있는지 확인할 수 있다.

 

  • 호스트 서버에서 ip a를 쳤을 때 나온 vethXXXXX 2개가 docker0 와 연결되어 있는 것을 확인할 수 있다. 
  • docker0 외에 다른 가상 네트워크를 만들 수 있고, 다른 가상 네트워크에 다른 컨테이너들을 또한 연결할 수 있다. 
  • 물론 ip도 각 가상 네트워크마다 다른 대역으로 생성된다.

 

 

참고 : 각 컨테이너와 가상 네트워크 장치 파악

  • 어떤 가상 네트워크가 어떤 컨테이너의 네트워크인지 확인하려면 다음과 같이 확인할 수 있다. 
  • 아래 그림에서 새로 생긴 2개의 가상 네트워크 장치는 13번 항목의 if12로 끝나는 장치, 15번 항목의 if14로 끝나는 장치가 생성되어 있다.

각 컨테이너의 네트워크 정보는 다음과 같다.

 

8835bd89la60 : nginx 컨테이너, 12번 항목의 eth0@if13 을 가진다.
28485a9293db : CentOS 컨테이너, 14번 항목의 eth0@if15 를 가진다.

  • 즉, 컨테이너와 호스트 사이 서로 매핑되는 장치는 항목과 if값이 거꾸로 되어있다.
  • nginx 컨테이너의 12번 항목의 if13과 호스트 13번 항목의 if12가 일치하며, CentOS 컨테이너의 14번 항목의 if15와 호스트 1번 항목의 if14가 일치한다.

 

외부에서 컨테이너로 Network연결

 

  • 컨테이너는 기본적으로 docker0 브릿지 네트워크에 있으므로 호스트에서만 접근이 가능하다. 
  • 기본적으로 외부접근은 불가하다. 외부에 컨테이너 에플리케이션을 노출하기 위해서는 컨테이너의eth0의 ip와 포트를 host의 ip와 포트에 바인딩을 수행해야 한다. 
  • 컨테이너 실행 시 포트옵션으로 바인딩할 수 있다. 
  • 이러한 바인딩은 기술적으로 가상 브릿지 docker0와 호스트OS의 물리 NIC에서 패킷을 전송하는 장치가 필요하다.
  • 도커에서는 NAPT 기능을 사용하여 연결한다.

 

NAPT(Network Address Port Translation) 이란?

 

  • Private IP 를 Public IP로 변환하여 Pirvate IP가 외부에 연결할 수 있도록 하는 기술은 NAT, NAPT 두가지가 있다.
  • NAT는 단순히 Private IP를 변경하는 것이지만, NAPT는 Private IP와 함께 포트번호까지 함께 변환한다.
  • 따라서 하나의 Public 주소를 여러 개의 Private IP 주소로 변환할 수 있다.
  • NAPT는 이러한 기술의 이름으로써, LINUX에서 NAPT를 사용하는 것을 IP Masquerade 라고 부른다.
  • docker에서는 NAPT 기술을 사용하기 위해 LINUX의 iptables 프로그램을 사용한다.
  • ip 마스커레이드는 패킷의 소스 주소를 자체 공용 ip주소로 변경하면서 패킷을 전달하는 기능이다.
  • 브릿지에 연결된 컨테이너들은 private ip가 할당된다.
  • Private ip로는 인터넷 통신이 불가능 하기 때문에, 출발지 IP를 Public ip로 바꾸는 방법으로 인터넷 통신이 가능하게 한다.
  • 해당 패킷에 대한 응답을 받을 때는, 받을 대상으로써 자체 공용 ip주소가 응답을 받고, 그걸 다시 원래 호스트 주소로 수정하고 패킷을 전송한다. nat의 한 형태이다.

 

외부에서 컨테이너로 들어올 때 

  • 웹서버 컨테이너를 시작할 때 컨테이너 안의 웹서버가 사용하는 80번 포트를 호스트OS의 8080포트로 전송하도록 설정한다. 
  • 그러면 외부 네트워크에서 호스트OS의 8080포트로 접속하면, 컨테이너안의 80번 포트로 연결하게 된다.

 

컨테이너에서 외부로 나갈 때 

  • 192.168.0.1, 192.168.0.2 각각 컨테이너가 있고, NAT 54.10.10.1이 있다고 가정하자. 
  • 각 컨테이너가 외부로 나가려면 192.168.0.1 이 54.10.10.1 변환되어 할일을 다 한 후, 그 후에야 192.168.0.2가 54.10.10.1로 변환되어 할일을 할 수 있다. 
  • 하지만 NAT가 아니라 NAPT라면, 192.168.0.1:1500 포트로 NAPT 54.10.10.1 로 변환해서 나가고, 192.168.0.2:1501 포트가 NAPT 54.10.10.1로 변환해서 나갈 수 있다.

Docker-proxy

 

  • 컨테이너 포트를 외부로 노출하도록 설정하면, 도커 호스트에는 docker-proxy라는 프로세스가 자동으로 생성된다. 
  • Docker-proxy는 이름처럼 docker host로 들어온 요청을 container로 넘기는 것 뿐이다. 
  • Docker-proxy는 커널이 아닌 userland에서 수행되므로 kernel과 상관없이 host가 받은 패킷을 그대로 container의 포트로 넘긴다. 
  • 이렇게 외부로 binding 된 컨테이너가 있다면, 아래처럼 docker-proxy라는 프로세스가 생기며, 포트 LISTEN도 확인할 수 있다.

 

예를들어, -p 8080:80 옵션을 사용해서 컨테이너 포트를 오픈하면, docker-proxy가 생성되며, 8080포트를 리스닝하는것을 확인할 수 있다. 

root@~~# netstat -nlp | grep 8080 

tcp6 0 0 :::8080 :::* LISTEN 12581/docker-proxy

반응형