Kuberentes를 사용하면서 이해하기 어려운 부분이 CNI(Cluter Network Interface)이다.
실제로 각 CNI 마다 동작하는 방식과 구현이 다른데 CNI라고 퉁쳐서 표현하다보니 Kubernetes를 사용하는 운영자 입장에서는 CNI가 어떻게 IP Traffic(트래픽)을 처리하는지 알기 어렵다.
여러 종류의 CNI 중에서 내가 사용하고 있는 특정 CNI에 대해서 깊이 있게 설명하는 자료도 별로 없으니 스터디하기가 더욱 어렵다.
나의 일터에서는 주로 Openshift SDN을 사용하기 때문에 오늘은 시간을 내서 Openshift SDN을 깊게 파헤쳐보려 한다.
우선 아래 그림에 있는 빨간색 숫자를 따라 가면서 보자.
이 빨간 색 숫자의 순서대로 요청 패킷이 처리된다.
그림에 순서에 맞게 설명을 적었기 때문에 전반적인 설명은 필요 없을 것 같다.
단, 복잡한 처리가 있는 부분을 좀더 살펴 본다면,
(2) Netfilter를 이용하여 DNAT, SNAT 처리
Kubernetes Pod 정보를 조회해보면 Cluster IP를 볼 수 있다. 바로 그 Pod의 Cluster IP로 DNAT 처리되는 것이다.
즉, 10.10.12.208:8080 목적지 주소를 보고, 이 주소 값과 Mapping되는 Kubernetes Pod IP를 찾고 Netfilter를 이용하여 DNAT 처리한다.
Worker 1 Node에서 iptables 명령을 이용하여 Netfilter의 Chain Rule을 조회하면 실제로 아래와 같이 정보를 볼 수 있다.
이 Chain Rule대로 관련 Packet 조건을 찾고, 그 조건에 맞는 Netfilter Chain을 따라가면서 DNAT처리하는 것이다.
$ iptables -t nat -L KUBE-SERVICES -nv | grep 10.10.12.208
1760 106K KUBE-FW-BAR7JSQD2GL6A2KT tcp -- * * 0.0.0.0/0 10.10.12.208 /* almighty/almighty5:web loadbalancer IP */ tcp dpt:8080
… 중간 생략 …
$ iptables -t nat -L KUBE-SEP-ZBWV76PMI2XAVMCD -nv
1949 117K DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* almighty/almighty5:web */ tcp to:10.128.2.151:8080
—> kube-proxy가 실제 iptables 룰 생성시 사용한 명령은 아래와 같음.
KUBE-SEP-ZBWV76PMI2XAVMCD -p tcp -m comment --comment "almighty/almighty5:web" -m tcp -j DNAT --to-destination 10.128.2.151:8080
만약 Destination Pod가 다른 Worker Node에 있다면, 다른 Worker Node로 IP Packet을 보내기 위해 tun0 인터페이스를 이용하여야 한다. 이때 tun0의 IP Address로 SNAT 하도록 하는 Chain Rule 적용을 받는다.
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
OPENSHIFT-MASQUERADE all -- anywhere anywhere /* rules for masquerading OpenShift traffic */
KUBE-POSTROUTING all -- anywhere anywhere /* kubernetes postrouting rules */
Chain KUBE-POSTROUTING (1 references)
target prot opt source destination
RETURN all -- anywhere anywhere mark match ! 0x1/0x1
MARK all -- anywhere anywhere MARK xor 0x1
MASQUERADE all -- anywhere anywhere /* kubernetes service traffic requiring SNAT */ random-fully
(3) DST IP로 갈 수 있는 Routing Table을 조회하여 tun0로 Packet을 보냄
아마 대부분 Kubernetes 사용자가 헷갈려하는 부분일 것이다.
만약 Destination Pod가 같은 Worker Node에 있다면, 단순히 Netfilter가 처리한 대로 Packet Forward만 하면 된다.
그런데, Destination Pod가 다른 Worker Node에 있다면 관련있는 물리 Network Port를 찾아서 보내야 한다.
위 그림에서 Worker 1과 Worker 2의 tun0 간에는 ARP Packet이 브로드캐스팅되므로, 이미 Worker 1에서는 Destination Pod IP에 해당하는 MAC Address를 알고 있다.
(참고: arp 명령으로 Worker 1 노드의 ARP Table 조회 가능)
따라서 일반적인 L2 Forward 처리와 동일하게 처리된다.
(4) ~ (5) Encapsulate, Decapsulate
일반적인 VxLAN 터널링을 사용하여 Worker Node간에 Pod의 메시지를 전송해준다.
VxLAN 터널링 때문에 tun0의 MTU는 1450 byte가 된다. (왜냐하면, 터널링 헤더 메시지 때문에 50 Byte만큼 tun0 포트의 MTU가 작아지게 된다)
나머지 절차는 모두 L2 Switching이기 때문에 딱히 설명할 것이 없다.
응답 메시지는 따로 설명하지 않았다.
왜냐하면,
L2 Switching 구간은 단순히 Source Address와 Destination Address를 반대로 뒤집으면 되고,
Netfilter가 SNAT 처리한 부분의 Connection Track 정보를 찾아서 원래의 주소값으로 치환해주면 되기 때문이다.
블로그 작성자: sejong.jeonjo@gmail.com
'kubernetes' 카테고리의 다른 글
Kubernetes CLI Command 예제 모음 (0) | 2022.07.27 |
---|---|
kubernetes script - 모든 Node Reboot (0) | 2022.07.27 |
Podman 또는 Docker 명령으로 Image Registry 접속 시 인증(Authentication) 에러 해결 (0) | 2022.07.21 |
Docker Private Registry API 사용법 (CURL 명령 예제) (0) | 2022.07.21 |
Kubernetes Network (0) | 2022.07.20 |