K8S Networking - Single Node, Multiple Pods (2)

Jay Park·2021년 11월 30일
0
post-custom-banner

들어가며

동일 노드상의 여러 Pod간 통신에 대해서 다른 방식으로 설명된 내용을 살펴보며 이해를 높여가도록 한다.

Pods

하나의 포드는 동일한 호스트에 같이 위치하며 네트워크 스택과 스토리지 볼륨과 같은 리소스를 공유하는 여러 컨테이너들로 구성된다.

두번째 컨테이너를 띄워보자.

여기까지는 좋다. 하지만 이게 쿠버네티스 Pod의 shared network stack 을 제공하지는 않는다.

shared network stack (앞선 글에서 발췌)

Docker의 경우 Pod 컨테이너는 개방된 네트워크 네임스페이스를 가지고 있고, App 컨테이너들은 이 네임스페이스에 도커의 -net=container: 기능을 이용하여 가입하게 만든다. (Pod 컨테이너는 GCP의 Shared VPC의 host project 개념과 유사해 보인다.)

다행히도 네임스페이는 아주 유연하다. Docker는 컨테이너를 시작하면서 새로운 가상 네트워크 인터페이스(veth)를 생성하는 대신에 이미 존재하는 인터페이스를 지정할 수 있다. 이 경우 그림은 약간 달라진다.

이제 두 번째 컨테이너는 자신의 veth1이 아닌 공유된 veth0를 보게 된다. 여기에는 두가지 함의가 있다.

  • 외부에서는 172.17.0.2 주소로 양쪽의 컨테이너들에 접근 가능하다.
  • 내부에서는 loopback(localhost)의 Port를 통해서 통신이 가능하다.

이런 방식으로 프로세스들은 컨테이너가 제공하는 decoupling and isolation의 장점을 활용하며 동시에 단순한 방식으로 서로 협업할 수 있게 된다.

(이를 통해 각 Containerized App들은 독립된 실행 공간을 가지면서 NAT없이 직접 통신이 가능하다.)

Pause 컨테이너

쿠버네티스에서는 이런 패턴의 구현을 위해 각 포드마다 특별한 컨테이너를 생성하여 다른 컨테이너들을 위한 네트워크 인터페이스(네트워크 스택)를 제공한다.

pause 컨테이너 - 가상 네트워크 스택을 제공하는 특수한 컨테이너

pause 컨테이너를 포함한 포드 내부의 네트워크 구조는 아래와 같다.

Pod Network

(싱글노드가 아닌 멀티노드이긴 하나 마저 정리하도록 한다.)

이번에는 포드간 통신을 다룬다. 동일 노드상에서의 포드간 통신과 서로 다른 노드간의 포드통신 두 가지를 생각해 볼 수 있다. (여기서는 동일 노드만 다룸)

쿠버네티스는 하나 이상의 노드로 구성되고 하나의 노드는 하나의 호스트 시스템이다. 노드는 BM이건 VM이건 상관없다.

왼쪽의 호스트의 경우 eth0 -> docker0 -> veth0 로 연결되어 있다.

172.17.0.2를 목적지로 하여 eth0에 도달하는 패킷들은 기본 라우팅 규칙에 따라서 브리지를 거쳐 veth0 인터페이스로 보내진다. 172.17.0.2Pod가 있다는 것을 알고 있으면 라우터(그림에서 router/gateway) 설정에 next hop을 eth0의 IP주소인 10.100.0.2로 설정하면 패킷들은 veth0로 전달될 것이다.

오른쪽 호스트도 eth0를 가지고 동일하게 10.100.0.1을 default gateway 로 사용중이다. 여기의 eth0docker0 브리지에 연결되어 있는데 왼쪽 호스트와 동일한 IP 주소를 사용하고 있다. veth0도 마찬가지다.

172.17.0.2 패킷은 그럼 어디로 라우팅되어야 할까? 알 수 없다. 이를 해결하기 위한 새로운 구조가 필요하다.

쿠버네티스는 2가지 방법을 사용하여 이를 해결하고 있다.

첫번째는, 각 노드의 브리지들을 위한 전체 주소 공간을 먼저 생성한 후 브리지가 있는 노드에 따라서 브리지 IP 주소를 할당한다.

(커피고래님 역자주를 통해 좀 더 자세히 이해하도록 한다.)

노트(호스트)별로 분리된 서브넷을 사용하면 된다고 한다. 서브넷 범위내에서 Pod나 bridge의 IP들이 할당되니 충돌이 없을 것이다.

두번째로는, 라우팅 규칙을 10.100.0.1 게이트웨이에 추가하여 각각의 각 브리지로 향하는 패킷들을 어떻게 라우팅시켜야 할지를 알려준다. 예를 들어, 어떤 노드의 eth0를 통하면 브리지에 도착할 수 있을지에 대한 규칙 같은 것들이다.

veth*, bridge, routing rule의 조합을 보통 overlay network 이라 부른다. Pod들이 어떤 노드상에 있건 서로 통신을 주고 받을 수 있게 해주기 때문에 쿠버네티스에 대한 얘기를 할 때는 pod network이라 부르기도 한다.

[Note] bridge0 -> cbr0 : custom bridge. 쿠버네티스는 표준 도커 브리지를 사용하지 않는다.
[Note] 브리지에 할당된 10.0.0.0/14 주소공간은 Google Cloud에서의 실제 사례. kubectl을 통해서 이 정보를 노출시킬 수 있는 방법은 없지만 GCP에서는 gcloud container clusters describe <cluster> 명령을 통해서 clusterIpv4Cidr 속성을 확인할 수 있다.

일반적으로는 살펴본 네트워크가 어떻게 동작하는지 생각할 필요는 없다. Pod가 다른 Pod와 얘기하고 싶을 때는 추상화된 서비스라고 하는 것을 통하기 때문이다.
서비스는 일종의 소프트웨어 프락시(software-define proxy)로 나중에 다루게 될 것이다.

그러나 Pod 네트워크 주소는 로그상에 남겨질 수 있고 디버깅을 하거나 어떤 상황에서 명시적으로 이 네트워크의 경로를 설정할 필요가 생길 수 있다.

예를 들어, 쿠버네티스 Pod를 떠나 10.0.0.0/8 의 어떤 주소를 향하는 트래픽은 기본적으로 NAT 되지 않는다. 그래서 다른 Private 네트워크상의 서비스와 통신하고자 할 때는 라우팅 규칙을 설정하여 패킷이 Pods로 다시 라우팅되도록 해야 한다.
(이 문단은 이해가 안됨)

나가며

이상으로 두 편의 블로그 내용을 바탕으로 동일 노드에 복수개의 포드들이 어떻게 NAT없이 통신이 가능한지 살펴보았다.

profile
Jaytiger
post-custom-banner

0개의 댓글