Docker 컨테이너 네트워크
Docker Network
Docker가 시작되면 docker0 이라는 이름의 virtual 인터페이스를 만들어 컨테이너와 호스트 머신이 통신합니다. private 범위에서 사용하지 않는 IP를 자동으로 선택해서 docker0 에 할당합니다. 자세한 내용은 Advanced networking - Docker Documentation 에 있습니다.
디폴트로 --net=bridge 옵션으로 실행되며, bridge로 통신합니다. --net=container:NAME_or_ID 옵션으로 다른 컨테이너에게 위임이 가능합니다. 이렇게 되면 첫 번째 컨테이너와 같은 IP주소, 포트를 공유하고, loopback 인터페이스로 통신이 가능합니다.
docker run 으로 컨테이너가 시작되면 docker0 의 IP주소공간에서 이 컨테이너의 IP가 할당됩니다. 그리고 docker0 과 연결된 veth* 인터페이스가 만들어지고 컨테이너에 할당됩니다. 컨테이너 쪽에서는 이게 eth0 으로 보입니다. 제가 이해한 통신 경로는 컨테이너1의 eth0 – veth* – docker0 – 호스트의 eth0 입니다.
--bip 옵션으로 docker0 의 IP주소범위를 지정 가능합니다 (github). Kubernetes(이하 k8s) 에서는 Docker를 실행할 때 DOCKER_OPTS="--bridge cbr0 --iptables=false" 이 옵션으로 실행합니다 (github). 여기서 cbr0 은 바깥으로 나가는 트래픽을 위한 NAT 역할만 하는 bridge입니다. bridge가 아니라 flannel 을 써서 docker0 끼리 직접 연결하는 구조도 가능한 듯합니다.
1개의 머신 내부 컨테이너 간 통신
Docker에서는 iptables을 사용합니다. EXPOSE 로 docker0 에 포트를 노출할 수 있습니다. docker run 할 때 --link 컨테이너이름:별명 옵션으로 다른 컨테이너와 연결할 수 있습니다 (docker). 이 옵션이 하는 일은 환경변수와 /etc/hosts 에 연결정보를 추가해 주는 일입니다. 환경변수 별칭_PORT 를 사용하여 연결할 수도 있고, /etc/hosts 를 사용하여 연결할 수도 있습니다. 저는 보통 link를 써야 할 일이 있으면 fig 를 사용합니다.
2개 이상의 머신에서 컨테이너 간 통신
각 호스트에 Ambassador Container를 만들고 ambassador 가 forward 하는 방법이 있습니다 (docker). 통신 경로는 아래와 같습니다.
(consumer) --> (redis-ambassador) ---network---> (redis-ambassador) --> (redis)
etcd 를 사용하는 방법도 있습니다 (coreos). 글을 제가 이해한 대로 짧게 요약하면, 서비스 제공자는 연결정보를 etcd에 쓰고, 서비스 소비자는 etcd에서 연결정보를 읽어서 서비스 제공자에 연결합니다.
Docker 전용 overlay network 를 구성하는 방법도 있습니다. 모든 컨테이너를 동일 네트워크에 있는 것처럼 구성하는 방식인데, weave 가 그렇고, k8s 도 이 방법을 사용합니다. 이것을 GCE가 아닌 다른 곳에서도 쓸 수 있게 만든 것이 coreos의 flannel 입니다.
coreos의 flannel
k8s를 위해 만들어진, 각 머신 별로 subnet 을 주기 위한 overlay network 입니다 (github). 지정한 IP주소 대역으로 각 호스트가 /24씩 잘라서 할당받습니다. 이 정보를 etcd에 저장하고 실제 IP와 매핑합니다.
google의 cAdvisor
Container Advisor 의 약자입니다. 구글이 공개했습니다. 실행 중인 컨테이너들의 자원 사용량과 성능 특이점을 수집하여 컨테이너 사용자에게 보여 주는 목적의 도구입니다 (github).
수집해서 정보를 보내는 역할의 cadvisor daemon을 docker container들이 돌아가는 machine에 띄우면, 해당 machine의 모니터링 정보와 해당 machine에서 돌아가는 docker container들의 정보를 웹UI (디폴트 8080포트) 와 REST API 로 알 수 있습니다.
raw 데이터와 가공된 통계 데이터를 REST API로 제공하고 (github), 공식 go client 라이브러리를 제공합니다 (github). k8s 에서는 디폴트로 실행되고 4194포트로 통신합니다 (google, github).
만약 machine에 8004 포트로 cadvisor를 올렸다면, 아래와 같은 REST API로 machine에서 실행 중인 docker containers 들의 cpu, network 등의 사용량을 알 수 있습니다.
$ curl http://localhost:8004/api/v1.2/docker
{
/docker/2f0fad0378402d0fdc2b4515ded4cca92232c2e6feec3febf27af1cfd97b9c51: {
...
aliases: [mysql_1, 2f0fad0378402d0fdc2b4515ded4cca92232c2e6feec3febf27af1cfd97b9c51]
stats: [
{ timestamp: ..., cpu: ..., memory: ..., network: ...}
...
]
}
/docker/602b7986fc363dab0c924acfef7ed9f2ed8c88fa7fed7fda28c98cd5b2ab4aa4: { ... }
/docker/a73c6c51a9f7131130af31c1006ea880566a44987cc74473f3f09c8fd1b490f2: { ... }
}