Docker 네트워크 심층 탐구

DockerBeginner
지금 연습하기

소개

이 실습에서는 Docker 네트워킹의 기초를 바탕으로 한 단계 더 나아가 고급 네트워크 개념을 살펴봅니다. 브리지 (Bridge), 호스트 (Host), 논 (None) 이라는 세 가지 주요 네트워크 모드를 심층적으로 분석할 것입니다. 또한 사용자 정의 네트워크를 생성하고, 서로 다른 네트워크에 있는 컨테이너를 연결하며, 각 네트워크 모드가 컨테이너 간의 통신과 격리에 미치는 영향을 이해하게 됩니다. 이러한 실무 경험은 Docker 네트워킹 실무를 위한 탄탄한 기초를 제공할 것입니다.

이 과정은 단계별 안내에 따라 학습하고 연습할 수 있는 가이드형 실습입니다. 각 단계를 주의 깊게 따라가며 실무 경험을 쌓으시기 바랍니다. 통계 데이터에 따르면 이 실습은 초급 수준이며, 98%의 수료율과 학습자들로부터 100%의 긍정적인 평가를 기록하고 있습니다.

사용자 정의 브리지 네트워크

Docker 는 기본 브리지 네트워크를 제공하지만, 사용자 정의 브리지 네트워크를 직접 만들면 컨테이너 간 통신을 더 세밀하게 제어하고 격리 수준을 높일 수 있습니다.

  1. 먼저 현재 Docker 네트워크 목록을 확인합니다.
docker network ls

다음과 유사한 결과가 출력됩니다.

NETWORK ID     NAME      DRIVER    SCOPE
296d1b460b17   bridge    bridge    local
91199fc6ad2e   host      host      local
1078d2c781b6   none      null      local
  1. 이제 사용자 정의 브리지 네트워크를 생성해 보겠습니다.
docker network create my-custom-bridge
  1. 네트워크가 잘 생성되었는지 다시 확인합니다.
docker network ls

출력 결과에 my-custom-bridge가 포함되어야 합니다.

NETWORK ID     NAME               DRIVER    SCOPE
296d1b460b17   bridge             bridge    local
91199fc6ad2e   host               host      local
7215f99d0080   my-custom-bridge   bridge    local
1078d2c781b6   none               null      local
  1. 생성한 네트워크에서 두 개의 컨테이너를 실행하고 ping 도구를 설치합니다.
docker run --network=my-custom-bridge --name container1 -d nginx
docker run --network=my-custom-bridge --name container2 -d nginx

기본 Nginx 이미지에는 ping 유틸리티가 포함되어 있지 않으므로, 각 컨테이너에 직접 설치해야 합니다.

docker exec container1 apt-get update && docker exec container1 apt-get install -y iputils-ping
docker exec container2 apt-get update && docker exec container2 apt-get install -y iputils-ping
  1. 컨테이너 간의 통신을 테스트합니다.
docker exec container1 ping -c 4 container2

성공적으로 응답이 오는지 확인하세요. 이는 동일한 사용자 정의 브리지 네트워크에 있는 컨테이너들이 컨테이너 이름을 통해 서로 통신할 수 있음을 보여줍니다. Docker 의 내장 DNS 가 동일 네트워크 내에서 컨테이너 이름을 해당 IP 주소로 해석해주기 때문에 가능한 일입니다.

만약 ping 이 실패한다면, docker ps 명령어로 두 컨테이너가 정상 실행 중인지, 그리고 ping 유틸리티가 제대로 설치되었는지 확인하시기 바랍니다.

네트워크 간 컨테이너 연결

Docker 에서는 하나의 컨테이너를 여러 네트워크에 동시에 연결할 수 있습니다. 이를 통해 서로 다른 네트워크에 있는 컨테이너 간의 통신이 가능해집니다. 특정 컨테이너들을 격리하면서도 필요한 경우에만 선별적으로 통신을 허용하고 싶을 때 매우 유용합니다.

  1. 먼저 두 번째 사용자 정의 브리지 네트워크를 생성합니다.
docker network create my-second-bridge
  1. 네트워크 생성을 확인합니다.
docker network ls

이제 두 개의 사용자 정의 네트워크가 모두 보여야 합니다.

NETWORK ID     NAME               DRIVER    SCOPE
296d1b460b17   bridge             bridge    local
91199fc6ad2e   host               host      local
7215f99d0080   my-custom-bridge   bridge    local
8a15f99d0081   my-second-bridge   bridge    local
1078d2c781b6   none               null      local
  1. container2를 새 네트워크에 연결합니다.
docker network connect my-second-bridge container2

이 명령을 실행하면 container2는 기존 my-custom-bridge 연결을 유지한 채 my-second-bridge 네트워크에도 추가로 소속됩니다.

  1. 두 번째 네트워크에서 새 컨테이너를 실행합니다.
docker run --network=my-second-bridge --name container3 -d nginx
docker exec container3 apt-get update && docker exec container3 apt-get install -y iputils-ping
  1. 모든 컨테이너 간의 통신을 테스트합니다.
docker exec container1 ping -c 2 container2
docker exec container1 ping -c 2 container3
docker exec container2 ping -c 2 container3

결과를 분석해 보겠습니다.

  • container1container2와 통신할 수 있습니다. (동일 네트워크 소속)
  • container1container3와 통신할 수 없습니다. (서로 다른 네트워크 소속)
  • container2container1container3 모두와 통신할 수 있습니다. (두 네트워크 모두에 연결됨)

만약 container1에서 container3로 ping 이 성공한다면 네트워크 격리 설정에 문제가 있는 것입니다.

호스트 네트워크 모드

호스트 (Host) 네트워크 모드는 컨테이너와 Docker 호스트 사이의 네트워크 격리를 제거하여, 컨테이너가 호스트의 네트워크를 직접 사용하게 합니다. 이는 네트워크 성능을 극대화하는 데 유리하지만, 격리 수준이 낮아지므로 보안상 주의가 필요합니다.

  1. 호스트 네트워크 모드를 사용하여 컨테이너를 생성합니다.
docker run --network host --name host-container -d nginx
  1. 현재 네트워크 목록을 확인합니다.
docker network ls

이 컨테이너는 호스트의 네트워크를 그대로 사용하므로 목록에 새로운 네트워크가 추가되지는 않습니다.

  1. 컨테이너가 호스트 네트워크 모드를 사용 중인지 확인합니다.
docker inspect --format '{{.HostConfig.NetworkMode}}' host-container

출력 결과로 host가 나와야 합니다.

  1. 호스트 머신에서 Nginx 기본 페이지에 접속해 봅니다.
curl localhost:80

Nginx 환영 페이지가 보일 것입니다. 컨테이너가 호스트의 네트워크 인터페이스를 공유하고 있고, Nginx 가 호스트의 80 번 포트에서 요청을 대기하고 있기 때문에 별도의 포트 포워딩 없이도 접속이 가능합니다.

참고: 만약 호스트 머신의 80 번 포트에서 이미 다른 서비스가 실행 중이라면 이 단계는 실패할 수 있습니다. 그럴 경우 기존 서비스를 먼저 중단해야 합니다.

논 네트워크 모드

'논 (None)' 네트워크 모드는 네트워크 인터페이스가 없는 컨테이너를 생성하여 네트워크로부터 완전히 격리합니다. 보안상 극도의 격리가 필요한 작업에 유용하지만, 컨테이너가 외부와 통신할 수 없다는 점을 유의해야 합니다.

  1. 네트워크가 없는 컨테이너를 생성합니다.
docker run --network none --name isolated-container -d alpine sleep infinity
  1. 네트워크 목록을 확인합니다.
docker network ls

이 컨테이너는 어떤 네트워크에도 연결되어 있지 않습니다.

  1. 컨테이너 내부에 네트워크 인터페이스가 없는지 확인합니다.
docker exec isolated-container ip addr

루프백 (lo) 인터페이스만 보이고, eth0와 같은 일반적인 네트워크 인터페이스는 존재하지 않아야 합니다.

  1. 격리된 컨테이너에서 외부 (Google) 로 ping 을 시도해 봅니다.
docker exec isolated-container ping -c 2 google.com

네트워크 접근 권한이 없으므로 "Network is unreachable" 오류와 함께 실패해야 정상입니다.

네트워크 별칭과 서비스 디스커버리

Docker 네트워크는 네트워크 별칭 (Alias) 을 통한 서비스 디스커버리 기능을 지원합니다. 이는 유연하고 확장 가능한 애플리케이션을 구축할 때 매우 유용합니다. 여러 컨테이너가 동일한 DNS 이름을 공유하게 함으로써 기본적인 로드 밸런싱을 구현할 수 있습니다.

  1. 이번 실습을 위한 새로운 브리지 네트워크를 생성합니다.
docker network create service-network
  1. 네트워크 생성을 확인합니다.
docker network ls

목록에 service-network가 나타나야 합니다.

  1. 동일한 네트워크 별칭을 가진 두 개의 컨테이너를 실행합니다.
docker run -d --network service-network --network-alias myservice --name service1 nginx
docker run -d --network service-network --network-alias myservice --name service2 nginx
  1. 클라이언트 컨테이너를 생성하여 nslookup으로 서비스를 조회해 봅니다.
docker run --rm --network service-network appropriate/curl nslookup myservice

두 컨테이너의 IP 주소가 모두 반환되는 것을 확인할 수 있습니다. 이는 Docker 의 내장 DNS 서버가 두 컨테이너 사이에서 로드 밸런싱을 수행하고 있음을 보여줍니다.

  1. 서비스에 여러 번 접속하여 테스트합니다.
for i in {1..4}; do docker run --rm --network service-network appropriate/curl ping -c 1 myservice; done

두 컨테이너로부터 번갈아 가며 응답이 오는 것을 확인할 수 있으며, 이는 기본적인 로드 밸런싱이 작동하고 있음을 증명합니다. Docker DNS 서버는 myservice 이름을 해석할 때 두 IP 주소를 교대로 제공합니다.

PING myservice (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.106 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.106/0.106/0.106 ms
PING myservice (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.119 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.119/0.119/0.119 ms
PING myservice (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.097 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.097/0.097/0.097 ms
PING myservice (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.140 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.140/0.140/0.140 ms

요약

이 고급 Docker 네트워킹 실습을 통해 다음과 같은 핵심 개념들을 학습했습니다.

  1. 컨테이너 격리 및 통신 최적화를 위한 사용자 정의 브리지 네트워크 활용법
  2. 컨테이너를 여러 네트워크에 동시에 연결하는 방법
  3. 호스트의 네트워크 스택에 직접 접근하기 위한 호스트 네트워크 모드
  4. 완전한 네트워크 차단을 위한 논 네트워크 모드
  5. 확장 가능한 애플리케이션 구축을 위한 네트워크 별칭 및 서비스 디스커버리

Docker 의 이러한 고급 네트워킹 기능은 컨테이너 간의 통신과 격리를 정밀하게 제어하여 복잡한 다중 컨테이너 애플리케이션을 설계할 수 있는 강력한 도구를 제공합니다. 효율적이고 안전하며 확장 가능한 컨테이너 기반 애플리케이션을 설계하기 위해서는 이러한 개념을 이해하는 것이 필수적입니다.

Docker 네트워킹은 뛰어난 유연성을 제공하지만, 네트워크 아키텍처를 설계할 때는 항상 보안을 염두에 두어야 합니다. 필요한 포트와 서비스만 노출하는 '최소 권한 원칙'을 항상 준수하시기 바랍니다.

앞으로 Docker 를 활용하면서 이러한 네트워킹 개념은 복잡한 애플리케이션과 마이크로서비스 아키텍처를 조율하는 데 매우 귀중한 자산이 될 것입니다. Docker 네트워크를 효과적으로 관리할 수 있도록 꾸준히 연습해 보시기 바랍니다.