Network Driver
Docker를 설치한 후 Docker host의 Network interface를 확인해보면 아래와 같이 docker0이란 interface가 생성되어 있습니다.
$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:6c:89:b0:94 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
$ docker network inspect ee5030326ef9
[
{
"Name": "bridge",
"Id": "ee5030326ef98cbdbe866144b45b25d291e36ef279e6b338afaabffabf68d51f",
"Created": "2022-11-10T09:30:58.516776372Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"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": {}
}]
이 드라이버는 docker의 default network인 bridge입니다. 드라이버를 지정하지 않으면 기본적으로 이 브리지 드라이버가 연결됩니다. default network는 172.17.0.0/16 대역을 가지고 있어 따로 네트워크를 지정해주지 않고 생성한 컨테이너가 해당 대역을 가지게 되는 것입니다. 그리고 이는 컨테이너가 외부와 통신할 수 있게 합니다.
실제로 alpine 컨테이너를 하나 띄워보면 해당 네트워크에 172.17.0.2/16 대역을 가진 컨테이너가 차례대로 할당되는 모습을 볼 수 있습니다.
$ docker run -d --name alpine2 alpine:latest tail -f /dev/null
$ docker network inspect ee5030326ef9
[
{
"Name": "bridge",
"Id": "ee5030326ef98cbdbe866144b45b25d291e36ef279e6b338afaabffabf68d51f",
"Created": "2022-11-10T09:30:58.516776372Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"844f442a86b31a23012017217821786c189a059c89f50883793d226e40193530": {
"Name": "alpine2",
"EndpointID": "2fc801ef9904ac709469c41ea707c9479827e0ec6919bacbf1e8c826571648c6",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"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": {}
}
]
이와 같이 docker의 네트워크 드라이버에는 아래와 같은 여러 가지 종류가 있습니다.
- bridge : 기본 네트워크 드라이버로, 일반적으로 사용되는 드라이버입니다. 기본 브리지 말고도 사용자가 직접 정의해서 연결할 수도 있으며 이는 후에 docker network - bride 편에서 자세히 다루겠습니다.
- host : host는 말 그대로 docker host의 networking을 사용하는 것으로, 후설 할 iptables의 network isolation을 제거하고 사용합니다.
- overlay : docker demon들을 연결하고 컨테이너 간의 통신을 가능하게 합니다. 보통 swarm에서 많이 쓰입니다.
- ipvlan : IPvlan은 기본 인터페이스인 eth0의 하위 인터페이스에서 제공되어 물리적인 연결로 아주 가볍습니다.
- macvlan : mac 주소를 컨테이너의 VNIC(Virtual Network Interface Card)에 연결하여 Docker demon은 MAC 주소로 트래픽을 라우팅 합니다.
- none : 네트워킹을 비활성화합니다.
docker network ls를 통해 도커의 네트워크들을 볼 수 있습니다.
docket network ls
NETWORK ID NAME DRIVER SCOPE
ee5030326ef9 bridge bridge local
d08d819aeb7f host host local
e1cf6408e31b none null local
위와 같이 local에 기본적으로 bridge, host, none 네트워크가 존재합니다. user-defined docker network을 생성하기 위해
아래와 같이 docker network create {network-name}을 통해 도커 네트워크를 정의할 수도 있습니다.
$ docker network create -d bridge define-network
78456876d229390bfb84836ee1f443c8a6324351f01340e6af08a12f28706710
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
ee5030326ef9 bridge bridge local
78456876d229 define-network bridge local
d08d819aeb7f host host local
e1cf6408e31b none null local
그리하여 전체적인 구조를 그려보자면 아래와 같은 형상이 됩니다.
default network(docker0) 아래서 veth(Virtual Ethernet Device)가 컨테이너의 eth0 인터페이스와 쌍으로 생성되게 됩니다.
my_bridge와 같이 user-define network를 만들어 붙일 수도 있습니다.
iptables
Docker에서 Network isolation(네트워크 격리)을 위해 iptables를 조작합니다. Docker를 설치하면 DOCKER와 DOCKER-USER라는 두 개의 iptables Chain(규칙)이 생성됩니다. 컨테이너로 가는 트래픽은 가장 우선적으로 이 DOCKER & DOCKER-USER chain을 지나갑니다. DOCKER-ISOLATION-STAGE와 같은 chain은 docker에서 자동적으로 생성되며, 위 두 체인에 종속되기 때문에 이를 바꾸어주기 위해서는 DOCKER-USER chain을 건드려야 합니다.
기본적으로는 모든 외부 ip는 docker host에 연결할 수 있는데요. 이를 특정 네트워크만 컨테이너에 액세스 할 수 있도록 허용하려면 아래와 같이 체인에 deny rule을 넣어줘야 합니다.
& iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.1 -j DROP
그러면 192.168.1.1을 제외한 모든 컨테이너로 향하는 패킷이 드랍됩니다. -m iprange--src-range--dst-range와 같이 사용해 ip를 대역 단위로 지정할 수도 있습니다.
etc..
이러한 container network를 더 깊게 이해하려면 CNM(Container Network Model)를 살펴봐야 합니다. libnetwork라는 구현체는 docker 등 driver & plugin 모델을 제공하여 일관된 네트워크 모델을 컨테이너 런타임에 지원합니다. 도커 또한 libnetwork를 활용하여 네트워킹을 지원합니다. 아래는 libnetwork의 github 주소입니다.
GitHub - moby/libnetwork: networking for containers
networking for containers. Contribute to moby/libnetwork development by creating an account on GitHub.
github.com