도커 네트워크 구조
도커는 컨테이너에 내부 IP를 순차적으로 할당하는데, 이 IP는 컨테이너를 재시작할 때마다 변경될 수 있다.
이 내부 IP는 도커가 설치된 호스트, 즉 내부 망에서만 쓸 수 있는 IP이므로 외부와 연결되어야 한다.
도커는 각 컨테이너에 외부와의 네트워크를 제공하기 위해 컨테이너마다 가상 네트워크 인터페이스를 호스트에 생성하는데 이름이 veth로 시작한다.
veth 인터페이스는 사용자가 직접 생성할 필요는 없으며 컨테이너가 생설될 때 도커 엔진이 자동으로 생성한다.
도커가 설치된 호스트에서 ifconfig나 ip addr과 같은 명령어로 네트워크 인터페이스를 확인하면 실행 중인 컨테이너 수만큼 veth로 시작하는 인터페이스가 생성된 것을 확인할 수 있다.
$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
...
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
...
veth05c082e: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
...
docker0은 각 veth 인터페이스와 바인딩돼 호스트의 eth0 인터페이스와 이어주는 브릿지 역활을 한다.
eth0은 공인 IP 또는 내부 IP가 할당되어 실제로 외부와 통신할 수 있는 호스트의 네트워크 인터페이스다.
출력 결과 컨테이너의 eth0 인터페이스는 호스트의 veth로 시작하는 인터페이스와 연결됐으며 veth 인터페이스는 docker0 브리지와 바인딩돼 외부와 통신할 수 있다.
도커 네트워크 기능
컨테이너를 생성하면 기본적으로 docker0 브리지를 통해 외부와 통신할 수 있는 환경을 사용할 수 있지만 사용자의 선택에 따라 여러 네트워크 드라이버를 쓸 수도 있다.
도커 자체적으로 제공하는 드라이버는 브리지(bridge), 호스트(host), 논(none), 컨테이너(container), 오버레이(overlay)가 있다.
서드파티(third-party) 플러그인 솔루션으로 더 확장된 네트워크 구성을 구축할 수 도 있다.
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
2b8eafae3d91 bridge bridge local
64163d0b6165 host host local
21cb34f62ad6 none null local
네트워크 목록을 출력해보면 이미 브리지, 호스트, 논 네트워크가 존재함을 알 수 있다.
브리지 네트워크는 컨테이너를 생성할때 자동으로 연결되는 docker0 브리지를 활용하도록 설정되있다.
$ docker network inspect bridge
...
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
...
브리지 네트워크 상세 정보를 확인해보면 Config 항목의 서브넷과 게이트웨이가 172.17.0.0/16과 172.17.0.1로 설정되있다.
Containers 항목에는 현재 브리지 네트워크를 사용하는 컨테이너를 확인할 수 도 있다.
브리지 네트워크
컨테이너는 연결된 브리지를 통해 외부와 통신할 수 있다.
기본적으로 존재하는 docker0을 사용하는 브리지 네트워크가 아닌 새로운 브리지 타입의 네트워크를 생성할 수 있다.
$ docker network create --driver bridge mybridge
5cd58d8f85b3e977c225520ca26fdc04e4f6ca19df718e87a5cf99e93ee8c123
$ docker network inspect mybridge
...
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
...
도커 컨테이너를 실행할때 --net 옵션의 값을 설정하면 해당 네트워크를 사용할 수 있다.
$ docker run -d --name ubuntu -it --net mybridge ubuntu:20.04
$ docker exec -it ubuntu bash
$ root@cd88e44a93c2:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.19.0.2 ....
컨테이너 내부에서 ifconfig 명령어를 입력해보면 172.19 대역의 내부 IP가 할당된것을 확인할 수 있다.
connect, disconnect 명령어로 유동적으로 연결하고 연결을 해제할 수 있다.
$ docker network disconnect mybridge ubuntu
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cd88e44a93c2 ubuntu:20.04 "bash" 8 minutes ago Up 8 minutes ubuntu
$ docker network connect mybridge ubuntu
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cd88e44a93c2 ubuntu:20.04 "bash" 9 minutes ago Up 9 minutes 0.0.0.0:22->22/tcp ubuntu
네트워크의 서브넷, 게이트웨이, IP 할당 범위 등을 임의로 설정하려면 --subnet, --gateway, --ip-range 옵션을 사용하면 된다.
단 --subnet과 --ip-range는 같은 대역이여야 한다.
호스트 네트워크
네트워크를 호스트로 설정하면 호스트의 네트워크 환경을 그대로 사용할 수 있다.
호스트 드라이버의 네트워크는 별도로 생성할 필요 없이 기존에 host 네트워크를 사용하면 된다.
$ docker run -d --name ubuntu -it --net host ubuntu:20.04
컨테이너 내부에서 ifconfig 명령어로 확인해보면 실제 호스트와 같은 네트워크가 출력된다.
컨테이너의 네트워크를 호스트 모드로 설정하면 컨테이너 내부의 애플리케이션을 별로의 포트 포워딩 없이 바로 서비스할 수 있다.
실제 호스트에서 애플리케이션을 외부에 노출하는 것과 같다.
논 네트워크
none은 말 그대로 아무런 네트워크를 쓰지 않는 것이다.
$ docker run -d --name ubuntu -it --net none ubuntu:20.04
위와 같이 컨테이너를 생성하면 외부와 연결이 단절된다.
컨테이너 내부에서 ifconfig 명령어로 확인해보면 로컬호스트를 나타내는 lo 외에는 존재하지 않는다.
컨테이너 네트워크
컨테이너 네트워크는 다른 컨테이너의 네트워크 네임스페이스 환경을 공유할 수 있다.
내부IP, 네트워크 인터페이스의 맥(MAC) 주소 등의 속성이 공유된다.
--net 옵션의 값으로 container:<컨테이너명>와 같이 입력하면 된다.
$ docker run -d -it --name bridge_ubuntu --net mybridge ubuntu:20.04
$ docker run -d -it --name container_ubuntu --net container:bridge_ubuntu ubuntu:20.04
$ docker exec -it bridge_ubuntu bash
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.19.0.2 netmask 255.255.0.0 ...
$ docker exec -it container_ubuntu bash
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.19.0.2 netmask 255.255.0.0 ...
두 컨테이너의 eth0 정보가 완전히 같은 것을 확인할 수 있다.
브리지 네트워크와 --net-alias
브리지 타입의 네트워크와 run 명령어의 --net-alias 옵션을 사용하면 특정 호스트 이름으로 컨테이너 여러 개의 접근할 수 있다.
$ docker run -d -it \
--name ubuntu1 \
--net mybridge \
--net-alias mybridge_alias \
ubuntu:20.04
$ docker run -d -it \
--name ubuntu2 \
--net mybridge \
--net-alias mybridge_alias \
ubuntu:20.04
$ docker run -d -it \
--name ubuntu3 \
--net mybridge \
--net-alias mybridge_alias \
ubuntu:20.04
$ docker inspect ubuntu1 | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.2",
$ docker inspect ubuntu2 | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.3",
$ docker inspect ubuntu3 | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.19.0.4",
inspect 명령어로 각 컨테이너의 IP를 확인해보면 172.19 대역의 IP인것을 확인할 수 있다.
$ docker run -d -it --name ubuntu4 --net mybridge ubuntu:20.04
$ docker exec -it ubuntu4 bash
$ root@9c31d48a0152:# ping -c 1 mybridge_alias
PING mybridge_alias (172.19.0.2) 56(84) bytes of data.
...
$ root@9c31d48a0152:/# ping -c 1 mybridge_alias
PING mybridge_alias (172.19.0.3) 56(84) bytes of data.
...
$ root@9c31d48a0152:/# ping -c 1 mybridge_alias
PING mybridge_alias (172.19.0.4) 56(84) bytes of data.
...
또 다른 컨테이너에 접속해 위에서 설정한 alias로 핑을 보내보면 각각 172.19.0.2, 172.19.0.3, 172.19.0.4로 전송된 것을 확인할 수 있다.
매번 달라지는 IP를 경정하는 것은 별도의 알고리즘이 아닌 라운드 로빈(round-robin)방식 이다.
이것이 가능한 이유는 도커 엔진에 내장된 DNS가 mybridge_alias라는 호스트 이름을 --net-alias 옵션으로 mybridge_alias을 설정한 컨테이너로 변환하기 때문이다.
dig 명령어를 사용하면 해당 alias가 변환되는 IP를 확인할 수 있다.
$ root@9c31d48a0152:/# apt-get install dnsutils
$ root@9c31d48a0152:/# dig mybridge_alias
...
;; ANSWER SECTION:
mybridge_alias. 600 IN A 172.19.0.4
mybridge_alias. 600 IN A 172.19.0.3
mybridge_alias. 600 IN A 172.19.0.2
...
도커의 DNS는 --link 옵션처럼 호스트 이름으로 유동적인 컨테이너를 찾을 때 주로 사용한다.
'Docker & Kubernetes' 카테고리의 다른 글
도커 컨테이너 로깅(Docker Container Logging) (0) | 2022.12.27 |
---|---|
도커 명령어 정리 (0) | 2022.12.27 |
도커 볼륨(Docker Volume) 활용하기 (2) | 2022.12.27 |
Jenkins + Docker + Nginx 무중단 자동화 배포하기(Centos) (0) | 2022.07.24 |
Centos Docker 컨테이너 내부에 Docker 설치하기 (0) | 2022.07.22 |