일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- vgw
- cognito
- DynamoDB
- transit gateway
- JavaScript
- AWS
- On-Premise
- Endpoints
- Proxy Resource
- 단축 평가
- api gateway
- docker swarm
- Custom Resource
- elasticsearch
- docker
- 비구조화 할당
- Service
- 옵셔널 체이닝
- grafana
- Await
- VPC
- prometheus
- 자바스크립트
- CloudFormation
- Kubernetes
- null 병합 연산자
- optional chaining
- 구조분해 할당
- 온프레미스
- Site-to-Site VPN
- Today
- Total
만자의 개발일지
[Docker] Docker Network (docker0와 veth) 본문
Docker Network
컨테이너를 생성하게 되면 컨테이너는 NET namespace라는 기술을 통해 구현된 가상화 기법을 사용하여 각자 독립된 네트워크 공간을 할당 받습니다. 그렇다면 이 독립된 네트워크 공간을 가진 컨테이너는 어떻게 외부와 통신되고 컨테이너간의 통신이 가능한 걸까요?
NET namespace
Network interface, iptables 등 네트워크 리소스와 관련된 정보를 분할하여 각각 다른 namespace에 할당한다.
Docker Network 구조
도커의 동작을 이해하기 위해서는 우선 도커 네트워크의 구조부터 이해해야 합니다.
도커 네트워크는 다음과 같은 구조로 이루어져 있습니다.
컨테이너를 생성하면 컨테이너는 호스트와 통신하기 위한 eth0라는 네트워크 인터페이스를 할당받습니다. 이때 동시에 호스트에도 veth(virtual ethernet)라는 네트워크 인터페이스가 할당되고 컨테이너에 할당된 eth0 인터페이스와 통신하게 됩니다. 호스트에 할당된 veth 인터페이스는 docker0와 바인딩되고 docker0는 호스트의 eth0 인터페이스와 연결되어 외부로부터 들어온 요청을 처리합니다.
docker0와 veth
대충 구조는 알았으니 이제 도커가 구체적으로 어떻게 외부와 통신할 수 있는지에 대해 알아보도록 합시다. 그 중심에는 바로 docker0와 veth가 있습니다.
docker0
docker0는 호스트의 eth0 네트워크 인터페이스와 직접적으로 연결되는 네트워크 인터페이스입니다.
도커를 설치하면 도커 내부 로직에 의해 자동으로 IP를 할당받게 되는데, 이는 172.17.x.x로 시작하며 netmask는 255.255.0.0으로 설정됩니다.
docker0 인터페이스는 호스트의 eth0 인터페이스와 컨테이너의 eth0 인터페이스 사이의 중재자 역할을 하는 가상의 브릿지이며, 컨테이너가 생성되면 컨테이너 내부에 할당되는 eth0 인터페이스와 호스트에 할당되는 veth 인터페이스가 연결되고 docker0에 veth 인터페이스가 바인딩됩니다.
도커를 설치한 후 ifconfig를 통해 확인해보면 docker0라는 이름의 네트워크 인터페이스가 생성된 것을 확인하실 수 있습니다.
$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:1ff:fe49:e168 prefixlen 64 scopeid 0x20<link>
ether 02:42:01:49:e1:68 txqueuelen 0 (Ethernet)
RX packets 1946 bytes 770155 (752.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 564 bytes 44678 (43.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
또한 도커를 설치하면 기본적으로 생성되는 브릿지 네트워크의 정보를 확인해보면 bridge.name이 docker0로 되어있고, docker0의 IP와 기본 브릿지 네트워크의 Gateway IP가 일치하는 것을 보실 수 있습니다. 이를 통해 기본 브릿지 네트워크가 Gateway로 docker0 인터페이스를 사용한다는 사실을 확인할 수 있습니다.
$ docker network inspect bridge
[
{
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
.
.
.
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
따라서 컨테이너가 기본 브릿지 네트워크를 사용하는 경우 외부로 통신할 때에는 무조건 docker0 인터페이스를 거쳐야 합니다.
그렇다면 docker0는 외부에서 들어오는 요청을 어떻게 처리할까요?
도커는 호스트의 iptables를 통해 외부에서 들어오는 요청을 관리합니다. 예시를위해 포트 포워딩이 활성화 되있는 컨테이너와 비활성화 되있는 컨테이너를 각각 한개씩 실행시켜주었습니다.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
37cca9fb3b3a nginx "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 80/tcp nginx
05d19d18ceab gcr.io/cadvisor/cadvisor:latest "/usr/bin/cadvisor -…" 4 hours ago Up 6 minutes (healthy) 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp cadvisor
iptables을 확인해보면 다음과 같이 규칙이 추가된 것을 볼 수 있습니다. 포트 포워딩이 활성화된 컨테이너에 대해서는 iptables에 규칙이 추가되었지만 비활성화된 컨테이너는 규칙이 추가되지 않은 것을 보실 수 있습니다.
$ iptables -S
.
.
.
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -o docker_gwbridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker_gwbridge -j DOCKER
-A FORWARD -i docker_gwbridge ! -o docker_gwbridge -j ACCEPT
-A FORWARD -i docker_gwbridge -o docker_gwbridge -j DROP
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -j ACCEPT <-- 이 부분!
.
.
.
위 규칙을 쉽게 해석해보자면 호스트에 tcp, 8080번 포트로 요청이 들어오는 경우 docker0 인터페이스를 거쳐서 172.17.0.2로 요청을 전달해! 라는 뜻입니다.
이처럼 도커는 포트 포워딩이 활성화된 컨테이너를 생성하면 iptables에 규칙을 추가하고 해당 규칙을 통해 외부에서 들어오는 요청을 처리합니다.
veth
컨테이너를 실행하게 되면 호스트에 veth 인터페이스가 할당됩니다. veth(virtual ethernet) 인터페이스는 가상의 네트워크 인터페이스로, 자신과 연결된 컨테이너의 네트워크 인터페이스와 패킷을 주고받는 식으로 동작합니다.
이는 사용자가 직접 생성할 필요없이 도커가 자동으로 생성해주며, veth 인터페이스는 항상 쌍으로(pair)로 생성됩니다.
하나는 vethxxxx라는 이름으로 호스트에 생성되며 docker0에 바인딩 되는 형식이고, 하나는 컨테이너 내부에 eth0 라는 이름으로 생성되어 veth 인터페이스와 연결되는 방식입니다.
호스트에 컨테이너가 한개도 실행중이지 않은 경우 실제로 docker0에 veth가 바인딩되지 않는 것을 볼 수 있습니다.
$ brctl show docker0
bridge name bridge id STP enabled interfaces
docker0 8000.02420149e168 no
그렇다면 호스트에 컨테이너가 실행중이라면 어떻게 될까요?
임시로 컨테이너 하나를 실행시켜 주었습니다.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
05d19d18ceab gcr.io/cadvisor/cadvisor:latest "/usr/bin/cadvisor -…" 4 hours ago Up 2 seconds (health: starting) 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp cadvisor
그리고 다시 docker0를 확인해보면 veth 인터페이스 하나가 바인딩된 것을 보실 수 있습니다.
$ brctl show docker0
bridge name bridge id STP enabled interfaces
docker0 8000.02420149e168 no veth9159bb2
하지만 veth 인터페이스는 쌍으로 생성된다고 했습니다. 컨테이너 내부에도 네트워크 인터페이스가 할당되었는지 확인해 봅시다.
컨테이너 내부에서 ifconfig 명령어로 네트워크 인터페이스 목록을 출력해보니 eth0 이라는 이름의 네트워크 인터페이스가 할당된것을 보실 수 있습니다.
또한 eth0 인터페이스의 IP주소는 호스트의 내부 IP로, 기본 브릿지 네트워크의 Subnet CIDR 대역에 포함되는 것을 보실 수 있습니다.
$ ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:38 errors:0 dropped:0 overruns:0 frame:0
TX packets:91 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3146 (3.0 KiB) TX bytes:7512 (7.3 KiB)
이처럼 같은 브릿지 네트워크에서 생성된 컨테이너들은 같은 CIDR 대역에 포함되는 IP를 할당받기 때문에 마치 하나의 네트워크에 있는 것처럼 동작하는 것입니다. 따라서 같은 기본 브릿지 네트워크에서 생성된 컨테이너들은 docker0를 통해 서로간의 통신이 가능하게 됩니다.
참고
'Docker' 카테고리의 다른 글
[Docker] Docker Stack이란? (0) | 2022.08.02 |
---|---|
[Docker] WARNING: bridge-nf-call-iptables is disabled 해결 방법 (0) | 2022.08.01 |
[Docker] WARNING: IPv4 forwarding is disabled 해결 방법 (0) | 2022.08.01 |
[Docker] Docker Swarm Worker Node에만 서비스 배포하기 (0) | 2022.07.28 |
[Docker] Docker Swarm host mode로 서비스 생성하기 (0) | 2022.07.27 |