카테고리 없음

Docker Network

pioneerxj 2023. 9. 10. 13:28

$ sudo yum update -y
$ sudo yum install docker -y
$ sudo -i 
$ sudo systemctl start docker
$ ifconfig docker0

docker가 설치되면 docker0 인터페이스가 자동으로 설치된다.

1. docker0 interface 특징

  • IP는 자동으로 172.17.0.1로 설정되며 16bit netmask(255.255.0.0)로 설정
  • 이 IP는 DHCP를 통해 할당 받는 것은 아니며, docker 내부 로직에 의해 자동 할당 받음
  • docker0는 일반적인 interface가 아니며, virtual ethernet bridge

docker0는 container가 통신하기 위한 가상 linux bridge이다. bridge는 기본적으로 L2 통신 기반이며, 만약 container가 하나 생성되면 이 bridge에 container의 interface가 하나씩 binding되는 형태이다. 따라서 container가 외부로 통신할 때 docker0 interface를 지나야 한다. 위에서 docker가 설치 되면 이름이 docker0라는 bridge가 생성되며, container가 running 될 때마다 vethXXXX 라는 이름의 interface가 attach되는 형태이다.

 

또한, docker0의 IP는 자동으로 172.17.0.1로 설정되며, subnet mask는 255.255.0.0 즉, 172.17.0.0/16으로 설정된다. 이 subnet정보는 앞으로 container가 생성될 때 할당 받게 될 IP의 range를 결정한다. 즉, 모든 container는 172.17.XX.YY 대역에서 IP를 하나씩 할당받는다.

 

container를 생성하면 container는 각자만의 격리된 network 공간을 할당 받는다. 이는 linux namespace 기술을 이용하여 구현된 가상화 기법을 사용하여 각자 독립된 network 공간을 할당 받는 것이다. 이 container마다 독립된 공간은 어떻게 외부로(또는 다른 container로) 통신을 주고받는가? 만약 container가 생성되면, 해당 container 는 pair interface라는 한 쌍의 interface가 생성된다.

 

pair(peer) inferface는 두개의 interface가 한 쌍으로 구성되는데, 이 둘은 마치 직접 direct로 cable을 연결한 두 대의 PC와 같이 서로의 packet을 주고받는 형태이다. container가 생성되면, 이 pair interface의 한 쪽은 container 내부 namespace에 할당되며 eth0라는 이름으로 할당된다. 그리고 나머지 하나는 vethXXXX 라는 이름으로 docker0 bridge에 binding되는 형태이다.

위와 같이 vethXXXX 형태의 interface가 docker0 bridge에 binding된 상태로 생성된 것을 볼 수 있으며 container 내부에 할당된 eth0 인터페이스가 보이지 않는 이유는 해당 namespace에서만 보이도록 격리 되어 있기 때문이다.

 

2. Docker Network 구조

Container Network 방식에는 4가지가 있다.

아래의 driver로 구분된 3가지와 별도로 생성한 컨테이너 네트워크이다.

$ docker network ls
#$ docker run --net mynet1

 

1) bridge

docker의 기본 network방식은 bridge이다. docker daemon을 실행하면 먼저 docker0 라는 bridge가 생성된다.

컨테이너가 생성되면, 각 컨테이너마다 고유한 network namespace영역이 하나씩 생성되며
이때 docker0 bridge에 container의 인터페이스들이 하나씩 binding되는 구조이다.

 

$ docker network create --driver bridge --subnet 172.16.1.0/16 --ip-range 172.16.1.0/24 --gateway=172.16.1.1 vswitch01
$ docker network ls

$ docker run --name centos1 --hostname centos1 --network vswitch01 -itd centos
$ docker run --name centos2 --hostname centos2 --network vswitch01 -itd centos
$ docker ps
$ docker exec -it centos1 /bin/bash
[root@centos1 /]# ping -c3 centos2
exit
$ docker exec -it centos2 /bin/bash
[root@centos2 /]# ping -c3 centos1
exit

$ docker network inspect vswitch01

 

2) host

host 방식으로 컨테이너를 생성하면, 컨테이너가 독립적인 네트워크 영역을 갖지 않고 host와 네트워크를 공유해서 사용한다.

$ docker run --name centos3 --hostname centos3 --network host -itd centos
$ docker ps
$ docker exec -it centos3 ip a

$ docker exec -it centos3 ping -c3 8.8.8.8
$ docker network inspect host

 

3) container

이 방식으로 생성된 컨테이너는 기존에 존재하는 다른 컨테이너의 network 환경을 공유하며 생성시 옵션으로

--net=container:CONTAINER_ID를 사용한다.

 

centos1의 ID를 사용하여 centos4 컨테이너를 생성

$ docker ps
$ docker run --name centos4 --net=container:45693b3c1390 -itd centos
$ docker ps
$ docker inspect centos4

 

4) none

--net=none 옵션으로 컨테이너를 생성하면 격리된 네트워크 영역을 갖긴 하지만, 인터페이스가 없는 상태로 컨테이너를 생성하게 된다.

$ docker run --name centos5 --net=none -dit centos
$ docker exec -it centos5 /bin/bash
$ ip a

 

Overlay Network

여러 Docker demons을 서로 연결하여 swarm 서비스가 서로 통신한다.
여러 대의 서버(물리적으로 네트워크 분리되어 ip가 다른)에서 실행된 container간 통신이 가능하다.
Overlay에 연결된 컨테이너같은 subnet에 묶여 서로 간 안전하게 통신

 

컨테이터 포트를 외부로 노출하기

docker run --name nginx -d -p 8080:80 nginx
오른쪽 8080이 호스트의 포트번호이고 왼쪽 80이 컨테이너 포트번호이다.
호스트의 8080포트를 컨테이너의 80포트와 연결한다는 의미이다.
이 8080 포트를 listen하고 있는 프로세스는 docker-proxy이다.

 

docker-proxy

이 프로세스의 목적은 docker host로 들어온 요청을 container로 넘기는 것이다. docker-proxy는 kernel이 아닌 사용자영역에서 수행되기 때문에 kernel 과 상관없이 host가 받은 패킷을 그대로 container의 port로 넘긴다. Container를 시작할 때 port를 외부로 노출하도록 설정하면, docker host에는 docker-proxy 라는 프로세스가 생성된다.

$ docker run --name nginx -d -p 8080:80 nginx
$ ps -aux | grep docker-proxy

docker-proxy 프로세스는 container의 port를 노출하도록 설정한 수만큼 추가로 생성된다 (run process per port).

만약 하나의 Port를 오픈하는 두개의 Container를 생성한다면 docker-proxy는 두개가 생성된다.

또한, 한개의 container 에 두개의 port 에 대해 외부로 노출하도록 설정한다면, 마찬가지로 docker-proxy 프로세스는 두개가 생성된다.

docker-proxy가 존재하는 가장 큰 이유는, docker host가 iptables 의 NAT를 사용하지 못하는 상황에 대한 처리이다.

만약 정책상의 이유로 docker host의 iptables나 ip_forward를 enable 하지 못하는 경우에는

docker-proxy 프로세스가 패킷을 포워딩하는 역할을 대신하게 된다.

하지만, 실제로는 docker host로 요청이 들어온 패킷이 container로 전달되는 것은

docker-proxy 와 무관하게 docker host의 iptables에 의해 동작된다. 

즉, docker-proxy 프로세스를 kill 해도 외부에서 들어오는 요청이 container로 전달되는데 문제가 없다는 의미이다.