kubernetes NodePort Networking 분석
kube-proxy = iptable 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)
환경
[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
[Test Pod 정보]
1개의 Pod 안에 tomcat 과 mysql container 2개를 생성
Pod는 worker node에 배포되어 있음
tomcat container port = 8080
mysql container port = 3306
글을 읽는데 필요한 기초 개념
Netfilter란?
Netfilter란 Network Packet Filtering Framework로
Linux Kernel Space에 위치하여
모든 오고 가는 패킷의 생명주기를 모니터링하고 통제 및 조작할 수 있는 기능을 제공함.
Netfilter는 Netfilter Hook Function을 제공하고 있음.
해당 function을 사용하여 Application을 개발하면 패킷 필터링을 할 수 있도록 해줌.
[Netfilter 5개 Hook point]
NF_IP_PRE_ROUTING: 외부에서 온 Packet이 Linux Kernel의 Network Stack을 통과하기 전에 발생하는 Hook이다. Packet을 Routing하기 전에 발생
NF_IP_LOCAL_IN: Packet이 Routing된 후 목적지가 자신일 경우, Packet을 Process에 전달하기 전에 발생
NF_IP_FORWARD: Packet이 Routing된 후 목적지가 자신이 아닐 경우, Packet을 다른 곳으로 Forwarding하는 경우 발생
NF_IP_LOCAL_OUT: Packet이 Process에서 나와 Network Stack을 통과하기 전 발생
NF_IP_POST_ROUTING: Packet이 Network Stack을 통과한 후 밖으로 보내기 전 발생
[Netfilter Framework를 사용하는 대표적인 Tool]
iptables, ip6tables, ebtables, arptables, ipset, nftables와
추가로 IPVS 가 있음.
[Netfilter Tool 동작 원리]
Netfilter Framework를 사용해서 개발된 Tool의 동작원리를 좀 더 자세히 설명하자면
해당 Tool은 Netfilter 룰 셋 구축을 하는 역할을 수행하는 것임.
Netfilter Hook Function을 사용해서 Rule을 구축하고 패킷을 컨트롤 함.
즉 실질적으로 패킷 필터링은 Linux Kernel에 탑제된 Netfilter Function이 수행함.
참고 :
https://ko.wikipedia.org/wiki/%EB%84%B7%ED%95%84%ED%84%B0
https://xenostudy.tistory.com/245
https://cognitive.tistory.com/99
https://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-4.html
iptables이란?
iptables는 Netfilter Framework를 이용하는 대표적인 Tool로
모든 오고 가는 패킷의 생명주기를 모니터링하고 통제 및 조작할 수 있음.
[iptables Chain (Rule)]
기본적으로 Iptables에는 세가지 chain이 있음.
모든 패킷은 INPUT, OUTPUT, FORWARD 이 세가지 chain중 하나를 통과하게 됨.
컴퓨터로 들어가는 모든 패킷은 INPUT chain을 통과하고,
컴퓨터에서 나가는 모든 패킷은 OUTPUT chain을 통과함.
그리고 하나의 네트워크에서 다른 곳으로 보내는 모든 패킷은 FORWARD chain을 통과함.
iptables가 작동하는 방식은 이들 각각의 INPUT, OUTPUT, FORWARD chain에 어떠한 rule을 세우는 지에 따라 달라짐.
[iptables Tables]
iptables는 5가지 Table을 제공하고 있음.
1) fileter Table
packet을 drop할지 전달할지 결정
2) NAT table
Packet NAT(Network Address Translation)을 위한 table. packet의 source/destination address를 변경
3) Mangle Table
Packet의 IP header를 바꿈. Packet의 TTL 변경, Marking하여
다른 iptables의 Table이나 Network tool에서 Packet을 구분 할 수 있도록 함
4) Raw Table
Netfilter Framework는 Hook 뿐만 아니라 Connection Tracking 기능을 제공.
이전에 도착한 Packet들을 바탕으로 방금 도착한 Packet의 Connection을 추적함.
Raw Table은 특정 Packet이 Connection Tracking에서 제외되도록 설정함.
5) Security Table
SELinux에서 Packet을 어떻게 처리할지 결정하기 위한 Table
Netfilter, iptables와 tcpdump 우선순위
Wire -> NIC -> tcpdump -> netfilter/iptables
iptables -> tcpdump -> NIC -> Wire
Chain 종류
[PREROUTING (DNAT)]
패킷의 도착지(deatination) 주소를 변경한다. D(estination)NAT
[POSTROUTING (SNAT 또는 masquerade)]
패킷의 출발지(source) 주소를 변경한다. S(ource)NAT
[OUTPUT]
호스트에서 밖으로 흐르는 패킷의 도착지(destination) 주소를 변경한다.
[INPUT]
밖에서 호스트로 흐르는 패킷의 출발지(source) 주소를 변경한다.
NAT
모든 IP 패킷에는 Source IP와 Destination IP가 있다.
NAT란, Network Address Translation, 즉 IP 패킷 헤더의 IP 주소를 변경하는 기능 혹은 절차를 뜻한다. 1:1 NAT 혹은 1:다 NAT가 있다.
PREROUTING : DNAT을 이용하여 패킷이 생길 때 사용됨.
POSTROUTING : SNAT을 이용하여 패킷이 나갈 때 사용됨.
SNAT 개념
내부 -> 외부
패킷의 Source 주소를 변경하는 것으로 Source NAT, SNAT, 혹은 IP 마스커레이드라고 한다.
인터넷으로 나가는 패킷의 Source IP를 G/W의 Public IP로 바꾼다.
DNAT 개념
외부 -> 내부
Destination IP 주소를 변경하여 내부에 접근할 수 있도록 패킷을 변경한다.
대표적인 것은 Load Balancer이다.
lsof 명령
리눅스와 유닉스는 추상화된 파일 시스템(VFS - Virtual File System)을 사용함으로
일반 파일, 디렉터리, 네트워크 소켓, 라이브러리, 심볼릭 링크 등도 모두 파일로 처리되며
lsof 에서 상세한 정보를 확인할 수 있음.
특정 port를 사용하는 프로세스 정보를 확인하기 위해서는 i 옵션을 사용하면 됨.
tcpdump
External -> Master Node IP:NodePort-> Container
Pod는 Worker Node에 배포되어있는 상태.
예제 환경
Tomcat Pod IP = 10.244.1.117
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 [Master Node IP]:NodePort
명령으로 Pod에 접근
Routing 요약
1. Master 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:02:06:7c (Master Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 192.168.56.1 (external에서 접근한 ip주소) 도착지 : 10.0.2.15 (Master Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : pago-services1 (설정된 NodePort 번호) |
( 192.168.56.1, 52:54:00:12:35:00 )
external에서 접근한 ip주소와
vritualBox 의 router mac주소
test환경은 virtualbox 환경이라 해당 ip로 접근함.
virtualbox 에서 포트포워딩 설정되어있음.
[pago-services1]
pago-services1는 30001번 port를 뜻함
30002번 port는 pago-services2라고함
/etc/services 명령을 보면 port번호와 name 맵핑을 확인할 수 있음
패킷 흐름 분석
해당 인터페이스의 내용은 virtualBox 포트포워딩에 관한 내용.
모든 Kubernetes Node의 해당 인터페이스에서
NodePort로 설정된 Port 를 감시하고 있으면
external network에서 nodePort를 통해 접근한다는 것을 확인 가능.
2. Master Node : kube-proxy
패킷을 따라가다 보면 중간에 패킷이 갑자기 다른 패킷으로 변경되는데
이를 찾다보니 패킷이 kube-proxy가 연관이 있다는것을 알아냄
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가 점유하고 있음.
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-8fc7f -n kube-system
[kube-porxy mode 확인 결과]
아래 log 내용을 보아
default mode의 경우 : iptables
test 환경의 kube-proxy의 경우 default 설정을 사용했음으로
iptables mode로 동작함.
[kube-proxy iptable Mode란?]
kube-proxy의 iptables Mode는
iptables를 사용해서 Chain Rule이라는 규칙을 지정한 뒤
패킷이 Chain Rule에 매칭되면 지정한 규칙에 따라서
패킷을 포워딩 함.
2.2. kube-proxy Netfiler (iptables) 도식화
2.3. kube-proxy iptables 분석
2.3.1. 모든 패킷은 kube-proxy가 생성한 Netfilter Chain를 거쳐야함.
[명령어]
iptables -t nat -L OUTPUT
[명령어]
iptables -t nat -L PREROUTING | column -t
[분석]
kube-proxy에 의해 생성된 KUBE-SERVICES Chain을 확인할 수 있음.
참고) PREROUTING Chain은 raw와 mangle에도 존재하는데 kube-proxy는 nat에만 규칙을 생성함.
[패킷 흐름]
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
[분석]
현재 kubernetes cluster에 생성되어있는 모든 Service Object의 정보를 확인할 수 있음.
Service Object Type 중 ClusterIP의 경우는 해당 Rule에서 바로
할당된 ClusterIP를 확인할 수 있음.
예제에서 default/iksoon-tomcat-service 의
destination ip가 10.97.155.249 인것을 확인 할 수 있는데
실제로 service object를 확인해보면
다음과 같이 10.97.155.249로 IP가 동일한 것을 확인할 수 있음
ClusterIP를 확인했지만
해당 Service는 NodePort Type임으로
NodePort 정보도 확인해야함
그러기 위해서 위에서 확인한
KUBE-NODEPORTS Rule을 확인함.
[패킷 흐름]
패킷은 PREROUTING Chain Rule에 의해
KUBE-SERVICES Chain Rule의 영향을 받게됨.
KUBE-SVC-????에 설정된 src, dst, dpt 와
패킷 정보과 일치한다면 해당 KUBE-SVC-??? Chain Rule이 적용되지만
예제에서는
[MAC 정보] 출발지 : 52:54:00:12:35:00 (Master Node 의 virbr0 인터페이스 MAC주소) 도착지 : 08:00:27:02:06:7c (Master Node 의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 192.168.56.1 (external에서 접근한 ip주소) 도착지 : 10.0.2.15 (Master Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : pago-services1 (설정된 NodePort 번호) |
위와같이 도착지 IP가 Master Node 자신의 IP이기 때문에
KUBE-NODEPORTS로 전달됨.
2.3.3. KUBE-NODEPORTS Chain의 Rule을 확인
[명령어]
iptables -t nat -L KUBE-NODEPORTS -n | column -t
[분석]
KUBE-NODEPORTS Rule을 확인해보면
Kubernetes Cluster에 있는 모든 NodePort정보를 확인할 수 있음
예제 환경에서는 NodePort가 한개 생성되어있어서 위와같이 1개를 확인할 수 있음
상위 정보의 주석부분( /* default/iksoon-tomcat-service */)을 통해
namespace = default
service object name = iksoon-tomcat-service
정보를 확인 할 수 있고
dpt:30001 정보를 통해
NodePort = 30001 로 설정되었음을 알 수 있음.
[KUBE-MARK-MASQ]
KUBE-MARK-MASQ는 iptables의 MASQUERADE (SNAT)옵션에 해당함.
external network에서 kubernetes cluster에 생성된 service obejct로 접근 할 시
접근하는 TCP 패킷에 Netfilter Mart를 추가하는 역할을 함.
즉
KUBE-NODEPORTS의 KUBE-MARK-MASQ는
Netfilter Mark로 패킷의 Source IP 주소를 Node(Host) IP주소로 변경함
[MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node flannel.1인터페이스 MAC주소로 변경됨) 도착지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.0.0 (external에서 접근한 ip주소를 Host IP주소로 변경함. master node의 flannel.1 인터페이스 ip주소가 됨.) 도착지 : 10.0.2.15 (Master Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : pago-services1 (설정된 NodePort 번호) |
해당 KUBE-MARK-MASQ을 통과한다는 증거는 아래와 같음
[명령어]
watch -n 1 iptables -t nat -L KUBE-NODEPORTS -nv
패킷이 KUBE-MARK-MASQ와 KUBE-SVC가 동시에 올라감.
[패킷 흐름]
예제 환경의 패킷 중 도착지 Port 번호를 확인함.
[MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node flannel.1인터페이스 MAC주소) 도착지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소) 도착지 : 10.0.2.15 (Master Node의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : pago-services1 (설정된 NodePort 번호) |
위와같이 도착지 Port번호가 pago-services1 즉 30001 로
KUBE-NODEPORTS 정보 중 dpt가 30001인
KUBE-SVC-TV7YSFNMBFSIUZMD 와 매칭이 됨.
2.3.4. KUBE-SVC-TV7YSFNMBFSIUZMD Chain의 Rule을 확인
[명령어]
iptables -t nat -L KUBE-SVC-TV7YSFNMBFSIUZMD -n | column -t
[분석]
KUBE-SVC-XXX Table에서는
iptables의 statistic 기능을 이용하여
요청 Packet은 Service를 구성하는 Pod들로 랜덤하고 균등하게
Load Balancing하는 역할을 수행함.
예제 환경에서 해당 service object에 매칭 되어있는 pod가 1개 임으로
위와같이 1개의 KUBE-SEP가 조회 되지만
Service Object에 다수의 pod가 매칭되는 환경이라면
다수의 KUBE-SEP가 생성되어 있고
해당 SEP 중에 한곳으로 Load Balancing 됨.
예시)
deployment replicaset 설정이 3인 경우
service obejct 에 3개의 pod가 매칭되어
아래와 같이 3개의 KUBE-SEP가 조회됨.
[패킷 흐름]
예제 환경에서는 KUBE-SEP가
KUBE-SEP-72KKHLS3BKN7AUK6 하나 있음으로
KUBE-SEP-72KKHLS3BKN7AUK6로 전달됨.
2.3.5. KUBE-SEP-72KKHLS3BKN7AUK6 Chain의 Rule을 확인
[명령어]
iptables -t nat -L KUBE-SEP-72KKHLS3BKN7AUK6 -n | column -t
[분석]
KUBE-MARK-MASQ와 DNAT가 존재함.
KUBE-SEP-XXX Table에서 요청 Packet은
Pod의 IP 및 Service에서 설정한 Port로 DNAT를 수행한다.
Pod의 IP로 DNAT된 요청 Packet은 CNI Plugin을 통해
구축된 Container Network를 통해서 해당 Pod에게 전달됨.
즉 Master Node의 cni0로 아래의 패킷을 만들어서 보냄
[KUBE-MARK-MASQ]
Netfilter Mark로 패킷의 Source IP 주소를 Node(Host) IP주소로 변경함
상위 KUBE-NODEPORTS 과정에서 TCP 패킷의 Source IP주소를 변경했고
여기서는 prot가 all로 설정되어 있는데
NodePort로 접근한 경우 해당 KUBE-MARK-MASQ은 통과하지 않는것을 확인함.
위와같이 주장하는 근거는 아래와 같음
[명령어]
watch -n 1 iptables -t nat -L KUBE-SEP-72KKHLS3BKN7AUK6 -nv
위와같이 KUBE-MARK-MASQ는 카운팅되지 않고 DNAT만 카운팅됨
해당 KUBE-MARK-MASQ은 어떤 역할을 하는것인지
추후 리서치가 필요함.
[DNAT]
최종적으로 목표로 했던 Pod IP주소와 Port번호로 패킷을 변경해줌.
즉 kube-proxy가 생성한 Netfilter Chain을 통과한 결과물임.
도착지 Mac의 경우는 Host의 ARP Table에 따라서 입력됨.
[MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node flannel.1인터페이스 MAC주소) 도착지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP주소로 변경) [Port] 출발지 : 랜덤한 Port 번호 도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경) |
2.4. 패킷 흐름 분석
enp0s3 인터페이스로 전달된 모든 패킷은
kube-proxy가 설정한 iptables Chain Rule을 통과해야함.
iptables를 통과하면서 Marking 된 패킷은 아래와 같이
출발지 정보는 Node(Host)의 정보로 변경되고
도착지 정보는 Pod의 정보로 변경됨.
[MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node flannel.1인터페이스 MAC주소) 도착지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP주소로 변경) [Port] 출발지 : 랜덤한 Port 번호 도착지 : 8080 (30001 NodePort에 맵핑된 목적지 Pod의 Port번호로 변경) |
해당 패킷은 다음 인터페이스인 flannel.1으로 전달됨.
3. Master Node : flannel.1
[명령어]
tcpdump -i flannel.1 -ne tcp -vv -c 10
[MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node flannel.1인터페이스 MAC주소) 도착지 : 12:38:cf:16:75:1b (Worker Node의 flannel.1인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip 주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 tomcat container port = 8080) |
참고) webcache = 8080을 의미함
패킷 흐름 분석
2. kube-proxy에서 설명했던 것 처럼
iptables chain을 통과한 상태의 패킷과
동일한 패킷을 확인할 수 있음
아직 이해하지 못함 부분으로는
도착지 MAC주소가 Worker Node의 flannel.1 인터페이스 주소가 들어가 있는데
해당 부분은 DNAT 과정에서 ARP Tables 정보를 확인하고
도착지 Mac 주소가 갱신됨.
일단 flannel.1 인터페이스에서 위와같은 패킷을 확인함.
이제 해당 패킷이 다음으로 어떤 인터페이스로 가는지 확인해야함.
4. Master Node : flannel.1의 ARP Table확인
해당 패킷이 다음으로 어떤 인터페이스로 가는지 확인하기 위해
Master Node의 ARP Table을 확인.
CentOS의 경우 arp 명령으로 확인할 수 있지만 아래와 같은 방법으로도 확인할 수 있음
[명령어]
kubectl get pod -o wide -n kube-system
명령으로 Master Node에서 동작 중인 Flannel Pod를 확인
[명령어]
kubectl -it exec kube-flannel-ds-ghksg -n kube-system -- arp -a
명령으로 Master Node Flannel 의 ARP Table확인
확인 결과
[MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node의 flannel.1인터페이스 MAC주소) 도착지 : 12:38:cf:16:75:1b (Worker Node의 flannel.1인터페이스 MAC주소) [IP주소 정보] 출발지 : 10.244.0.0 (master node의 flannel.1 인터페이스 ip 주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP주소) [Port] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 tomcat container port = 8080) |
이전에 통신을 했었음으로 ARP Table에 해당 MAC주소가 학습되어있음.
그래서 Master Node의 cni0 인터페이스로 가지 않고
ARP Table내용대로 enp0s3 인터페이스로 감.
Flannel.1 인터페이스는 VXLAN에서 VTEP과 동일한 역할을 수행하는데
그 작업으로 받은 패킷을 VXLAN 패킷으로 만들기 위해
패킷을 UDP를 사용하여 실제 네트워크를 통해 전송하기 위해 L3패킷으로 encapsulated (캡슐화)함.
UDP Header에는 출발지와 목적지 정보가 저장되어있고 Port는 8285 혹은 8472로 설정되어있음.
다음으로 enp0s3 인터페이스를 확인해야함.
5. Master Node : enp0s3
[명령어]
tcpdump -i enp0s3 -ne udp -vv -c 10
Port 참고) otv = 8472
패킷 흐름 분석
UDP Header에는 출발지와 목적지 정보가 저장되어있고 Port는 8472로 설정되어 있음.
확인 결과 아래와 같은 encapsulated (캡슐화) 정보를 확인할 수 있음.
Outer-packet [MAC 정보] 출발지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스의 MAC) 도착지 : 08:00:27:7c:5c:53 (Worker Node 2의 enp0s3 인터페이스의 MAC) [IP주소 정보] 출발지 : 10.0.2.15 (Master Node의 IP) 도착지 : 10.0.2.4 (Worker Node의 IP) [Port 정보] 출발지 : 랜덤한 Port 번호 도착지 : 8472 VXLAN으로 캡슐화 된 패킷 정보 [MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node의 flannel.1 인터페이스의 MAC) 도착지 : 12:38:cf:16:75:1b (Worker Node의 flannel.1 인터페이스의 MAC) [IP주소 정보] 출발지 : 10.244.0.0 (Master Node의 flannel.1 인터페이스의 IP주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP) [Port 정보] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 tomcat container port = 8080) |
다음으로는 Worker Node에서 패킷을 확인해야함.
6. Worker Node : enp0s3
Master Node의 enp0s3 인터페이스가 패킷을 Worker Node로 보내기 위해
먼저 패킷을 enp0s3과 연결되어 있는 default Router로 전송함.
그리고 default Router가 전달한 패킷을
Worker Node에서 확인가능
[명령어]
tcpdump -i enp0s3 -ne udp -vv -c 10
패킷 흐름 분석
Master Node의 enp0s3에서 확인한 결과과 같은 encapsulated (캡슐화) 패킷을 확인할 수 있음.
Outer-packet [MAC 정보] 출발지 : 08:00:27:02:06:7c (Master Node의 enp0s3 인터페이스의 MAC) 도착지 : 08:00:27:7c:5c:53 (Worker Node 2의 enp0s3 인터페이스의 MAC) [IP주소 정보] 출발지 : 10.0.2.15 (Master Node의 IP) 도착지 : 10.0.2.4 (Worker Node의 IP) [Port 정보] 출발지 : 랜덤한 Port 번호 도착지 : 8472 VXLAN으로 캡슐화 된 패킷 정보 [MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node의 flannel.1 인터페이스의 MAC) 도착지 : 12:38:cf:16:75:1b (Worker Node의 flannel.1 인터페이스의 MAC) [IP주소 정보] 출발지 : 10.244.0.0 (Master Node의 flannel.1 인터페이스의 IP주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP) [Port 정보] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 tomcat container port = 8080) |
해당 패킷은 flannel.1 인터페이스에서 캡슐화를 해제할 수 있음.
7. Worker Node : flannel.1
iptables를 통과하지만 Chain Rule에 해당하지 않기 때문에
그대로 통과함
[명령어]
tcpdump -i flannel.1 -ne tcp -vv -c 10
패킷 흐름 분석
encapsulated (캡슐화)를 해제한 패킷을 확인할 수 있음.
VXLAN으로 캡슐화 된 패킷 정보 [MAC 정보] 출발지 : 2e:bf:78:0e:53:8f (Master Node의 flannel.1 인터페이스의 MAC) 도착지 : 12:38:cf:16:75:1b (Worker Node의 flannel.1 인터페이스의 MAC) [IP주소 정보] 출발지 : 10.244.0.0 (Master Node의 flannel.1 인터페이스의 IP주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP) [Port 정보] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 tomcat container port = 8080) |
Worker Node의 ARP Table에
해당 도착지 정보가 있음으로 다음 인터페이스로 cni0로
패킷이 전달됨.
8. Worker Node : cni0
[명령어]
tcpdump -i cni0 -ne tcp and dst 10.244.1.117 -vv -c 10
패킷 흐름 분석
encapsulated (캡슐화)를 해제한 패킷을 확인할 수 있음.
MAC 주소만 변경 되어 있음
VXLAN으로 캡슐화 된 패킷 정보 [MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node의cni0 인터페이스의 MAC) 도착지 : ca:22:4b:8f:5b:79 [IP주소 정보] 출발지 : 10.244.0.0 (Master Node의 flannel.1 인터페이스의 IP주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP) [Port 정보] 출발지 : 랜덤한 Port 번호 도착지 : webcache (목적지 Pod의 tomcat container port = 8080) |
[도착지 MAC 정보 ca:22:4b:8f:5b:79]
kubectl -it exec kube-flannel-ds-5qrzc -n kube-system -- arp -a | grep 10.244.1.117
명령으로 ARP Table을 확인해보면 아래와 같은 정보를 확인할 수 있고
도착지 MAC주소 또한
조회된 MAC주소를 가지고 있음.
9. Worker Node : vethbf625505 (목적지 Pod)
vethbf625505 인터페이스가
목적지인 tomcat pod에 해당하는 인터페이스임.
Pod에 해당하는 veth 장비 찾기 참고 : Pod의 veth (Virtual Ethernet Interface) 장치 찾기
[명령어]
tcpdump -i vethbf625505 -ne tcp -vv -c 10
그리고 Pod의 tomcat container로 들어가서
tcpdump를 설치한 후 패킷을 확인해봄.
[명령어]
tcpdump -ne tcp -vv -c 10
패킷 흐름 분석
vethbf625505 인터페이스에 확인한 정보와 Pod의 tomcat container안에서 확인해본 결과가 동일함.
cni0에서 확인했던 패킷을 Pod내부의 tomcat container가 받는것을 확인할 수 있음.
VXLAN으로 캡슐화 된 패킷 정보 [MAC 정보] 출발지 : c2:c8:57:67:d6:27 (Worker Node의cni0 인터페이스의 MAC) 도착지 : ca:22:4b:8f:5b:79 [IP주소 정보] 출발지 : 10.244.0.0 (Master Node의 flannel.1 인터페이스의 IP주소) 도착지 : 10.244.1.117 (목적지 Pod의 IP) [Port 정보] 출발지 : 랜덤한 Port 번호 도착지 : 8080 (목적지 Pod의 tomcat container port) |
분석 완료..
tcpdump
External -> Worker Node IP:NodePort-> Container
Pod는 Worker Node에 배포되어있는 상태.
특징 : flannel.1 인터페이스를 거치지 않음
Pod 통신 시 netstat 명령 log 확인
한개의 Pod안에 tomcat, mysql 2개의 container 존재함.
Pod IP = 10.244.1.117
NodePort = 30001:8080
Container1 -> Container2 [localhost 주소로 통신]
[사용 명령어]
kubectl exec -it [pod이름] -c [mysql container 이름] -- /bin/bash
curl localhost:8080
Pod 내부에 있는
mysql container에서
tomcat container로
localhost:8080 통신
[결과]
로컬 = tcp6 loopback ip : 랜덤한 Port번호
외부 = tcp6 loopback ip : 8080
Container1 -> Container2 [IP 주소로 통신]
[사용 명령어]
kubectl exec -it [pod이름] -c [mysql container 이름] -- /bin/bash
curl 10.244.1.117:8080
mysql container에서
tomcat container로
[pod ip주소]:8080 통신
[결과]
로컬 = tcp Pod IP : 랜덤한 Port번호
외부 = Pod IP : 8080
External -> Master Node ip: NodePort-> Container
[사용 명령어]
curl [master node ip]:30001
(Pod는 worker node에 배포되어 있음)
master node ip : nodePort 주소를 통해서
pod ip의 8080 port로 접근
[결과]
로컬 = Pod IP : 8080
외부 = worker node의 cni0 인터페이스 : 랜덤 port 번호
External -> Worker Node ip: NodePort-> Container
[사용 명령어]
curl [worker node ip]:30001
(Pod는 worker node에 배포되어 있음)
worker node ip : nodePort 주소를 통해서
pod ip의 8080 port로 접근
[결과]
netstat 결과가 생성되지 않음
제 글을 복사할 시 출처를 명시해주세요.
글에 오타, 오류가 있다면 댓글로 알려주세요! 바로 수정하겠습니다!
iptable 모니터링 명령어
watch -n1 iptables -vnL
watch -n 1 iptables -t nat -L PREROUTING -nv
watch -n 1 iptables -t nat -L KUBE-SERVICES -nv
watch -n 1 iptables -t nat -L KUBE-NODEPORTS -nv
watch -n 1 iptables -t nat -L KUBE-SEP-72KKHLS3BKN7AUK6 -nv
일정시간이 지난 후 카운팅이됨.
참고
[kube-proxy iptable]
https://rtfm.co.ua/en/kubernetes-service-load-balancing-kube-proxy-and-iptables/
https://kubernetes.io/docs/concepts/services-networking/service/
https://sktelecom-oslab.github.io/Virtualization-Software-Lab/ExposeService/
https://arthurchiao.art/blog/cracking-k8s-node-proxy/
https://www.system-rescue.org/networking/Load-balancing-using-iptables-with-connmark/
[LoadBalancer Type의 경우 kubernetes Routing 참고]
https://www.stackrox.com/post/2020/01/kubernetes-networking-demystified/
[kubernetes routing]
https://ronaknathani.com/blog/2020/07/kubernetes-nodeport-and-iptables-rules/
[kube-proxy mode 설명]
https://ssup2.github.io/theory_analysis/Kubernetes_Service_Proxy/
https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
[iptable 개념 : KUBE-MARK-MASQ 의 MASQUERADE 패킷]
[tcpdump]
'Kubernetes > 네트워크' 카테고리의 다른 글
kubernetes NodePort Networking 분석 (kube-proxy : IPVS mode) (0) | 2021.05.07 |
---|---|
kubernetes LoadBalancer Networking 분석 (kube-proxy : iptable mode) (0) | 2021.05.06 |
Kubernetes kube-proxy IPVS Mode 설정 (1) | 2021.03.19 |
Kubernetes kube-proxy Mode 분석 (4) | 2020.12.20 |
Pod의 veth (Virtual Ethernet Interface) 장치 찾기 (0) | 2020.11.07 |