Dev / App

K8s Network - Flannel CNI

K8s Network

9 min read
K8s Network - Flannel CNI

Flannel CNI

Flannel CNI는 Kubernetes 클러스터에서 Pod 간의 네트워크 통신을 가능하게 해주는 Container Network Interface(CNI) 플러그인 중 하나입니다. 간단히 말해, Kubernetes의 네트워크 계층을 구성해주는 도구입니다.

Flannel Overlay Network

K8s 내부에는 여러개의 노드들이 존재할 수 있으며, 각 노드들의 네트워크를 하나의 망으로 엮어 인식하는 것을 Overlay Network라고 합니다.
이로 인하여, 노드들은 가상의 네트워크지만, 물리적으로 연결된 것처럼 동작하게 됩니다.

Flanneld

Flannel CNI는 데몬셋으로 실행됩니다. 그렇기에, 각 노드마다 Flannel Pod가 실행되는 구조입니다.

Flannel pod 확인

WSL2에서 Vagrant로 가상 환경을 구성하여 진행 중이며, Master Node 1개 / Worker Node 2개로 K8s가 구성되어 있습니다.

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml


Flannel NIC 확인

Flannel CNI는 flannel.1(vxlan) 인터페이스 및 cni0 인터페이스를 Master Node에 추가합니다.


cni0의 네트워크 대역은 어디에서 지정되는 것일까요?
아래와 같이 FLANNEL_NETWORK 필드 값을 참조하여 설정됩니다.

cat /run/flannel/subnet.env

Pod의 IP 또한 마찬가지로 flannel.1 네트워크 대역에 영향을 받습니다.

kubectl get node master -o json | jq '.spec.podCIDR'
kubectl get node worker1 -o json | jq '.spec.podCIDR'
kubectl get node worker2 -o json | jq '.spec.podCIDR'

iptables

먼저, iptables에는 Flannel이 가상브릿지를 활용하여 내부(FWD)/외부(POSTROUTING) 통신을 할 수 있도록 Routing이 설정되어 있습니다.

sudo iptables -t filter -S | grep 10.244.
sudo iptables -t nat -S | grep 'A POSTROUTING' #외부 통신 식별 시, CIDR 값과 같은 별다른 정보 안보이며, "FLANNEL-POSTRTG"와 같은 라우팅 체인만 존재함
sudo iptables -t nat -S FLANNEL-POSTRTG -N FLANNEL-POSTRTG #체인의 세부 룰 확인 시, 외부 통신에 대한 여러 NAT 정책에 따른 CIDR 룰이 확인됨

룰 분석

-A FLANNEL-POSTRTG -m comment --comment "flanneld masq" -j RETURN
모든 패킷을 대상으로 기본 동작은 패스(RETURN) 한다.
-A FLANNEL-POSTRTG -s 10.244.0.0/24 -d 10.244.0.0/16 -j RETURN
-A FLANNEL-POSTRTG -s 10.244.0.0/16 -d 10.244.0.0/24 -j RETURN
Pod간 내부 통신(같거나/하위인 CIDR 간은) -> NAT하지 않는다.
-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/24 -j RETURN
외부에서 내부로 들어오는 트래픽 중 일부도 NAT에서 제외한다.
-A FLANNEL-POSTRTG -s 10.244.0.0/16 ! -d 224.0.0.0/4 -j MASQUERADE --random-fully
클러스터 내부(Pod)에서 멀티캐스트를 제외한 외부 통신 시에는 NAT를 적용한다.
-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/16 -j MASQUERADE --random-fully
외부에서 클러스터로 접근할 때도 NAT를 적용한다.

MASQUERADE?

NAT의 기술안에 속한 기술로, IP주소 변환 및 포트포워딩 기능도 가지고 있다.
예) ClientA(192.168.0.1), ClientB(192.168.0.2) 두 클라이언트는 Pub IP가 없기에, 외부 통신이 불가한 상태이다.
이때, MASQUERADE를 통해 Pri IP를 가진 클라이언트가 패킷을 전송하면, 라우터(211.xxx...)에서 목적지에 자신이 보낸 것처럼 패킷을 전송한다.
즉, 수신측에서는 192.168.0.1가 아닌 211.xxx...의 Pub IP가 보인다.

(참고: 라우터는 Pub IP의 무작위 포트 번호를 붙혀서 보내며, 외부에서 다시 내부로 패킷을 보낼 때, 해당 포트를 통해 클라이언트로 패킷을 전달함)

Node Routing Table

현재까지 내용 정리

  1. Flannel CNI를 통해서 flannel.1이라는 vxlan 인터페이스가 생성됨
  2. 이를 통해 Pod간 통신을 vxlan 패킷으로 캡슐화되어 전송됨
  3. 각 노드의 flanneld(Daemon)이 /run/flannel/subent.env 정보를 기반으로 패킷 라우팅을 함

이전에 iptables에 외부 통신을 위한 룰을 확인했었습니다.
그렇다면, Node간 Pod 통신은 어떻게 설정될까요?

Pod가 다른 노드의 Pod로 통신하기 위한 라우팅 테이블도 존재하며, 다른 노드로 라우팅될 때, flannel.1 vxlan 인터페이스를 거쳐가는 것을 확인할 수 있습니다.
참고: Pod 자신은 네트워크 대역 cni0를 거쳐갑니다.

Node Routing Table 분석(Master Node 기준)

10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
-> Master Node는 현재 10.244.0.0/24 대역을 가지고 있습니다. 즉, 자기 자신이며, cni0을 통해 통신됩니다.
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
-> Worker1, 2 Node 둘 다, flannel.1 vxlan 인터페이스를 통해서 터널링 통신되고 있습니다.
여기서 "onlink"는 직접 연결된 것처럼 취급한다라는 의미로 vxlan 구조 방식의 일반적인 설정입니다.

노드간 통신 검증

노드간 통신 검증은 여러 방식이 있을 수 있겠으나, Worker1에 생성된 Pod에 접근하여, Worker2로 ping을 날리는 방식으로 검증하도록 하겠습니다.

  1. 각 노드별로 busybox Pod 생성
  2. 각 컨테이너 IP 확인 - 노드 대역에 따라 IP가 설정됨을 확인 가능
  3. Worker1의 Pod 접근 후 Worker2의 Pod로 Ping 테스트
  4. 반대로도 진행 후 정상인지 확인

CoreDNS 테스트

클러스터의 CoreDNS도 함께 확인할 수 있습니다.

kubectl run dns-test --image=busybox:1.28 --rm -it --restart=Never – sh

<결과>

VXLAN - flannel

아래 다이어그램은 Flannel 기반 K8s Cluster의 Pod-to-Pod 통신 경로를 표현합니다.

다이어그램의 각 요소

Node간 통신 확인 - tcpdump

tcpdump를 통해서 노드간에 패킷이 전달되는지도 확인 가능합니다.

  1. worker2 컨테이너 접근 후 worker1으로 ping
  2. worker1에서 tcpdump 실행

--> flannel에서 VXLAN type을 사용 시, port는 default로 8472입니다.
tcpdump 확인 시, worker2에서 worker1로 패킷이 전달되는 것을 확인 가능합니다.

Pod 외부 통신

MASQUERADE 룰에 외부 라우팅 설정이 되어 있다면, 정상적으로 Pod가 외부와의 통신이 가능해야 합니다.

저의 경우 아래와 같이 설정되어 있어 외부 -> 내부 / 내부 -> 외부 통신이 문제없이 가능합니다.

-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/16 -j MASQUERADE
-A FLANNEL-POSTRTG -s 10.244.0.0/16 ! -d 224.0.0.0/4 -j MASQUERADE

실제 Worker1의 Pod Container 접근 후 외부로 ping 테스트 시, 정상적으로 통신이 됩니다. 또한, tcpdump를 통해 Pod가 eth0 인터페이스를 통해 외부로 패킷을 전달하는 것을 확인 가능합니다.

Share This Post

Check out these related posts

개발팀의 애자일 도입 이야기2

개발팀의 애자일 도입 이야기 1

Lambda@Edge 고급 로깅 제어 기능