kubernetes NodePort Networking 분석
kube-proxy : IPVS mode
CNI = Flannel
[kubernetes kube-proxy 관련 글 목록]
Kubernetes kube-proxy IPVS Mode 설정
Kubernetes NodePort Networking 분석 (kube-proxy : iptable mode)
Kubernetes NodePort Networking 분석 (kube-proxy : iptable mode)- New version
kubernetes LoadBalancer Networking 분석 (kube-proxy : iptable mode)
목적
kube-proxy IPVS mode의 경우
NodePort로 접근하는 Networking 과정일 분석함.
글을 읽는데 필요한 기초 개념
IPVS (IP Virtual Server)란?
IPVS는 Netfilter Framework 기반으로 구현된
Linux Kernel Level에서 동작하는
Layer-4(Transport Layer) Load Balancing Tool임.
Least-Connection 및 Round-Robin을 포함한 다양한 Load Balancing 알고리즘을 지원함.
[IPVS 동작원리]
패킷을 효과적으로 추적하고 Route하기 위해 IPVS는 Linux Kernel에
IPVS 테이블을 생성함.
해당 테이블은 해쉬 테이블임.
IPVS 테이블은 ipvsadm 명령을 사용해서 지속적으로 업데이트가 가능함.
해당 테이블 목록에 따라 특정 End Point로
설정된 Load Balancing 알고리즘을 사용해서 Load Balancing을 수행함.
[ IPVS에서 사용하는 Netfilter Hook Function ]
Netfilter Framework 기반으로 구현되어
제공되는 Netfilter Hook Function 목록 중 아래의 6개를 사용해서 구현함.
ip_vs_remote_request()
ip_vs_local_request()
ip_vs_reply()
ip_vs_local_reply()
ip_vs_forward_icmp()
[IPVS 설정 명령]
ipvsadm
[IPVS Tunneling 종류]
Direct Routing
NAT
IPIP
[IPVS를 사용하는 환경]
Linux에서 제공하는 L4 Load Balancer 솔루션인 LVS( Linux Virtual Server )에서도
Packet Load Balancing 메카니즘으로 IPVS를 사용되고 있음.
참고
https://ssup2.github.io/theory_analysis/Linux_LVS_IPVS/
https://github.com/kubernetes/kubernetes/blob/master/pkg/proxy/ipvs/README.md
IPSET이란?
iptables의 확장 기능인 ipset은 IP들의 집합을 별도로 만들어 관리 할 수 있음.
iptables 유틸을 통해 관리 할 때보다
ipset은 좀 더 다양한 방법으로 많은 IP 셋을 관리 할 수 있는 이점과
인덱싱 데이터 저장 방식으로 인해
iptables로 5000건 이상의 룰셋이 등록 되었을때
시스템의 성능이 급격하게 떨어지는 반면
ipset은 많은 IP 세트를 설정 하더라도 성능이 심각하게 떨어지지 않는 장점이있음.
iptables는 차단하고자하는 룰셋 목록이 많아지면 유지보수가 힘든데
이를 해결하기 위한 방법으로 IPSET을 많이 이용함.
환경
[Master Node server]
OS = CentOS 7
리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64
docker version : 1.13.1
docker api verison : 1.26
[Worker Node server]
OS = CentOS 7
리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64
docker version : 1.13.1
api verison : 1.26
[kubernetes version]
1.19.2
[생성되어있는 Pod, Service 정보]
pod1 IP = 10.244.1.160
pod2 IP = 10.244.1.169
pod3 IP = 10.244.1.170
pod4 IP = 10.244.1.171
NodePort Service = 10.109.153.101:30001
LoadBalancer Service = external 10.0.2.10:31857
tcpdump
External -> Worker Node IP:NodePort-> Container
Pod는 Worker Node에 배포되어있는 상태.
환경
Tomcat Pod
pod1 IP = 10.244.1.160
pod2 IP = 10.244.1.169
pod3 IP = 10.244.1.170
pod4 IP = 10.244.1.171
Service Object Type = NodePort 30001
Tomcat Pod 배포 Node = Worker Node
Tomcat Pod Port = 8080
Master Node IP = 10.0.2.15
Worker Node IP = 10.0.2.4
이외의 정보는 문서 상단위 "환경"에서 설명한 정보와 동일
external 환경에서
curl [Worker Node IP]:NodePort
명령으로 Pod에 접근
NodePort Routing
1. Worker Node : enp0s3
VirtualBox의 경우 : enp0s3
VMware 의 경우 : ens192
에 해당하는 인터페이스임,
[명령어]
tcpdump -i enp0s3 -ne tcp port 30001 -vv -c 10
[MAC 정보] 출발지 : 52:54:00:12:35:00 (VirtualBox Router Mac) 도착지 : 08:00:27:7c:5c:53 (Worker Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 192.168.56.1 (external에서 접근한 ip주소) 도착지 : 10.0.2.4 (Worker Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : pago-services1 (설정된 NodePort 번호 30001) |
( 192.168.56.1, 52:54:00:12:35:00 )
external에서 접근한 ip주소와
vritualBox 의 Router Mac 주소
test환경은 virtualbox 환경이라 해당 ip로 접근함.
virtualbox 에서 포트포워딩 설정되어있음.
패킷 흐름 분석
해당 인터페이스의 내용은 virtualBox 포트포워딩에 관한 내용.
모든 Kubernetes Node의 해당 인터페이스에서
NodePort로 설정된 Port 를 감시하고 있으면
external network에서 nodePort를 통해 접근한다는 것을 확인 가능.
2. Worker Node : kube-proxy
nodeport = 30001임으로
lsof 명령으로 30001 port를 사용하는 프로세스를 확인
[명령어]
lsof -i:30001
[netstat 명령]
netstat -nap | grep kube-proxy
[확인 결과]
kube-proxy pod가 모든 NodePort 수신하고 있음.
NodePort Type의 service object를 생성하면
kube-proxy가 모든 NodePort를 포트 예약하고
다른 프로세스가 사용할 수 없도록 함.
즉 test환경에서는
30001대 port를 kube-proxy가 수신하고 있어서
해당 패킷은 kube-proxy로 감.
2.1. kube-proxy Mode 확인
Kube-proxy는 user space, iptables, ipvs 와 같은 mode로 동작할 수 있음으로
어떤 mode로 동작하는지 확인해야함.
[kube-proxy mode 확인 명령어]
kubectl logs -f [베포되어있는 kube-proxy pod 이름] -n kube-system
예) kubectl logs -f pod/kube-proxy-gcvm4 -n kube-system
[kube-porxy mode 확인 결과]
아래 log 내용을 보아
IPVS mode로 동작함.
2.2. kube-proxy Netfiler (iptables) 도식화
2.3. kube-proxy iptables 분석
kube-proxy IPVS mode에서 IPVS는 Load Balancing은 가능하지만
패킷 Filtering, hairpin-masquerade , SNAT 등등의 작업은 처리 할 수 없음.
그래서 iptables 기능을 최소한으로 사용해야했으며
kube-proxy iptables mode 처럼 많은 룰을 생성하면 안되니
ipset기술을 사용하여 문제를 해결함.
2.3.1. 모든 패킷은 kube-proxy가 생성한 iptables chain를 거쳐야함.
[명령어]
iptables -t nat -L OUTPUT
[분석]
kube-proxy에 의해 생성된 KUBE-SERVICES Chain을 확인할 수 있음.
[패킷 흐름]
enp0s3 인터페이스로 전달된 모든 패킷은
Host의 Network Namespace로 전달되고
해당 패킷은 OUTPUT Rule 중
src = anywhere
dst = anywhere
Rule에 매칭되어
kube-proxy가 생성한 KUBE-SERVICES Chain Rule에 적용되기 시작함.
2.3.2. KUBE-SERVICES Chain의 Rule을 확인
[명령어]
iptables -t nat -L KUBE-SERVICES -n | column -t
[분석]
(KUBE-LOAD-BALANCER)
패킷은 Chain 규칙에 따라 가장 처음에 있는 KUBE-LOAD-BALANCER Chain의 조건 에 맞는지 확인함
조건에 맞는지 확인하기 위해 KUBE-LOAD-BALANCER Chain과 match-set 되어있는
ipset 리스트 중 하나인 KUBE-LOAD-BALANCER를 확인하게 됨.
ipset -L 명령 목록 중 KUBE-LOAD-BALANCER를 확인해보면 아래와 같이
Members로 10.0.2.10:8080만 등록되어있음.
현재 Packet의 dst는 10.0.2.4:30001 임으로 매칭 되지 않아서
해당 Chain은 적용되지 않고 통과하게 됨
적용되지 않고 통과된다는 증거로 아래의 그림을 확인해 보면
KUBE-LOAD-BALANCER의 pkts는 증가하지 않는것을 확인 할 수 있음.
(KUBE-MARK-MASQ)
패킷은 그 다음인 KUBE-MARK-MASQ Chain 조건을 확인함
조건을 확인해보니 source ip가 일치하지 않아 Chain을 타지 않고
다음으로 패킷은 KUBE-NODE-PORT Chain으로 가게됨.
(KUBE-NODE-PORT)
KUBE-NODE-PORT Chain source destination에 해당함으로
KUBE-NODE-PORT Chain을 분석해야함.
[패킷 흐름]
KUBE-NODEPORTS Chain으로 전달됨.
2.3.3. KUBE-NODE-PORT Chain의 Rule을 확인
[명령어]
iptables -t nat -L KUBE-NODE-PORT -n
[분석]
KUBE-NODE-PORT Chain은 match-set : KUBE-NODE-PORT-TCP 로 연결되어
ipset 리스트 중 KUBE-NODE-PORT-TCP를 확인하게 됨.
[명령어]
ipset -L
결과 중 KUBE-NODE-PORT-TCP 부분을 확인
참고로 해당 ipset -L 명령 결과는 kubernetes 를 구성하는 모든 Node가 동일함.
위와 같이 ipset의 KUBE-NODE-PORT-TCP 에 30001 항목이 있고
패킷의 정보 중 dst Port를 확인해보면
[MAC 정보] 출발지 : 52:54:00:12:35:00 (VirtualBox Router Mac) 도착지 : 08:00:27:7c:5c:53 (Worker Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 192.168.56.1 (external에서 접근한 ip주소) 도착지 : 10.0.2.4 (Worker Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : pago-services1 (설정된 NodePort 번호 30001) |
위와같이 Port가 30001번으로 일치함.
해당 ipset Rule 매칭이 됨으로
패킷은 KUBE-NODE-PORT Chain에 적용됨.
적용 되었다는 증거는 아래와 같음
KUBE-NODE-PORT pkts 만 증가되는 것을 확인 가능
그래서 KUBE-MARK-MASQ Chain을 타게됨.
[KUBE-MARK-MASQ]
KUBE-MARK-MASQ는 iptables의 MASQUERADE (SNAT)옵션에 해당함.
external network에서 kubernetes cluster에 생성된 service obejct로 접근 할 시
접근하는 모든 패킷에 Netfilter Mart를 추가하는 역할을 함.
[MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node(Host) cni0 인터페이스 MAC주소 변경됨) 도착지 : 08:00:27:7c:5c:53 (Worker Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.1.1 (Worker Node(Host)의 cni0인터페이스 IP주소로 변경됨) 도착지 : 10.0.2.4 (Worker Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호로 변경됨. 도착지 : pago-services1 (설정된 NodePort 번호 30001) |
Netfilter Mark로 패킷의 Source IP 주소를 Node(Host) IP주소로 변경함
해당 KUBE-MARK-MASQ를 탄다는 증거
위와 같이 KUBE-NODE-PORT Chain의 KUBE-MARK-MASQ Chain pkts가 증가는것을 확인가능
[패킷 흐름]
출발지 정보를 SNAT으로 변경하고
패킷은 IPVS로 전달됨.
(iptables Netfilter Chain을 나온 패킷이 어떻게 IPVS로 가는지에 대한
자세한 부분은 리서치가 추가로 필요함.)
2.3.4. IPVS Hash Tables 확인
[명령어]
ipvsadm -Ln
해당 ipvsadm -Ln명령은 kubernetes 를 구성하는 모든 Node가 동일함.
[분석]
상위의 결과 중에 매칭되는것을 찾기 위해
패킷의 정보 중 dst 정보를 확인해보면
[MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node(Host) cni0 인터페이스 MAC주소) 도착지 : 08:00:27:7c:5c:53 (Worker Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.1.1 (Worker Node(Host)의 cni0인터페이스 IP주소) 도착지 : 10.0.2.4 (Worker Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : pago-services1 (설정된 NodePort 번호 30001) |
dst = 10.0.2.4:30001
정보를 확인할 수 있음.
해당 정보는 IPVS Hash Tables의
TCP 10.0.2.4:30001 rr -> 10.244.1.160:8080 Masq 1 0 0 -> 10.244.1.169:8080 Masq 1 0 0 -> 10.244.1.170:8080 Masq 1 0 0 -> 10.244.1.171:8080 Masq 1 0 0 |
결과와 일치함.
해당 Tables 하위의 4개 IP가 목적지 Pod 목록의 IP와 일치함.
rr 표시를 보고 해당 목록 중 대상 결정은
Round-Robin 알고리즘을 통해서 결정된다는 것을 알 수 있음.
[패킷 흐름]
IPVS를 통해 DNAT이 수행되어
목적지가 해당 Pod목록 중 1개로 선정됨.
[MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node(Host) cni0 인터페이스 MAC주소) 도착지 : ??? (Host의 ARP Tables 정보를 보고 도착지 IP에 해당하는 MAC으로 변경됨.) [IP주소 정보] 출발지 : 10.244.1.1 (Worker Node(Host)의 cni0인터페이스 IP주소) 도착지 : 10.244.1. 160, 169, 170, 171 중 1개 (목적지 Pod의 주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : 8080 (목적지 Pod의 Port) |
2.4. 패킷 흐름 분석
enp0s3 인터페이스로 전달된 모든 패킷은
kube-proxy가 설정한 iptables, ipset Chain Rule을 통해
IPVS로 전달됨.
IPVS에서는 Hash Tables 정보를 확인하고
다수의 Pod 목록 중 1개를 선택하기 위해
Load Balancing을 수행함.
IPVS를 통과하면서 Marking 된 패킷은 아래와 같이
출발지 정보는 Node(Host)의 정보로 변경되고
도착지 정보는 Pod의 정보로 변경됨.
[MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node(Host) cni0 인터페이스 MAC주소) 도착지 : ??? (Host의 ARP Tables 정보를 보고 도착지 IP에 해당하는 MAC으로 변경됨.) [IP주소 정보] 출발지 : 10.244.1.1 (Worker Node(Host)의 cni0인터페이스 IP주소) 도착지 : 10.244.1. 160, 169, 170, 171 중 1개 (목적지 Pod의 주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : 8080 (목적지 Pod의 Port) |
해당 패킷은 다음 인터페이스인 cni0로 전달됨.
3. Worker Node : flannel.1 확인
[명령어]
tcpdump -i flannel.1 -ne tcp -vv -c 10
패킷 흐름 분석
worker node의 flannel.1 인터페이스에 어떠한 패킷도 들어오지 않음.
4. Worker Node : flannel.1의 ARP Table확인
flannel.1에 어떠한 패킷도 들어오지 않는 이유를 확인하기 위해
Worker Node의 ARP Table을 확인
[명령어]
arp -an
해당 명령은 Worker Node에서 실행
명령으로 Worker Node Flannel 의 ARP Table확인
[확인 결과]
이전에 통신을 했었음으로 ARP Table 목적지 Pod의 IP주소와 Mac주소가 있음.
그래서 패킷이 Worker Node의 flannel.1에서 탐지되지 않고
cni0 인터페이스로 바로 이동함.
5. Worker Node : cni0 확인
[명령어]
tcpdump -i cni0 -ne tcp and dst 10.244.1.171 -vv -c 10
패킷 흐름 분석
도착지 MAC정보가 ARP Tables의 Pod의 정보로 변경된것을 확인할 수 있음
[MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node의 cni0 인터페이스 MAC주소) 도착지 : 3e:52:d6:a9:e3:94 ( ARP Table정보에서 확인했던 Pod Mac 주소) [IP주소 정보] 출발지 : 10.244.1.1 (Worker Node cni0 인터페이스 IP) 도착지 : 10.244.1.171 중 1개 (목적지 Pod의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 Port : 8080) |
6. Worker Node : veth60fa0925 (목적지 Pod)
[명령어]
tcpdump -i veth60fa0925 -ne tcp -vv -c 10
veth60fa0925 인터페이스가
목적지인 tomcat pod에 해당하는 인터페이스임.
Pod에 해당하는 veth 장비 찾기 참고 : Pod의 veth (Virtual Ethernet Interface) 장치 찾기
패킷 흐름 분석
cni0에서 확인했던 패킷을 Pod내부의 tomcat container가 받는것을 확인할 수 있음.
[MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node의 cni0 인터페이스 MAC주소) 도착지 : 3e:52:d6:a9:e3:94 ( ARP Table정보에서 확인했던 Pod Mac 주소) [IP주소 정보] 출발지 : 10.244.1.1 (Worker Node cni0 인터페이스 IP) 도착지 : 10.244.1.171 중 1개 (목적지 Pod의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 Port : 8080) |
분석 완료..
제 글을 복사할 시 출처를 명시해주세요.
글에 오타, 오류가 있다면 댓글로 알려주세요! 바로 수정하겠습니다!
'Kubernetes > 네트워크' 카테고리의 다른 글
Kubernetes NodePort Networking 분석 (kube-proxy : iptable mode) New version (1) | 2024.07.15 |
---|---|
kubernetes CNI 종류 확인 방법 (0) | 2021.11.04 |
kubernetes LoadBalancer Networking 분석 (kube-proxy : iptable mode) (0) | 2021.05.06 |
Kubernetes NodePort Networking 분석 (kube-proxy : iptable mode) (1) | 2021.05.06 |
Kubernetes kube-proxy IPVS Mode 설정 (1) | 2021.03.19 |