쿠버네티스 네트워킹을 이해하기 위한 여정을 떠나보자. 이번 여정의 1차 도착지로는 Kristen Jacobs 의 Talks들을 이해하는 것으로 잡았다. 꽤 도전적이다.
이 글은 다른 누군가를 이해시키기 보다는 내가 이미 알고 있는 지식과 어울려 새로운 것을 알아가는 과정을 정리한 글이다.
쿠버네티스(k8s) 의 개념적인 아키텍쳐로부터 구성요소들을 먼저 확인해 두자.
▶ Kubernetes Components
쿠버네티스 시스템을 구성하는 컴포넌트들은 대략 아래와 같은 계층 구조를 이루고 있다.
K8S Cluster ⊂ Node ⊂ Pod ⊂ Container ⊂ App
클러스터
단위로 배포된다.쿠버네티스 클러스터
는 노드
라고하는 워커머신(Worker Machine)들로 구성된다.노드
는 포드(Pod)
를 호스트한다.포드
는 컨테이너화(Containerized)
된 어플리케이션 워크로드
를 실행한다.* 요즘은 Application보다는 Workload라는 용어를 더 선호하는 것 같다.
컨테이너화된 워크로드
간 통신 (container-to-container)컨테이너화된 워크로드
을 실행시키는 포드
간 통신 (pod-to-pod)포드
와 서비스
간 통신 (pod-to-service)서비스
사이의 통신 (external-to-service)
서비스
는 여러 포드위에서 실행되는 하나의 앱(Application)을 하나의 네트워크 서비스로 노출시키는 추상화된 방식
*아래는 Kristen Jacobs의 발표자료에서 발췌한 내용
The network needs to satisfy the following (Kubernetes) requirements:
K8s Networking Type 중에 가장 단순한 형태부터 시작하자. (Kevin Sookocheff의 blog 내용이 가장 쉽게 읽힌다. 이걸로 시작해 보자.)
보통 가상머신에서 네트워크 통신이라고 하면 Ethernet 디바이스와 직접 상호작용하는 것을 생각하는데 실상은 이것보다 조금 더 복잡하다.
▷ 단순화한 Ethernet 디바이스
리눅스에서 프로세스는 하나의 네임스페이스(namespace)
안에서 통신을 하게 된다. 이 네임스페이스
는 경로(routes), 방화벽규칙, 네트워크 디바이스로 구성된 논리적인 하나의 네트워킹 스택을 제공한다.
TODO - namespace 란?
(나중에 따로 정리토록 하자)$ ip netns add ns1 $ ls /var/run/netns ns1 $ ip netns ns1
위 스크립트에서처럼 생성된 네임스페이스는/var/run/netns
아래 마운트되어 영구적으로 유지된다.
리눅스는 모든 프로세스를 root
네임스페이스에 할당하여 외부세계와의 통신을 제공한다.
도커 구성 관점에서 보면 하나의 포드
는 한 그룹의 도커 컨테이너
들로 모델링되고 이들은 네임스페이스를 공유한다.
하나의 포드
안에 위치한 모든 컨테이너
들은 같은 IP주소를 가지고 포드
에 지정된 네임스페이스
의 가용 Port 공간(Port Space)를 공유한다. 같은 네임스페이스내에 상주하기 때문에 localhost
를 통해서 서로를 찾을 수 있다.
하나의 가상머신내 각각의 포드
를 위한 네임스페이스를 생성할 수도 있다.
Docker의 경우 Pod 컨테이너
는 개방된 네트워크 네임스페이스를 가지고 있고, App 컨테이너들
은 이 네임스페이스에 도커의 -net=container:
기능을 이용하여 가입하게 만든다. ( net=container:pause
, Pod 컨테이너
는 GCP의 Shared VPC
에서의 host project 개념과 유사해 보인다.)
아래 그림은 어떻게 각 포드
들이 하나의 공유 네임스페이스안에서 복수의 도커 컨테이너(ctr*)들로 구성되어 있는지를 보여준다.
Applications within a Pod also have access to shared volumes, which are defined as part of a Pod and are made available to be mounted into each application’s filesystem.
Linux의 IPC 장치나 Shared Volume을 통한 프로세스간 통신을 설명하기 위한 밑밥인 듯
이어서 하나의 노드내 Pod간 통신에 대해서 살펴보자.
쿠버네티스에서 모든 Pod들은 각자의 IP를 가지고 있고 이를 통해서 Pod간 통신을 하게 된다. 실제 하나의 노드상에서 어떻게 Pod-to-Pod 통신이 이루어지는지를 보도록 하자.
Pod 관점에서 보면 Pod는 자신의 Ethernet 네임스페이스안에 존재하며 같은 노드의 다른 네임스페이스와 통신을 해야 한다.
다행스럽게도 네임스페이스는 Linux Virtual Ethernet Device를 통해서 연결될 수 있다.
veth pair
라고도 불리며 2개의 가상 인터페이스로 구성된 이것은 여러개의 네임스페이스에 걸칠 수 있다.
(namespaces can be connected using a Linux Virtual Ethernet Device or veth pair consisting of two virtual interfaces that can be spread over multiple namespaces.)
The veth devices are virtual Ethernet devices. They can act as tunnels between network namespaces to create a bridge to a physical network device in another namespace
Pod 네임스페이들을 연결하기 위해서는 veth pair
의 한쪽을 root
네임스페이스에 연결하고 다른 쪽을 Pod의 네트워크 네임스페이스에 연결한다. 각 veth pair
는 패치 케이블처럼 동작한다. 이런 셋업은 머신상의 Pod 수만큼 복제될 수 있다.
*patch cable - 양쪽에 RJ45 커넥터가 달려있는 보통 얘기하는 랜선
다음은 VM상의 각 Pod를 root 네임스페이스에 연결하는 veth pair
들을 보여준다.
각 Pod는 각자의 네임스페이스를 가지고 Node의 root 네임스페이스에 연결되어 있다. Pod가 root 네임스페이스를 통해서 통신이 되어야 하는데 이런 목적으로 네트워크 브리지를 사용한다.
Linux Ethernet 브리지는 Virtual Layer 2의 네트워킹 디바이스로 두 개 혹은 그 이상의 네트워크 세그먼트를 transparent하게 묶는데 사용된다.
브리지는 출발지와 도착지간 포워딩 테이블을 유지하며 통과하는 데이터 패킷의 도착지를 살펴보고 연결된 다른 네트워크 세그먼트로 보낼지 말지를 결정한다. (MAC주소 사용)
Future traffic with the same IP address uses the lookup table to discover the correct MAC address to forward the packet to.
브리지는 ARP 프로토콜을 구현하고 있다. 이를 사용하여 주어진 IP주소와 연관된 Link Layer MAC 주소를 발견한다. 브리지는 데이터 프레임이 도착하면 그 프레임을 모든 연결된 기기에 브로드캐스트한다. 이 후 응답한 기기는 Lookup 테이블에 기록된다. 이후로 동일 IP 주소를 가진 트래픽이 들어오면 Lookup 테이블을 사용하여 올바른 MAC 주소를 찾아 패킷을 포워드시킨다.
*cbr0 - cutom bridge 0
네트워크 스택을 분리시키는 각각의 네트워크 네임스페이스가 주어지고, 가상의 이더넷 디바이스가 각 네임스페이스를 root 네임스페이스에 연결한 후, 브리지가 이들 네임스페이스들을 묶어주면 마침내 동일 노드상의 Pod들 간에 트래픽을 보낼 수 있는 준비가 되었다.
eth0
으로 보낸다.eth0
는 가상 이더넷 디바이스인 veth0
를 통해 root 네임스페이스에 연결된다.cbr0
브리지는 veth0
를 브리지에 연결된 하나의 네트워크 세그먼트로 구성하였다.veth1
를 찾아(resolve) 전달한다. - veth1
에 도달하면 Pod 2의 네임스페이스의 eth0
디바이스로 바로 전달된다. 트래픽이 흘러가는 동안 각 Pod는 오직 localhost의 eth0
와만 통신하고 있다. 그래도 트래픽은 경로를 따라 올바른 Pod에 도달한다.
Kubernetes’ networking model dictates that Pods must be reachable by their IP address across Nodes. That is, the IP address of a Pod is always visible to other Pods in the network, and each Pod views its own IP address as the same as how other Pods see it.
veth pair
veth pair
들 + 리눅스 bridge
다음 글에서는 다른 블로그의 내용을 참고하여 이해를 높여보도록 하자.