도커 네트워킹 다루기

[목표]

Dokcer 컨테이너 및 서비스가 서로 연결하고 통신할 수있도록 한다.

네트워크 드라이버 종류

  • bridge network : 기본 네트워크 드라이버. 동일한 Docker 데몬 호스트에서 실행되는 컨테이너에 적용되며, 다른 Docker 데몬 호스트에서 실행되는 컨테이너 간 통신의 경우 OS 수준에서 라우팅을 관리하거나 오버레이 네트워크를 사용해야한다.
  • host network : standalone형 컨테이너의 경우 컨테이너와 Docker 호스트 간의 네트워크 격리를 제거하고 호스트의 네트워킹을 직접 사용.
  • overlay network : 여러 Docker 데몬을 함께 연결하여 스웜에서 서비스가 서로 통신 할 수 있게한다. 또한 오버레이 네트워크를 사용하여 [스웜 서비스와 standalone 컨테이너 간] 또는 [서로 다른 Docker 데몬에 있는 두 개의 standalone 컨테이너간] 통신을 가능하게 한다.
  • macvlan : 컨테이너에 MAC주소를 할당하여 네트워크의 물리적인 장치로 나타낼 수 있게한다.

브릿지 네트워킹

동일한 Docker 호스트에서 두 개의 다른 컨테이너를 실행시키고 서로 통신하기

  1. 현재 docker network 살펴보기

    docker network ls
    

    가장 기본적으로 생성되어있는 네트워크 bridge, host, none이 보인다.

  2. alpine 컨테이너를 두개 실행시킨다.

    docker run -d -i -t --name alpine1 alpine ash
    docker run -d -i -t --name alpine2 alpine ash
    

    컨테이너가 작동중인지 확인한다.

    docker container ls
    
  3. 브릿지 네트워크에 연결된 컨테이너가 있는 확인한다.

    docker network inspect bridge
    

    containers를 보면 현재 alpine1, alpine2가 따로 설정한적 없지만 연결되어 있는 모습이 보이고 각각에 부여된 IP주소와 상단 부분에 네트워크의 서브넷과, 게이트웨이가 보인다.

  4. docker attach 명령어를 통해 alpine1 컨테이너에 연결한다

    docker attach alpine1
    

    ip addr show 명령어를 사용하여 alpine1 컨테이너의 네트워크 인터페이스를 표시한다.

    ip addr show
    
  5. alpine1에서 google.com으로 핑을 날려볼 것이다.

    ping -c 2 google.com
    
  6. 다음으로 두번째 컨테이너인 alpine2(172.17.0.3)쪽으로 핑을 날려본다.

    ping -c 2 172.17.0.3
    

    이번에는 아이피가 아닌 alpine2 이름으로 핑을 날려본다.(실패하는게 정상)

    ping -c 2 alpine2
    
  7. ctrl + p ,ctrl + q 를 통해 alpine1 컨테이너를 중지시키지 않고 빠져나와, alpine2에 접속하여 위의 과정들을 다시해봐도 좋다.

  8. 두 개의 컨테이너를 중지시키고 제거한다.

    docker container stop alpine1 alpine2
    docker container rm alpine1 alpine2
    

도커에서는 브릿지 네트워크를 production환경으로는 추천하지 않는다라고 하고있다.

user-defined 브릿지 네트워크

이번에는 디폴트 네트워크(NAME=bridge)가 아닌 우리가 만들어낸 alpine-net네트워크에 컨테이너들을 시작할것이다. 또 bridge네트워크에도 컨테이너를 하나 생성한 후 두 개의 네트워크들을 살펴본다.

  1. alpine-net네트워크 만들기

    docker network create --driver bridge alpine-net
    
  2. 네트워크가 생성되었는지 확인해본다.

    docker network ls
    
    docker network inspect alpine-net
    

    여기서 보아야 하는 것은 게이트웨이의 주소이다. 전의 디폴트 네트워크의 게이트웨이 주소는 172.17.0.1이였고, 현재는 바뀐것을 알수있다.

  3. 컨테이너를 생성해보자. 또 docker network connect명령어를 통해서 alpine4를 브릿지 네트워크에 연결한다.

    docker run -dit --name alpine1 --network alpine-net alpine ash
    docker run -dit --name alpine2 --network alpine-net alpine ash
    docker run -dit --name alpine3 alpine ash
    docker run -dit --name alpine4 --network alpine-net alpine ash
    docker network connect bridge alpine4
    
  4. bridge네트워크와 alpine-net네트워크를 다시 확인해보자

    docker network inspect bridge
    

    컨테이너에 alpine3과 alpine4가 연결되어있어야 한다.

    docker network inspect alpine-net
    

    alpine1, alpine2, alpine4가 연결되어 있어야 한다.

  5. alpine-net과 같이 유저가 정의한 네트워크에서는 IP통신뿐만 아니라 위의 브릿지 네트워크에서 실패한 컨테이너 이름으로 통신하는 것 또한 가능하다. alpine1에 접속하여 테스트해보자.

    docker container attach alpine1
    
  6. 반면 alpine1에서 alpine3으로 연결을 시도하면 실패할 것이다.

    ping -c 2 alpine3
    

    뿐만 아니라 IP주소로 연결하는 것조차 되지 않는다.

    ctrl+p,ctrl+q를 통해서 alpine1에서 detach하자

  7. alpine4를 살펴보자. 이 컨테이너는 alpine-net뿐만 아니라 bridge네트워크에도 연결되어 있다. alpine3 컨테이너를 이름으로 부를수는 없지만 IP주소로 연결은 가능하다.

  8. 컨테이너를 중지하고 삭제하자.

    docker container stop alpine1 alpine2 alpine3 alpine4
    docker container rm alpine1 alpine2 alpine3 alpine4
    docker network rm alpine-net
    

호스트 네트워킹

Docker 호스트의 네트워크에 직접 바인딩하는 독립형 컨테이너

  • 호스트 네트워킹은 오직 리눅스 위에서만 작동한다. Docker Desktop for Mac, Docker Desktop for Windows, or Docker EE for Windows Server는 지원되지 않는다.
  1. 컨테이너 생성

    docker run --rm -d --network host --name my_nginx nginx
    

    –rm 태그는 컨테이너가 종료 혹은 중지 될때 제거된다는 것을 의미한다.

  2. 80포트를 이용하여 nginx에 접속한다.

  3. 현재 로컬의 네트워크 인터페이스를 보도록 한다.

    ip addr show
    

    netstat명령어를 통해서 80번 포트가 프로세스에 바운드됬는지 확인한다.

    sudo netstat -tulpn | grep :80
    

    호스트 네트워킹에 직접적으로 바인딩되었음을 알 수 있다.

  4. 컨테이너를 중지한다. 생성시 –rm 명령어로 인해 자동적으로 컨테이너는 삭제될것이다.

    docker container stop my_nginx
    

오버레이 네트워킹

디폴트 오버레이 네트워크 사용하기

  • 이번 튜토리얼을 진행하기 위해서는 3대가 필요하다. 나는 EC2를 3개 생성하여 진행하였다. (manager, worker-1, worker-2)
  • 3개를 만든 후에는 각각에 도커 설치를 진행한다.
  • EC2를 사용하는 경우라면 2377,7946,4789포트의 TCP/UDP를 열어주도록 한다.
Swarm 생성

이 과정을 통해서 3개의 호스트가 스웜에 join하고 오버레이 네트워크를 이용하여 연결시킨다.

  1. Manager역할을 맡을 호스트에서 다음의 명령어를 실행시킨다.

    docker swarm init
    

    명령어를 통해 나온 출력물을 보면 swarm에 join하기 위한 명령어를 보여줄것이다. 이를 통해 다른 호스트에서 조인해보자.

  2. worker-1 역할을 맡을 호스트에서 다음의 프린트를 실행시킨다.

    docker swarm join --token <TOKEN> IP-ADDRESS:PORT 
    

    권한 관련해서 뭐라하면 sudo 붙이고 실행하세요. 타임아웃이 날 경우 manager 역할을 맡은 호스트에서 2377포트를 허용하도록 했는지 확인하세요.

  3. 마찬가지로 worker-2에서도 위의 명령어를 실행시킵니다.

  4. manager 노드로 돌아가서 아래의 명령어를 통해 swarm 에 조인되어 있는 노드들을 확인합니다. 이 때 3개(자신, worker-1, worker-2)가 나와야 정상입니다.

    docker node ls
    
  5. manager 노드에서 ingress라는 이름을 가진 overlay 네트워크와 docker_gwbridge라는 브릿지 네트워크가 생성되었는지 확인합니다.

    docker network ls
    

    docker_gwbridge : manager와 worker로부터 트래픽이 움직일 수 있도록 ingress 네트워크를 도커 호스트 네트워크 인터페이스에 연결.

서비스 만들기
  1. manager 노드에서 nginx-net라 불리는 새로운 overlay 네트워크를 만든다.

    docker network create -d overlay nginx-net
    

    이 명령어는 다른 노드에서 실행하지 않더라도 서비스 작업을 실행하기 시작하면 이러한 네트워크 생성 작업이 자동으로 생성된다.

  2. manager 노드에서 5개의 nginx 서비스를 복사하고 이를 nginx-net에 연결한다. 모든 서비스 작업 컨테이너들은 어떠한 포트를 열지않고도 통신할 수 있다.

    docker service create \
    --name my-nginx \
    --publish target=80,published=80 \
    --replicas=5 \
    --network nginx-net \
    nginx
    
  3. docker service ls를 실행시켜 모니터링해봅니다.

  4. 모든 노드에서 docker network inspect nginx-net을 명령어를 치고 컨테이너와 피어 부분을 본다. 컨테이너에 엔드포인트와 my-nginx.(5이하의 숫자)가 각각 있음을 본다.

  5. docker service inspect my-nginx를 통해 서비스가 사용중인 엔드포인트,포트 등의 정보를 확인한다.

  6. nginx-net-2라는 새로운 네트워크를 생성하자 그리고 nginx-net을 대신하여 네트워크의 서비스를 업데이트한다.

    docker network create -d overlay nginx-net-2
    
    docker service update \
      --network-add nginx-net-2 \
      --network-rm nginx-net \
      my-nginx
    
  7. docker service ls 를 실행하여 서비스가 업데이트 되었고 모든 작업이 다시 배포되었는지 확인한다. 또한 docker network inspect nginx-net을 통해 어떠한 컨테이너도 네트워크에 연결되어있지 않다는 것을 확인하다. 또한 이것을 nginx-net-2에서도 확인해봅니다.

  8. 네트워크와 서비스를 정리한다. 이 명령어를 통해 manager노드가 worker노드들에게 마찬가지로 지시할것이다.

    docker service rm my-nginx
    docker network rm nginx-net nginx-net-2
    

user-defined 오버레이 네트워크 사용

  1. user-defined 오버레이 네트워크 생성하기

    docker network create -d overlay my-overlay
    
  2. 서비스를 실행시킨다.

    docker service create \
      --name my-nginx \
      --network my-overlay \
      --replicas 1 \
      --publish published=8080,target=80 \
      nginx:latest
    
  3. docker network inspect my-overlay 명령어를 통해서 my-nginx 서비스 작업이 연결되었음을 확인한다. 어디에 생성됬을까? ㅎㅎ

  4. 네트워크와 서비스를 제거한다

    docker service rm my-nginx
    docker network rm my-overlay
    

Standalone 컨테이너에 오버레이 네트워크 사용

이번 예제는 2개의 노드를 사용하여 진행한다.

  • host1 : swarm manager
  • host2 : swarm worker
  1. host1에서 스웜을 초기화하여 생성한다.

    host2에서 해당 스웜에 조인한다.

    이미 작업한 내용이기에 그냥 지나간다.

  2. manager노드에서 test-net이라 불리는 네트워크를 생성한다.

    docker network create --driver=overlay --attachable test-net
    
  3. host1에서 -it플래그를 통해서 컨테이너 alpine1을 시작한다.

    docker run -it --name alpine1 --network test-net alpine
    
  4. host2에서 이용 가능한 네트워크 리스트를 본다. 아직 test-net 네트워크가 존재하지 않는 것을 알 수 있다.

  5. host2에서 alpine2이름을 가진 컨테이너를 -d-it를 이용하여 실행시킨다.

    docker run -dit --name alpine2 --network test-net alpine
    
  6. host2에서 다시 네트워크 리스트를 본다. 이번에는 네트워크가 존재할 것이다.

  7. host1으로 돌아가 alpine2에게 핑을 날려보자.

    ping -c 2 alpine2
    

    나의 경우에는 뭘 잘못했는지 이상하게 여기서부터 통신이 안된다. ,,,,

  8. 아무튼 내가 잘못한거지 여기서는 잘 실행된다고 하니 뭐.. host2에서도 host1핑 날려보고

  9. 각 노드에서 컨테이너 중지, 삭제, manager에서는 test-net 네트워크 삭제까지 해준다.

마치며

  • 오늘은 도커 네트워킹을 사용하여 각 컨테이너 간의 통신에 대하여 알아보았다. 이제 이를 통해서 젠킨스와 도커를 이용한 배포를 이어서 할 수 있을듯 하다.