개발놀이터

도커 네트워크 (with 아키텍처) 본문

배포/Docker

도커 네트워크 (with 아키텍처)

마늘냄새폴폴 2024. 5. 27. 22:36

이번 포스팅에선 도커, 그 중에서 도커 네트워크에 대해서 알아보도록 하겠습니다. 도커 네트워크에 대해서는 구글링하면 bridge니 host니 overlay니 많이 나와있으니 흔히 구글링하면 나오는 내용 말고 좀 더 딥한 내용을 다뤄보려고합니다. 

 

제가 도커 네트워크를 공부해야겠다고 생각하게 된 계기는 제가 너무 도커에 대해서 아무것도 모르고 도커를 사용하고 있던 것을 발견했습니다. 

 

그냥 Dockerfile만들고 build하고 docker-compose에 등록해서 관리하면 끝! 

 

사실 이게 끝일 정도로 도커 자체는 정말 간단하긴 하지만 도커를 조금 더 깊이있게 공부해야겠다는 마음으로 도커 카테고리를 약 1년만에 부활시켰습니다. 

 

이번엔 도커 네트워크에 대해서 딥다이브하는 시간을 가져보겠습니다. 

 

도커 아키텍처

도커 네트워크를 먼저 알아보기 전에 도커 아키텍처에 대해서 짚고 넘어가도록 하겠습니다. 왜냐하면 이 아키텍처를 이해하고 있어야 도커 네트워크에 대한 내용이 이해가 될 것 같아서 먼저 공부했습니다. 

 

이참에 도커 docs를 봤는데 이야... 정말 잘 되어있더군요 어려분도 정독할 기회가 있다면 한번 읽어보시는 것을 추천드립니다. 

 

 

도커는 클라이언트, 도커 API, 도커 호스트, 도커 데몬, 이미지, 컨테이너, 레지스트리로 이루어져있습니다. 하나씩 알아보죠.

 

  • 도커 클라이언트 : 우리가 실행하는 API들이 호출되는 장소입니다. 리눅스가 될 수도 있고 맥이 될 수도 있고 윈도우가 될 수도 있죠. 
  • 도커 호스트 : 도커가 실제로 실행되는 곳입니다. 
    • 도커 데몬 : 우리가 호출한 API를 실제로 컨테이너에게 전달하는 역할을 합니다. 
    • 이미지 : 도커 컨테이너를 생성하기 위해 만들어놓은 틀 같은 것입니다. 
    • 컨테이너 : 실제로 운영되는 애플리케이션입니다. 
  • 레지스트리 : 도커 이미지가 저장되는 정적 공간입니다. 

 

 

도커가 정말 잘 만들었다고 생각되는 부분 중 하나가 누구나 이해하기 쉬운 아키텍처로 되어있다는 것입니다. 도커를 한시간정도만 사용해보면 바로 저 아키텍처가 이해가 됩니다. 

 

제가 감명깊게 받는 포인트는 정말 쉬운데 정말 파워플한 기능을 가졌다는 것입니다. (물론 깊이 파면 다르지만요)

 

 

자 이제 본격적으로 네트워크에 대해서 알아보도록합시다. 

 

도커 네트워크

도커 네트워크를 알아보기 전에 OSI 7계층이 먼저 선행되어야할 것 같습니다. 

 

Layer 1 (L1)

L1에 대표적인 기기는 뭐니뭐니해도 케이블이죠. 하지만 케이블은 너무 우리에게 멀리있는 존재고 우리 가까이 있는 L1기기중 우리에게 익숙한 것이 NIC ("닉" 이라고 읽습니다)입니다. 

 

엥? 안익숙한데요?

 

NIC은 우리에게 익숙한 랜(LAN)카드입니다. NIC은 외부에서 들어오는 네트워크를 OS로 연결시켜주는 역할을 합니다. 

 

Layer 2 (L2)

L2에 대표적인 기기 하나 꼽아봐라 하면 저는 당연 스위치입니다. 스위치는 하나의 네트워크로 들어온 요청을 MAC주소를 이용해 어디로 가야할지 정해주는 기기입니다. 보통 NIC에는 MAC주소가 적혀있고 스위치는 NIC에게 붙어있는 MAC주소를 보고 연결하는 것입니다. 

 

예를 들어서 공유기를 타고 들어온 저희집 네트워크가 제 컴퓨터로 들어오기 위해서는 스위치를 거쳐서 제 컴퓨터로 들어가게 됩니다. 

 

Layer 3 (L3)

L3에서 가장 대표적인 기기는 라우터입니다. 이 라우터도 우리 일상속에 가까이있습니다. 바로 공유기가 라우터입니다. 

 

우리집에서 요청한 네트워크 통신이 서버로 도달하고 서버가 응답해주는 요청에 우리집 IP와 포트가 적혀있습니다. 인터넷에 흘러다니던 요청들이 정확한 IP와 포트로 들어가게 되는데 이때 요청을 받아주는 것이 라우터인 공유기의 역할이죠. 

 

 

번외1 Layer 4 (L4)

번외로 L4에서 우리에게 익숙한 것은 TCP 통신입니다. 원래 패킷은 L3에서 사용하는 것이지만 L3에선 할 수 없는 것들을 L4에게 위임함으로써 이뤄낼 수 있습니다. 

 

예를 들어 L3에서의 패킷은 혼잡제어나 흐름제어, 장애회복과 같은 것들을 지원해주지 않습니다. 이를 L4에 위임하여 통신의 신뢰성을 높이는 것이죠. 

 

번외2 Layer 7 (L7)

L7 애플리케이션 계층은 우리가 사용하는 모든 애플리케이션이 위치하고 있는 곳입니다. DNS같은 서비스나 HTTP같은 프로토콜까지 폭넓게 존재하는 영역이죠. 

 

보통 우리가 보낸 요청이 이 L7을 찍고 다시 우리에게 전달되는 것이니 엔드포인트라고 할 수도 있겠습니다. 

 

 

흐름

OSI 7계층의 가장 좋은 공부 방법은 물리계층이니 데이터링크계층이니 이런식으로 외우는 것보다 OSI 7계층에서 우리 주변에 있는 것들을 잘 조합해서 이해하는 것이 좋다고 생각합니다. 

 

정리하자면 

 

애플리케이션 (L7) => TCP 프로토콜 (L4) => 공유기 (L3) => 스위치 (L2) => 랜카드 (L1) => OS (여기에 네트워크 드라이버가 있습니다.)

 

이렇게 구성된다고 볼 수 있습니다. 

 

 

이게 뭐..?

도커 네트워크 얘기하다 왜 이 얘기를 하냐... 바로 도커가 네트워크를 구성할 때 위와같은 방식을 사용하기 때문입니다. 

 

애플리케이션이 작동하기 위해서 세가지 요소가 반드시 필요한데 바로 OS, 네트워크, 애플리케이션 이렇게 세가지입니다. 

 

보통 서버는 리눅스 위에서 동작하기 때문에 도커의 전략은 "OS? 호스트가 쓰는 리눅스 그대로 써! 네트워크? 그것도 호스트거 그대로 써! 우린 애플리케이션만 남긴다."

 

이렇게 전략을 구성했기 때문에 도커 내부적으로 OS는 리눅스 커널을 사용하더라도 네트워크는 가상으로 구현을 해줘야합니다. 

 

도커의 네트워크 아키텍처는 다음과 같습니다. 

 

 

도커 네트워크는 다음과 같은 흐름을 가집니다. 

 

  1. 도커 호스트의 NIC : 도커가 동작하는 호스트 서버의 NIC을 그대로 이용하면서 사용자가 호스트의 NIC을 타고 들어갑니다. 
  2. 도커 데몬의 NAT Gateway : 도커 데몬은 컨테이너의 사설 IP와 포트를 알아내기 위해 NAT을 사용하는데 이 NAT 게이트웨이가 스위치의 역할을 하기도 합니다. 
  3. 도커 데몬의 veth0 : veth0는 가상 이더넷의 약자입니다. 가상 이더넷은 컨테이너마다 부여가 되고, 컨테이너의 MAC주소를 가지고 있다고 생각하시면 됩니다. 
  4. 도커 컨테이너의 NIC : 도커 컨테이너에 NIC이 애플리케이션의 연결을 도와줍니다. 

 

이 상태에서 도커 컨테이너에 있는 네트워크 드라이브를 설정함으로써 더 효율적인 네트워크 관리가 가능합니다. 

 

도커의 네트워크 모드

도커의 네트워크 모드는 몇개 존재하지만 중요한 것 네개만 짚도록 하겠습니다. 

 

bridge

bridge는 가장 기본이 되는 네트워크 모드로 bridge를 이용하면 각종 이점을 얻을 수 있습니다. 

 

  • 내부적으로 컨테이너 이름을 DNS처럼 사용할 수 있다. 
  • 네트워크를 하나로 묶어서 네트워크를 격리시킬 수 있다. 
  • 내부망을 사용하기 때문에 네트워크 I/O를 "조금" 줄일 수 있다. 

 

이렇게 크게 세가지 이점이 있는데 하나씩 자세하게 살펴보도록 하겠습니다. 

 

 - 내부적으로 컨테이너 이름을 DNS처럼 사용할 수 있다. -

예를 들어서 이런 경우를 가정해봅시다. 

 

상황)

서버의 비용을 줄이기 위해 웹서버와 WAS서버를 하나로 묶어서 사용할 것입니다. 웹서버는 nginx를 사용하고 있고 443으로 들어오는 HTTPS요청을 WAS의 포트로 연결해주는 역할을 합니다. 

 

server {
	listen 443 ssl;
    server_name www.google.com;
    
    location / {
    	proxy_pass {컨테이너이름}:8080
        
        proxy_header 불라불라
    }
}

 

보통같았으면 proxy_pass를 원래였으면 실제 도메인인 google.com을 입력해야 하지만 네트워크를 bridge로 설정해놓음으로써 컨테이너 이름을 도메인처럼 사용할 수 있습니다. 

 

 - 네트워크를 하나로 묶어서 네트워크를 격리시킬 수 있다. - 

위의 예시를 그대로 사용하자면 

 

nginx의 80포트와 443포트를 Security Group으로 열어두고, 8080포트를 열어두는 것이 아니라 nginx를 이용해서만 들어가게 함으로써 실제 도커 호스트의 네트워크와 도커 컨테이너의 네트워크를 격리시켜서 보안을 더 높일 수 있다는 이야기입니다. 

 

 - 내부망을 사용하기 때문에 네트워크 I/O를 "조금" 줄일 수 있다. -

bridge는 내부망을 사용하기 때문에 네트워크 I/O가 발생하지 않아 조금 더 빠른 성능을 보여줍니다. 

 

하지만 제가 "조금"이라고 쓴 이유는 그 효과가 미미해서 큰 이득을 얻을 수는 없기 때문입니다. 

 

 

host

네트워크 모드 host는 말 그대로 호스트와 컨테이너 사이의 네트워크 격리를 이루지 않는 것을 의미합니다. 

 

이렇게 host로 설정하면 도커 데몬과 네트워크 통신을 하지 않기 때문에 성능적으로 매우 뛰어나다는 장점이 있습니다. 

 

엥? 위에서도 내부망을 사용한다고 하지 않았나요? 

 

내부망을 사용하더라도 네트워크 아키텍처에서 봤듯이 도커 호스트와 도커 컨테이너간 네트워크 통신이 필요합니다. 그렇게 네트워크 통신이 한번 이뤄지면 그 다음부턴 다리를 놓듯이 내부망을 사용한다는 것이고, host는 내부망으로 타지도 않고 바로 호스트의 네트워크를 그대로 사용한다는 것입니다. 

 

그래서 호스트의 네트워크를 그대로 사용하기 때문에 보안이 조금 떨어진다는 단점이 있습니다. 

 

그럼 host는 언제 사용할까요? 

 

예를 들어서 미디어 서버를 사용해서 WebRTC를 구현한다면 미디어 서버는 엄청나게 넓은 범위의 포트를 열어둬야합니다. 또한, 미디어 서버 뿐만 아니라 Turn 서버를 이용할 때도 엄청나게 넓은 범위의 포트가 필요하죠. 

 

그때 만약 컨테이너로 포트를 열어두면 네트워크 통신에 비용이 많이 들기 때문에 이 때 host로 설정해두면 성능적인 이점을 많이 가져올 수 있습니다. 

 

 

overlay

overlay는 여러개의 호스트가 있을 때 유용한데, 여기서 호스트란 위에서도 언급했지만 도커 데몬을 실행시키는 물리적 서버 혹은 클라우드 인스턴스를 의미합니다. 

 

Docker Swarm이나 Kubernetes와 같은 컨테이너 관리 툴을 사용할 때 주로 사용되는 네트워크입니다. 일반적으로 사용되는 것은 아닌 것 같습니다. 

 

 

none

none은 말 그대로 네트워크를 설정하지 않는 것입니다. 개인적으로는 이게 왜 필요한가 싶긴한데... 도커 네트워크 스펙으로 있으니까 일단 가져와봤습니다. 

 

 

마치며

이렇게 도커 네트워크에 대해서 알아봤습니다. 도커 네트워크에 대해서 알아보면서 일반적인 네트워크 통신도 잠깐 알아봤습니다. 

 

도커 아키텍처는 그림 한장 그것도 쉬운 그림으로 도커를 쓰는 누구나 이해시킬 수 있고 도커 네트워크조차 일반적인 CS지식이 있다면 이해하기 정말 쉬운 구조로 되어있는 것 같습니다. 

 

다시한번 도커의 매력적인 능력에 감탄을 하며 이번 포스팅 마치도록 하겠습니다. 긴 글 읽어주셔서 감사합니다. 

 

 

출처

https://docs.docker.com/network/

 

Networking overview

Learn how networking works from the container's point of view

docs.docker.com