TCP/IP
컨테이너가 외부 인터넷에 연결할 때는 TCP/IP를 사용합니다. 리눅스 컨테이너에는 리눅스 커널이 필요하기 때문에, 도커 데스크톱에는 리눅스 VM이 포함되어 있고 따라서 컨테이너의 트래픽은 호스트 자체에서가 아닌 리눅스 VM에서 발생하기 때문에 문제를 일으키곤 한다.
기업에서 VPN을 사용하는 경우 “VPN을 통해 호스트에서 발생하는 트래픽만 전달하도록” VPN 정책을 만든다. 이는 호스트가 실수로 라우터처럼 작동하여 인터넷에서 내부 네트워크로 연결되는 것을 막는다. 따라서 VPN 소프트웨어가 Linux VM의 트래픽을 감지하면 컨테이너가 내부 리소스에 액세스하는 것을 막아서 VPN을 통해 라우팅되지 않도록 한다. Docker Desktop은 TCP/IP 계층인 vpnkit을 통해 사용자 수준의 모든 트래픽을 전달하여 이 문제를 해결한다.
다음 다이어그램은 도우미 VM에서 vpnkit 및 인터넷으로의 패킷 흐름을 보여줍니다:
VM이 부팅되면 DHCP를 사용하여 주소를 요청합니다. 요청이 포함된 이더넷 프레임은 Mac의 virtio 장치 또는 Windows의 경우 “하이퍼바이저 소켓”(AF_VSOCK)을 통해 VM에서 공유 메모리를 통해 호스트로 전송됩니다. Vpnkit에는 DHCP(mirage/charrua) 서버와 가상 이더넷 스위치(mirage-vnetif)가 포함되어 있습니다.
VM의 IP 주소와 게이트웨이의 IP 주소를 가진 DHCP 응답을 받으면 게이트웨이의 이더넷 주소(mirage/arp)를 검색하기 위한 ARP 요청을 보냅니다. ARP 응답을 받으면 인터넷으로 패킷을 보낼 준비가 완료됩니다.
Vpnkit은 새로운 대상 IP 주소가 있는 발신 패킷을 받으면, 원격 머신을 위한 가상 TCP/IP 스택을 생성합니다(mirage/mirage-tcpip). 이 스택은 리눅스의 피어 역할을 하며, 연결을 수락하고 패킷을 교환합니다. 컨테이너가 TCP 연결을 설정하기 위해 connect()를 호출하면, 리눅스는 SYNchronize 플래그가 설정된 TCP 패킷을 보냅니다. Vpnkit은 SYNchronize 플래그를 관찰하고 호스트에서 connect() 자체를 호출합니다. Connect()가 성공하면, vpnkit은 TCP 핸드셰이크를 완료하는 TCP SYNchronize 패킷으로 Linux에 응답합니다. 리눅스에서 connect()는 성공하고 데이터는 양방향으로 프록시됩니다(mirage/mirage-flow). Connect()가 거부되면, vpnkit은 Linux 내부의 connect()가 오류를 반환하는 TCP RST(리셋) 패킷으로 응답합니다.
또한 UDP와 ICMP 역시 유사하게 처리됩니다.
TCP/IP 외에도 vpnkit에는 DNS 서버(mirage/ocaml-dns) 및 HTTP 프록시(mirage/cohttp)와 같은 네트워크 서비스가 내장되어 있습니다. 이들 서비스는 가상 IP 주소/DNS 이름을 바로 연결 하거나 설정에 따라 발신 트래픽에 동적 리디렉팅을 대입하여 연결할 수 있습니다.
TCP/IP 주소만으로 사용하기는 어렵기 때문에,
다음 섹션에서는 Docker Desktop이 도메인 이름 시스템(DNS)을 사용하여 사람이 읽을 수 있는 이름을 네트워크 서비스에 제공하는 방법을 설명합니다.
DNS
도커 데스크톱 내부의 다중 DNS 서버: