본문 바로가기

서버운영 (TA, ADMIN)/인프라

[인프라] 도커 네트워크

컨테이너 네트워크 모델 (CNI)


- Sandbox는 Container의 Network Stack을 의미한다 (ex. Interface, DNS, Routing Table, ...): 네트워크 물리 장비 역할

- Endpoint는 Sandbox를 Network에 Join(Attach) 해주는 역할을 한다.

- Network는 Group of Endpoint로 한 Group의 Endpoint 간에는 서로 통신할 수 있다.





시스템의 ifconfig가 나오는 인터페이스를 바로 Endpoint라고 한다. Endpoint는 실제 Docker Network라는 것이 있어서 Docker Network에 Attach되는 방식이다. 드라이버 종류가 많은데, 드라이버를 지정하여 네트워크를 생성하고 컨테이너를 띄울때 네트워크를 쓰겠다라는 설정이 있다면 해당 컨테이너는 자신의 Network Sandbox에서 Endpoint를 만들어 해당 네트워크에 Attach하는 네트워킹하는 방식이다.


1. 도커에서 네트워크를 생성한다.

2. 생성한 (혹은 미리 생성되어 있는) 네트워크를 사용하는 도커 컨테이너를 실행한다.

3. 같은 도커 네트워크를 사용하는 도커 컨테이너 간에는 통신이 가능하다.


도커 네트워크는 드라이버를 이용하여 생성하며 같은 드라이버로 여러개의 서로 다른 네트워크를 생성할 수 있다. 이때 기본 제공되는 드라이버는 bridge, host이다. (none은 네트워크를 사용하지 않는 것이다)


bridge 드라이버를 이용한 bridge network / host 드라이버를 이용한 host network 등이 존재한다.



Docker Network inspect

도커 컨테이너와 마찬가지로 inspect 명령을 사용하여 네트워크의 상세 정보를 알 수 있다. Subnet에서 컨테이너에 대한 IP를 할당해서 주고(하드웨어 스위치에 VLAN이 하나 잡혀있는 형태), Gateway는 논리적 Gateway 역할을 하는데, Subnet이나 Gateway 등등으로 하나의 Network Stack 만들어 지는 것이다.

[
    {
        "Name": "bridge",
        "Id": "...",
        "Created": "...",
        "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,
        "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": {}
    }
]



Bridge/Host 네트워크


bridge는 리눅스에서 제공하는 L2 기능 소프트웨어인데, bridge subnet에서 IP를 할당받은 컨테이너들은 서로 내부 통신이 가능한 상태(외부 통신은 불가)가 된다. 외부에서 네트워크 트래픽을 받고 싶다면, NAT를 활용하여 외부 8000번 포트로 들어오는 유입을 bridge 내부 특정 ip:port로 바인딩하면 가능해진다. 


 - 리눅스 커널의 소프트웨어 L2 스위칭 기술인 Linux Bridge를 사용한다.

 - 같은 Bridge 네트워크를 사용하는 컨테이너 간에는 통신이 가능하다.

 - 호스트의 Inbound 트래픽은 NAT (iptables)를 통해 노출한 Port를 통해 수신한다.


# bridge 네트워크를 사용하는 $DOCKER-1 컨테이너 설정

> docker run -d --network bridge --name $DOCKER-1


# bridge 네트워크를 사용하는 $DOCKER-2 컨테이너 설정

> docker run -d --network bridge --name $DOCKER-2


# $DOCKER-2 컨테이너의 IP 확인

> PEER=`docker inspect --format='{{.NetworkSettings.IPAddress}}'$DOCKER-2`

> echo $PEER


# $DOCKER-1 컨테이너로 접근하여 네트워크 테스트

> docker exec -it -e PEER=$PEER $DOCKER-1 /bin/bash

# 컨테이너에서 실행

> ping -w3 $PEER

> curl -v $PEER

> exit


# 생성한 컨테이너 삭제

> docker rm -f $DOCKER-1

> docker rm -f $DOCKER-2



host 네트워크의 경우는 network 네임스페이스를 따로 만들지 않고, 기존 호스트에서 쓰던걸 그대로 이용하는 것이다. 즉 호스트 네트워크를 사용하는 컨테이너들은 호스트와 네트워크 스택을 공유하게 된다.


따라서, 컨테이너간/컨테이너와 호스트간에 통신이 가능하다. 내가 legacy 변경하고 싶지있고, host 자체를 소수 인원만 사용하면 이용하기 편리하다. 호스트 네트워크를 그대로 이용하기 때문에 네트워크 오버헤드는 전혀 없다.


host가 한대가 아니라 여러대일때는 기본 제공하는 것이 Overlay Network를 이용하기도 한다. Bridge는 한 호스트내에 생성하여 쓰는 것이기 때문에 host가 여러개 있다면, 여러대들간의 통신이 어렵다. 이런경우는 Host Network를 쓰는것이 유리하고, Overlay의 경우 Bridge와 개념은 동일하지만, 컨테이너 컨테이너 간의 통신을 할때는 터널링(터널을 통해 L2 네트워크를 해결)을 통해서 사용하게 된다. 각각의 컨테이너들의 Load Balancer 같은 것이 연결이 되야 하는데. 이를 docker에서는 proxy를 제공하는 모듈 등을 이용하기도 하는데. 이는 따로 살펴보면 된다.


서비스에서 여러대를 두고 접속해서 쓰는 방식은 제각각인 부분이 있다. 솔루션(쿠버네티스/shipdock 등..)을 무엇을 쓰느냐 네트워크를 무엇을 쓰느냐에 따라 다르다. 이는 초급 레벨에서 다루기에는 난이도가 있다.




도커 볼륨


컨테이너를 내렸다 올리면 RW layer는 기본적으로 다 삭제가 된다. RW layer를 이미지로 저장한다면, docker run을 한다음에 commit을 하고 다시 push를 하면 다시 되긴 되나, 이미지 내용이 어디까지 잘 커밋이 되었는지에 대한 내용을 구체적으로 제공하지 않아. 자주 이용하는 방식이 볼륨을 만들고 그 볼륨 안에 데이터를 저장하는 방식을 가장 많이 이용한다. 즉, 나머지 영역은 그대로 두고 볼륨을 만들어 저장과 같은 행위는 볼륨을 대상으로 수행한다.


 - 도커 컨테이너를 시작할 때 도커 볼륨, 로컬 호스트의 디렉토리/파일, 메모리를 마운트 할 수 있다.

 - 도커 볼륨을 마운트하는 것을 volume 마운트라고 한다.

 - 로컬 호스트의 디렉토리/파일을 마운트 하는 것을 bind 마운트라고 한다.




docker logs: 컨테이너 프로세스의 STDOUT/STDERR를 "docker logs" 명령으로 조회할 수 있다.

docker stats: 컨테이너의 상태를 "docker stats" 명령으로 조회할 수 있다.