Ssoon

[4주차] ClusterIP 본문

쿠버네티스 네트워크 스터디 3기

[4주차] ClusterIP

구구달스 2024. 9. 23. 18:53
CloudNet@ 가시다님이 진행하는 쿠버네티스 네트워크 스터디 3기

✅ 구성 정보

  • 목적지(backend) 파드(Pod) 생성 정보
cat <<EOT> 3pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: webpod1
  labels:	#Pod에 대한 레이블을 지정합니다. 특정 Pod을 선택할 때 사용합니다.
    app: webpod
spec:
  nodeName: myk8s-worker	#Pod가 배포될 노드의 이름
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0	#Pod가 종료될 때 바로 종료
---
apiVersion: v1
kind: Pod
metadata:
  name: webpod2
  labels:
    app: webpod
spec:
  nodeName: myk8s-worker2
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: webpod3
  labels:
    app: webpod
spec:
  nodeName: myk8s-worker3
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
EOT
  • 클라이언트(TestPod) 생성 정보
cat <<EOT> netpod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: net-pod
spec:
  nodeName: myk8s-control-plane
  containers:
  - name: netshoot-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]	#tail -f /dev/null은 무한 루프를 실행하는 명령으로, Pod가 종료되지 않고 계속 실행
  terminationGracePeriodSeconds: 0
EOT
  • 서비스(ClusterIP) 생성정보
cat <<EOT> svc-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc-clusterip
spec:
  ports:
    - name: svc-webport
      port: 9000        # 서비스 IP 에 접속 시 사용하는 포트 port 를 의미
      targetPort: 80    # 타킷 targetPort 는 서비스를 통해서 목적지 파드로 접속 시 해당 파드로 접속하는 포트를 의미
  selector:
    app: webpod         # 셀렉터 아래 app:webpod 레이블이 설정되어 있는 파드들은 해당 서비스에 연동됨
  type: ClusterIP       # 서비스 타입
EOT
  • 목적지 Pod, 테스트 Pod, 서비스Pod 를 생성합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 3pod.yaml,netpod.yaml,svc-clusterip.yaml
pod/webpod1 created
pod/webpod2 created
pod/webpod3 created
pod/net-pod created
service/svc-clusterip created
  • Kubernetes 클러스터의 네트워크 설정을 확인합니다.
    1. --service-cluster-ip-range=10.200.1.0/24:
      • 서비스 클러스터 IP 범위를 정의합니다.
      • 클러스터 내에서 Kubernetes 서비스가 사용하는 IP 주소 범위를 나타냅니다. 여기서 10.200.1.0/24는 서비스에 할당할 수 있는 IP 주소 범위를 의미합니다. 
    2. --cluster-cidr=10.10.0.0/16:
      • 클러스터 CIDR은 Pod들이 사용하는 IP 주소 범위를 나타냅니다.
      • 10.10.0.0/16는 클러스터 내에서 Pod에 할당되는  IP 주소 범위를 나타냅니다. 각 Pod은 이 범위 내의 IP를 할당받아 네트워크 통신을 하게 됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl cluster-info dump | grep -m 2 -E "cluster-cidr|service-cluster-ip-range"
                            "--service-cluster-ip-range=10.200.1.0/24",
                            "--cluster-cidr=10.10.0.0/16",
  • 생성된 각 Pod 의 정보를 확인할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get pod -owide
NAME      READY   STATUS    RESTARTS   AGE   IP          NODE                  NOMINATED NODE   READINESS GATES
net-pod   1/1     Running   0          22s   10.10.0.6   myk8s-control-plane   <none>           <none>
webpod1   1/1     Running   0          22s   10.10.3.2   myk8s-worker          <none>           <none>
webpod2   1/1     Running   0          22s   10.10.1.2   myk8s-worker2         <none>           <none>
webpod3   1/1     Running   0          22s   10.10.2.3   myk8s-worker3         <none>           <none>


  • Selector: app=webpod
    • 이 서비스가 라우팅할 대상인 Pod을 선택하는 기준입니다. app=webpod 레이블을 가진 Pod들이 이 서비스에 연결됩니다.
  • Type: ClusterIP
    • 이 서비스는 ClusterIP 타입으로, 클러스터 내부에서만 접근 가능한 서비스입니다.
  • IP: 10.200.1.118
    • 이 서비스에 할당된 클러스터 IP 주소입니다. 클러스터 내부에서만 접근할 수 있습니다
  • Port: svc-webport 9000/TCP
    • 서비스가 클러스터 내부에서 TCP 포트 9000으로 트래픽을 받습니다.
  • TargetPort: 80/TCP
    • 이 서비스가 요청을 전달할 Pod의 컨테이너 포트입니다. 즉, 서비스는 외부에서 9000번 포트로 요청을 받고, 이를 컨테이너의 80번 포트로 전달합니다.
  • Endpoints: 10.10.2.3:80, 10.10.1.2:80, 10.10.3.2:80
    • 이 서비스가 트래픽을 전달하는 실제 Pod들의 IP와 포트 정보입니다. 여기서는 세 개의 Pod(10.10.2.3, 10.10.1.2, 10.10.3.2)이 연결되어 있으며, 각 Pod의 80번 포트로 트래픽이 전달됩니다.
  • Session Affinity: None
    • 클라이언트의 세션이 특정 Pod에 고정되지 않고, 요청마다 다른 Pod으로 트래픽이 전달될 수 있습니다.
  • Internal Traffic Policy: Cluster
    • 이 정책은 서비스 내부 트래픽을 처리하는 방법을 정의합니다. Cluster는 트래픽이 클러스터 내의 모든 노드에 있는 Pod으로 전달될 수 있음을 의미합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc svc-clusterip
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
svc-clusterip   ClusterIP   10.200.1.118   <none>        9000/TCP   33s

(⎈|kind-myk8s:N/A) root@kind:~# kubectl describe svc svc-clusterip
Name:                     svc-clusterip
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=webpod
Type:                     ClusterIP
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.200.1.118
IPs:                      10.200.1.118
Port:                     svc-webport  9000/TCP
TargetPort:               80/TCP
Endpoints:                10.10.2.3:80,10.10.1.2:80,10.10.3.2:80
Session Affinity:         None
Internal Traffic Policy:  Cluster
Events:                   <none>

(⎈|kind-myk8s:N/A) root@kind:~# kubectl get endpoints svc-clusterip
NAME            ENDPOINTS                                AGE
svc-clusterip   10.10.1.2:80,10.10.2.3:80,10.10.3.2:80   9m4s

(⎈|kind-myk8s:N/A) root@kind:~# kubectl get endpointslices -l kubernetes.io/service-name=svc-clusterip
NAME                  ADDRESSTYPE   PORTS   ENDPOINTS                       AGE
svc-clusterip-h2dwm   IPv4          80      10.10.2.3,10.10.1.2,10.10.3.2   9m10s

서비스(ClusterIP) 접속

  • webpod 파드의 IP를 변수에 지정합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get pod -l app=webpod -o jsonpath="{.items[*].status.podIP}"
10.10.3.2 10.10.1.2 10.10.2.3

(⎈|kind-myk8s:N/A) root@kind:~# WEBPOD1=$(kubectl get pod webpod1 -o jsonpath={.status.podIP})
(⎈|kind-myk8s:N/A) root@kind:~# WEBPOD2=$(kubectl get pod webpod2 -o jsonpath={.status.podIP})
(⎈|kind-myk8s:N/A) root@kind:~# WEBPOD3=$(kubectl get pod webpod3 -o jsonpath={.status.podIP})

(⎈|kind-myk8s:N/A) root@kind:~# echo $WEBPOD1 $WEBPOD2 $WEBPOD3
10.10.3.2 10.10.1.2 10.10.2.3
  • net-pod에서 curl을 사용하여 $WEBPOD1, $WEBPOD2, $WEBPOD3 각각에 HTTP 요청을 보냅니다. 이때 각 Pod의 응답이 net-pod에서 확인됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# for pod in $WEBPOD1 $WEBPOD2 $WEBPOD3; do kubectl exec -it net-pod -- curl -s $pod; done
Hostname: webpod1
IP: 127.0.0.1
IP: ::1
IP: 10.10.3.2
IP: fe80::7cf7:7bff:fe30:81ed
RemoteAddr: 10.10.0.6:60766
GET / HTTP/1.1
Host: 10.10.3.2
User-Agent: curl/8.7.1
Accept: */*
...

(⎈|kind-myk8s:N/A) root@kind:~# for pod in $WEBPOD1 $WEBPOD2 $WEBPOD3; do kubectl exec -it net-pod -- curl -s $pod | grep Hostname; done
Hostname: webpod1
Hostname: webpod2
Hostname: webpod3

(⎈|kind-myk8s:N/A) root@kind:~# for pod in $WEBPOD1 $WEBPOD2 $WEBPOD3; do kubectl exec -it net-pod -- curl -s $pod | grep Host; done
Hostname: webpod1
Host: 10.10.3.2
Hostname: webpod2
Host: 10.10.1.2
Hostname: webpod3
Host: 10.10.2.3

(⎈|kind-myk8s:N/A) root@kind:~# for pod in $WEBPOD1 $WEBPOD2 $WEBPOD3; do kubectl exec -it net-pod -- curl -s $pod | egrep 'Host|RemoteAddr'; done
Hostname: webpod1
RemoteAddr: 10.10.0.6:57772
Host: 10.10.3.2
Hostname: webpod2
RemoteAddr: 10.10.0.6:52874
Host: 10.10.1.2
Hostname: webpod3
RemoteAddr: 10.10.0.6:51342
Host: 10.10.2.3
  • svc-clusterip라는 서비스의 클러스터 IP를 가져와서 SVC1이라는 변수에 저장하는 작업을 수행합니다.
(⎈|kind-myk8s:N/A) root@kind:~# SVC1=$(kubectl get svc svc-clusterip -o jsonpath={.spec.clusterIP})

(⎈|kind-myk8s:N/A) root@kind:~# echo $SVC1
10.200.1.118
  • 컨테이너 myk8s-control-plane 안에서 실행된 iptables 명령의 결과를 필터링하여, 특정 서비스에 대한 NAT 규칙을 조회합니다.
    • -A KUBE-SERVICES: KUBE-SERVICES 체인에 규칙을 추가합니다.
    • -d 10.200.1.118/32: 목적지 IP 주소가 10.200.1.118인 패킷에 대해 적용됩니다.
    • -p tcp: TCP 프로토콜에 대한 규칙입니다.
    • --dport 9000: 9000 포트로 들어오는 패킷에 대해 적용됩니다.
    • -j KUBE-SVC-KBDEBIL6IU6WL7RF: 패킷을 KUBE-SVC-KBDEBIL6IU6WL7RF라는 다른 체인으로 전달합니다.
    • -A KUBE-SVC-KBDEBIL6IU6WL7RF: 이전 규칙에서 지정한 체인에 규칙을 추가합니다.
    • ! -s 10.10.0.0/16: 출발지 IP 주소가 10.10.0.0/16 범위에 포함되지 않는 패킷에 대해 적용됩니다.
    • -d 10.200.1.118/32: 목적지 IP 주소가 10.200.1.118인 패킷에 대해 적용됩니다.
    • -j KUBE-MARK-MASQ: 이 규칙을 만족하는 패킷에 대해 마스커레이드(MASQUERADE) 마크를 설정합니다. 주로 NAT 처리를 위해 사용됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane iptables -t nat -S | grep $SVC1
-A KUBE-SERVICES -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-SVC-KBDEBIL6IU6WL7RF
-A KUBE-SVC-KBDEBIL6IU6WL7RF ! -s 10.10.0.0/16 -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-MARK-MASQ

(⎈|kind-myk8s:N/A) root@kind:~# for i in control-plane worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-control-plane iptables -t nat -S | grep $SVC1; echo; done
>> node myk8s-control-plane <<
-A KUBE-SERVICES -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-SVC-KBDEBIL6IU6WL7RF
-A KUBE-SVC-KBDEBIL6IU6WL7RF ! -s 10.10.0.0/16 -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-MARK-MASQ

>> node myk8s-worker <<
-A KUBE-SERVICES -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-SVC-KBDEBIL6IU6WL7RF
-A KUBE-SVC-KBDEBIL6IU6WL7RF ! -s 10.10.0.0/16 -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-MARK-MASQ

>> node myk8s-worker2 <<
-A KUBE-SERVICES -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-SVC-KBDEBIL6IU6WL7RF
-A KUBE-SVC-KBDEBIL6IU6WL7RF ! -s 10.10.0.0/16 -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-MARK-MASQ

>> node myk8s-worker3 <<
-A KUBE-SERVICES -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-SVC-KBDEBIL6IU6WL7RF
-A KUBE-SVC-KBDEBIL6IU6WL7RF ! -s 10.10.0.0/16 -d 10.200.1.118/32 -p tcp -m comment --comment "default/svc-clusterip:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-MARK-MASQ
  • curl 명령어를 사용해 $SVC1:9000으로 요청을 보냈고, webpod3에서 요청이 처리되었습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1
command terminated with exit code 28

(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1:9000
Hostname: webpod3
IP: 127.0.0.1
IP: ::1
IP: 10.10.2.3
IP: fe80::e4b0:d1ff:fe03:2c65
RemoteAddr: 10.10.0.6:38044
GET / HTTP/1.1
Host: 10.200.1.118:9000
User-Agent: curl/8.7.1
Accept: */*

(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1:9000 | grep Hostname
Hostname: webpod3

(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1:9000 | grep Hostname
Hostname: webpod2
  • $SVC1:9000에 대한 요청이 webpod1, webpod2, webpod3에서 응답을 받고 있다는 것을 보여줍니다.
    • webpod1이 가장 많이 응답했음을 알 수 있으며, 이는 Kubernetes의 로드 밸런싱 메커니즘이 각 Pod에 트래픽을 분산하고 있다는 것을 의미합니다.
    • 각 Pod의 응답 수가 다르므로, 트래픽 분산에 있어 약간의 편향이 있을 수 있습니다. 이는 Pod의 상태나 요청 시점의 부하에 따라 달라질 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- zsh -c "for i in {1..10};   do curl -s $SVC1:9000 | grep Hostname; done | sort | uniq -c | sort -nr"
      5 Hostname: webpod1
      3 Hostname: webpod2
      2 Hostname: webpod3

(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- zsh -c "for i in {1..100};  do curl -s $SVC1:9000 | grep Hostname; done | sort | uniq -c | sort -nr"
     39 Hostname: webpod2
     31 Hostname: webpod1
     30 Hostname: webpod3

(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- zsh -c "for i in {1..1000}; do curl -s $SVC1:9000 | grep Hostname; done | sort | uniq -c | sort -nr"
    350 Hostname: webpod3
    326 Hostname: webpod1
    324 Hostname: webpod2
  • conntrack -E 명령어는 현재 커넥션 트래킹 상태를 실시간으로 모니터링하는 데 사용됩니다.
    • src=127.0.0.1 dst=127.0.0.1: 출발지와 목적지가 모두 로컬호스트(127.0.0.1)임을 나타냅니다.
root@myk8s-control-plane:/# conntrack -E
    [NEW] tcp      6 120 SYN_SENT src=127.0.0.1 dst=127.0.0.1 sport=46868 dport=2381 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=46868
 [UPDATE] tcp      6 60 SYN_RECV src=127.0.0.1 dst=127.0.0.1 sport=46868 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=46868
 [UPDATE] tcp      6 86400 ESTABLISHED src=127.0.0.1 dst=127.0.0.1 sport=46868 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=46868 [ASSURED]
 [UPDATE] tcp      6 120 FIN_WAIT src=127.0.0.1 dst=127.0.0.1 sport=46868 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=46868 [ASSURED]
 [UPDATE] tcp      6 30 LAST_ACK src=127.0.0.1 dst=127.0.0.1 sport=46868 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=46868 [ASSURED]
 [UPDATE] tcp      6 120 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=46868 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=46868 [ASSURED]
...
  • conntrack -L --src 10.10.0.6 명령어는 특정 출발지 IP(여기서는 10.10.0.6) [net-pod] 에 대한 현재 커넥션 트래킹 상태를 나열합니다
    1. src=10.10.0.6 dst=10.200.1.118:
      • src=10.10.0.6: 출발지 IP 주소.  [net-pod]
      • dst=10.200.1.118: 목적지 IP 주소, 여기서는 서비스의 클러스터 IP입니다. [svc-clusterip]
    2. sport=60674 dport=9000
      • sport=60674: 출발지 포트 번호.
      • dport=9000: 목적지 포트 번호. 이 경우, 서비스 포트입니다.
    3. src=10.10.3.2 dst=10.10.0.6
      • src=10.10.3.2: 연결을 수립한 서버의 IP 주소. [webpod1]
      • dst=10.10.0.6: 응답을 받는 클라이언트의 IP 주소.  [net-pod]
      • sport=80 dport=60674
    4. sport=80 dport=60674
      • sport=80: 서버의 출발지 포트 번호 (HTTP 서비스 포트).
      • dport=60674: 클라이언트의 포트 번호.
root@myk8s-control-plane:/# conntrack -L --src 10.10.0.6
tcp      6 53 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=60674 dport=9000 src=10.10.3.2 dst=10.10.0.6 sport=80 dport=60674 [ASSURED] mark=0 use=1
tcp      6 65 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=59276 dport=9000 src=10.10.3.2 dst=10.10.0.6 sport=80 dport=59276 [ASSURED] mark=0 use=1
tcp      6 65 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=60482 dport=9000 src=10.10.1.2 dst=10.10.0.6 sport=80 dport=60482 [ASSURED] mark=0 use=1
tcp      6 68 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=36066 dport=9000 src=10.10.1.2 dst=10.10.0.6 sport=80 dport=36066 [ASSURED] mark=0 use=1
tcp      6 65 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=60066 dport=9000 src=10.10.1.2 dst=10.10.0.6 sport=80 dport=60066 [ASSURED] mark=0 use=1
...

 

  • 특정 목적지 IP(여기서는 10.200.1.118) [svc-clusterip] 에 대한 현재 커넥션 트래킹 상태를 나열합니다.
    1. src=10.10.0.6 dst=10.200.1.118:
      • src=10.10.0.6: 출발지 IP 주소 (클라이언트).  [net-pod]
      • dst=10.200.1.118: 목적지 IP 주소  [svc-clusterip]
    2. sport=45996 dport=9000:
      • sport=45996: 출발지 포트 번호 (클라이언트의 포트).
      • dport=9000: 목적지 포트 번호 (서비스의 포트).
    3. src=10.10.3.2 dst=10.10.0.6:
      • src=10.10.3.2: 연결을 수립한 서버의 IP 주소. [webpod1]
      • dst=10.10.0.6: 응답을 받는 클라이언트의 IP 주소.  [net-pod]
    4. sport=80 dport=45996:
      • sport=80: 서버의 출발지 포트 번호 (HTTP 서비스 포트).
      • dport=45996: 클라이언트의 포트 번호.
root@myk8s-control-plane:/# conntrack -L --dst 10.200.1.118
tcp      6 113 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=45996 dport=9000 src=10.10.3.2 dst=10.10.0.6 sport=80 dport=45996 [ASSURED] mark=0 use=1
tcp      6 110 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=45968 dport=9000 src=10.10.1.2 dst=10.10.0.6 sport=80 dport=45968 [ASSURED] mark=0 use=1
tcp      6 119 TIME_WAIT src=10.10.0.6 dst=10.200.1.118 sport=42552 dport=9000 src=10.10.1.2 dst=10.10.0.6 sport=80 dport=42552 [ASSURED] mark=0 use=1
...
  1. Bridge chain: INPUT, entries: 0, policy: ACCEPT:
    • Bridge chain: INPUT: 이 체인은 브리지에서 수신되는 패킷을 처리합니다.
    • entries: 0: 현재 이 체인에 등록된 규칙의 수입니다. 여기서는 규칙이 없습니다.
    • policy: ACCEPT: 기본 정책입니다. 즉, 규칙이 없을 경우 수신된 패킷을 허용합니다.
  2. Bridge chain: FORWARD, entries: 0, policy: ACCEPT:
    • Bridge chain: FORWARD: 이 체인은 브리지를 통해 전달되는 패킷을 처리합니다.
    • entries: 0: 현재 이 체인에 등록된 규칙이 없습니다.
    • policy: ACCEPT: 기본 정책은 패킷을 허용합니다.
  3. Bridge chain: OUTPUT, entries: 0, policy: ACCEPT:
    • Bridge chain: OUTPUT: 이 체인은 브리지에서 송신되는 패킷을 처리합니다.
    • entries: 0: 현재 이 체인에 등록된 규칙이 없습니다.
    • policy: ACCEPT: 기본 정책은 패킷을 허용합니다.
  • 현재 브리지 필터 테이블에는 어떠한 규칙도 정의되어 있지 않으며, 모든 패킷(수신, 전달, 송신)에 대해 기본적으로 허용(ACCEPT) 정책이 설정되어 있습니다.
root@myk8s-control-plane:/# ebtables -L
Bridge table: filter

Bridge chain: INPUT, entries: 0, policy: ACCEPT

Bridge chain: FORWARD, entries: 0, policy: ACCEPT

Bridge chain: OUTPUT, entries: 0, policy: ACCEPT
  • 각 node의 네트워크 정보를 확인합니다.

[ myk8s-worker ]

(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-worker bash
root@myk8s-worker:/# ip -c link
...
2: veth72a21f90@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 86:59:c6:b5:4d:c9 brd ff:ff:ff:ff:ff:ff link-netns cni-9275422a-388e-a234-07ef-a20672c46f08
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0

root@myk8s-worker:/# ip -c addr
...
2: veth72a21f90@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 86:59:c6:b5:4d:c9 brd ff:ff:ff:ff:ff:ff link-netns cni-9275422a-388e-a234-07ef-a20672c46f08
    inet 10.10.3.1/32 scope global veth72a21f90
       valid_lft forever preferred_lft forever
    inet6 fe80::8459:c6ff:feb5:4dc9/64 scope link
       valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fc00:f853:ccd:e793::3/64 scope global nodad
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe12:3/64 scope link
       valid_lft forever preferred_lft forever
  1. default via 172.18.0.1 dev eth0:
    • 기본 경로로, 어떤 목적지 IP가 명시되지 않았을 때 패킷이 172.18.0.1로 전송됩니다. 사용되는 인터페이스는 eth0입니다.
  2. 10.10.0.0/24 via 172.18.0.2 dev eth0:
    • 10.10.0.0부터 10.10.0.255까지의 IP로 가는 경로입니다. 패킷은 172.18.0.2를 통해 eth0 인터페이스로 전송됩니다.
  3. 10.10.1.0/24 via 172.18.0.5 dev eth0:
    • 10.10.1.0부터 10.10.1.255까지의 IP로 가는 경로입니다. 패킷은 172.18.0.5를 통해 eth0 인터페이스로 전송됩니다.
  4. 10.10.2.0/24 via 172.18.0.4 dev eth0:
    • 10.10.2.0부터 10.10.2.255까지의 IP로 가는 경로입니다. 패킷은 172.18.0.4를 통해 eth0 인터페이스로 전송됩니다.
  5. 10.10.3.2 dev veth72a21f90 scope host:
    • 10.10.3.2에 대한 경로입니다. 패킷은 veth72a21f90 인터페이스를 통해 전송되며, 이 IP는 호스트 내에서만 유효합니다.
  6. 172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.3:
    • 172.18.0.0부터 172.18.255.255까지의 서브넷에 대한 경로입니다. eth0 인터페이스를 통해 전송되며, 이 경로는 커널에 의해 생성되었습니다. 소스 IP는 172.18.0.3입니다.
root@myk8s-worker:/# ip -c route
default via 172.18.0.1 dev eth0
10.10.0.0/24 via 172.18.0.2 dev eth0
10.10.1.0/24 via 172.18.0.5 dev eth0
10.10.2.0/24 via 172.18.0.4 dev eth0
10.10.3.2 dev veth72a21f90 scope host
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.3

 

[ myk8s-worker2 ]

root@myk8s-worker2:/# ip -c link
...
2: veth9bbeeb96@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 6a:ea:87:e8:cf:06 brd ff:ff:ff:ff:ff:ff link-netns cni-1296e189-2f9e-20fa-443b-412cafa3009d
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:ac:12:00:05 brd ff:ff:ff:ff:ff:ff link-netnsid 0

root@myk8s-worker2:/# ip -c route
default via 172.18.0.1 dev eth0
10.10.0.0/24 via 172.18.0.2 dev eth0
10.10.1.2 dev veth9bbeeb96 scope host
10.10.2.0/24 via 172.18.0.4 dev eth0
10.10.3.0/24 via 172.18.0.3 dev eth0
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.5

root@myk8s-worker2:/# ip -c addr
...
2: veth9bbeeb96@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 6a:ea:87:e8:cf:06 brd ff:ff:ff:ff:ff:ff link-netns cni-1296e189-2f9e-20fa-443b-412cafa3009d
    inet 10.10.1.1/32 scope global veth9bbeeb96
       valid_lft forever preferred_lft forever
    inet6 fe80::68ea:87ff:fee8:cf06/64 scope link
       valid_lft forever preferred_lft forever
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:05 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.5/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fc00:f853:ccd:e793::5/64 scope global nodad
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe12:5/64 scope link
       valid_lft forever preferred_lft forever

 

[ myk8s-worker3 ]

root@myk8s-worker3:/# ip -c link
...
3: veth3dd7c033@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 5e:54:e2:ba:96:07 brd ff:ff:ff:ff:ff:ff link-netns cni-2ec54245-b914-d35f-0518-20969fe3e1e6
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0

root@myk8s-worker3:/# ip -c route
default via 172.18.0.1 dev eth0
10.10.0.0/24 via 172.18.0.2 dev eth0
10.10.1.0/24 via 172.18.0.5 dev eth0
10.10.2.3 dev veth3dd7c033 scope host
10.10.3.0/24 via 172.18.0.3 dev eth0
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.4

root@myk8s-worker3:/# ip -c addr
...
3: veth3dd7c033@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 5e:54:e2:ba:96:07 brd ff:ff:ff:ff:ff:ff link-netns cni-2ec54245-b914-d35f-0518-20969fe3e1e6
    inet 10.10.2.1/32 scope global veth3dd7c033
       valid_lft forever preferred_lft forever
    inet6 fe80::5c54:e2ff:feba:9607/64 scope link
       valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.4/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fc00:f853:ccd:e793::4/64 scope global nodad
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe12:4/64 scope link
       valid_lft forever preferred_lft forever
  • 10번의 요청 결과로 Hostname이 3개(즉, webpod1, webpod2, webpod3)에서 반복적으로 반환되었습니다.
  • 이 결과는 서비스의 가용성과 로드 밸런싱 기능을 보여줍니다. Pod들이 균일하게 요청을 처리하고 있다는 것을 확인할 수 있으며, 이로 인해 전체 시스템의 부하가 분산되고 있는 것을 나타냅니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- zsh -c "for i in {1..10};   do curl -s $SVC1:9000 | grep Hostname; done; sleep 1: done"
Hostname: webpod2
Hostname: webpod3
Hostname: webpod1
Hostname: webpod3
Hostname: webpod1
Hostname: webpod1
Hostname: webpod2
Hostname: webpod1
Hostname: webpod2
Hostname: webpod3
  •  eth0 의 TCP 포트 80에서 발생하는 패킷 트래픽으로 클라이언트와 서버 간의 TCP 연결이 성공적으로 수립되고 데이터 전송이 이루어지고 있음을 확인할 수 있습니다.
    • 10.10.0.6.32834 > 10.10.3.2.80: 출발지 IP 10.10.0.6의 포트 32834에서 목적지 IP 10.10.3.2의 포트 80으로의 트래픽입니다.
    • 10.10.3.2.80 > 10.10.0.6.32834: 그에 대한 응답으로, 목적지 IP 10.10.3.2의 포트 80에서 출발지 IP 10.10.0.6의 포트 32834로의 트래픽입니다.
  • TCP 포트 9000에서 발생하는 패킷 트래픽은 확인할 수 없습니다.

[ myk8s-worker ]

root@myk8s-worker:/# tcpdump -i eth0 tcp port 80 -nnq
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:17:22.546817 IP 10.10.0.6.32834 > 10.10.3.2.80: tcp 0
12:17:22.546857 IP 10.10.3.2.80 > 10.10.0.6.32834: tcp 0
12:17:22.546879 IP 10.10.0.6.32834 > 10.10.3.2.80: tcp 0
12:17:22.546964 IP 10.10.0.6.32834 > 10.10.3.2.80: tcp 80
12:17:22.546980 IP 10.10.3.2.80 > 10.10.0.6.32834: tcp 0
12:17:22.547516 IP 10.10.3.2.80 > 10.10.0.6.32834: tcp 310
...

root@myk8s-worker:/# tcpdump -i eth0 tcp port 9000 -nnq
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
...

[ myk8s-worker2 ]

root@myk8s-worker2:/# tcpdump -i eth0 tcp port 80 -nnq
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:17:22.534148 IP 10.10.0.6.32816 > 10.10.1.2.80: tcp 0
12:17:22.534197 IP 10.10.1.2.80 > 10.10.0.6.32816: tcp 0
12:17:22.534228 IP 10.10.0.6.32816 > 10.10.1.2.80: tcp 0
12:17:22.534327 IP 10.10.0.6.32816 > 10.10.1.2.80: tcp 80
12:17:22.534344 IP 10.10.1.2.80 > 10.10.0.6.32816: tcp 0
12:17:22.534743 IP 10.10.1.2.80 > 10.10.0.6.32816: tcp 310
...

root@myk8s-worker2:/# tcpdump -i eth0 tcp port 9000 -nnq
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
...

[ myk8s-worker 3]

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:17:22.540882 IP 10.10.0.6.32826 > 10.10.2.3.80: tcp 0
12:17:22.540933 IP 10.10.2.3.80 > 10.10.0.6.32826: tcp 0
12:17:22.540961 IP 10.10.0.6.32826 > 10.10.2.3.80: tcp 0
12:17:22.541106 IP 10.10.0.6.32826 > 10.10.2.3.80: tcp 80
12:17:22.541123 IP 10.10.2.3.80 > 10.10.0.6.32826: tcp 0
12:17:22.541446 IP 10.10.2.3.80 > 10.10.0.6.32826: tcp 310
...

root@myk8s-worker3:/# tcpdump -i eth0 tcp port 9000 -nnq
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
...
  • eth0 의 80번 포트를 ngrep 명령어로 네트워크 패킷을 캡처하고 필터링하여 내용을 출력합니다..
    • ngrep -tW byline -d eth0 '' 'tcp port 80':
      • -t : 타임스탬프를 포함하여 각 패킷의 출력을 표시합니다.
      • -W byline : 출력 형식을 설정합니다. byline은 패킷의 내용을 줄 단위로 표시하여 읽기 쉽게 합니다.
      • -d eth0: eth0 인터페이스에서 패킷을 캡처합니다.
      • '': 이 부분은 빈 문자열로, 모든 패킷을 캡처하겠다는 의미입니다. 필터링 조건이 없으므로 모든 데이터가 포함됩니다.
      • 'tcp port 80': TCP 프로토콜을 사용하고 포트 80에서 통신하는 패킷만 캡처하겠다는 조건입니다. 
root@myk8s-worker:~# ngrep -tW byline -d eth0 '' 'tcp port 80'
interface: eth0 (172.18.0.0/255.255.0.0)
filter: ( tcp port 80 ) and ((ip || ip6) || (vlan && (ip || ip6)))
####
T 2024/09/23 12:25:31.200602 10.10.0.6:47116 -> 10.10.3.2:80 [AP] #4
GET / HTTP/1.1.
Host: 10.200.1.118:9000.
User-Agent: curl/8.7.1.
Accept: */*.
.

##
T 2024/09/23 12:25:31.201132 10.10.3.2:80 -> 10.10.0.6:47116 [AP] #6
HTTP/1.1 200 OK.
Date: Mon, 23 Sep 2024 12:25:31 GMT.
Content-Length: 192.
Content-Type: text/plain; charset=utf-8.
.
Hostname: webpod1
IP: 127.0.0.1
IP: ::1
IP: 10.10.3.2
IP: fe80::7cf7:7bff:fe30:81ed
RemoteAddr: 10.10.0.6:47116
GET / HTTP/1.1.
Host: 10.200.1.118:9000.
User-Agent: curl/8.7.1.
Accept: */*.
.
  • VETH  에서 80포트로 tecpdump 결과 [net-pod](10.10.0.6)가 [webpod1]  (10.10.3.2)에게 SYN 패킷을 보내고, 서버는 SYN-ACK으로 하는 것을 확인할 수 있습니다.
  • TCP 포트 9000에서 발생하는 패킷 트래픽은 확인할 수 없습니다.

[ myk8s-worker ]

root@myk8s-worker:~# tcpdump -i $VETH1 tcp port 80 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on veth72a21f90, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:29:31.337463 IP 10.10.0.6.49862 > 10.10.3.2.80: Flags [S], seq 2393005995, win 64240, options [mss 1460,sackOK,TS val 830098404 ecr 0,nop,wscale 7], length 0
12:29:31.337480 IP 10.10.3.2.80 > 10.10.0.6.49862: Flags [S.], seq 3962254440, ack 2393005996, win 65160, options [mss 1460,sackOK,TS val 866396304 ecr 830098404,nop,wscale 7], length 0
12:29:31.337511 IP 10.10.0.6.49862 > 10.10.3.2.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 830098404 ecr 866396304], length 0
12:29:31.337598 IP 10.10.0.6.49862 > 10.10.3.2.80: Flags [P.], seq 1:81, ack 1, win 502, options [nop,nop,TS val 830098404 ecr 866396304], length 80: HTTP: GET / HTTP/1.1
12:29:31.337605 IP 10.10.3.2.80 > 10.10.0.6.49862: Flags [.], ack 81, win 509, options [nop,nop,TS val 866396304 ecr 830098404], length 0
12:29:31.338048 IP 10.10.3.2.80 > 10.10.0.6.49862: Flags [P.], seq 1:311, ack 81, win 509, options [nop,nop,TS val 866396305 ecr 830098404], length 310: HTTP: HTTP/1.1 200 OK
12:29:31.338101 IP 10.10.0.6.49862 > 10.10.3.2.80: Flags [.], ack 311, win 501, options [nop,nop,TS val 830098405 ecr 866396305], length 0
12:29:31.338317 IP 10.10.0.6.49862 > 10.10.3.2.80: Flags [F.], seq 81, ack 311, win 501, options [nop,nop,TS val 830098405 ecr 866396305], length 0
12:29:31.338374 IP 10.10.3.2.80 > 10.10.0.6.49862: Flags [F.], seq 311, ack 82, win 509, options [nop,nop,TS val 866396305 ecr 830098405], length 0
12:29:31.338415 IP 10.10.0.6.49862 > 10.10.3.2.80: Flags [.], ack 312, win 501, options [nop,nop,TS val 830098405 ecr 866396305], length 0

root@myk8s-worker:~# tcpdump -i $VETH1 tcp port 9000 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on veth72a21f90, link-type EN10MB (Ethernet), snapshot length 262144 bytes
...

[ myk8s-worker2 ]

root@myk8s-worker2:/# tcpdump -i $VETH1 tcp port 80 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on veth9bbeeb96, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:29:31.354890 IP 10.10.0.6.49896 > 10.10.1.2.80: Flags [S], seq 3521193546, win 64240, options [mss 1460,sackOK,TS val 830098422 ecr 0,nop,wscale 7], length 0
12:29:31.354905 IP 10.10.1.2.80 > 10.10.0.6.49896: Flags [S.], seq 3179706539, ack 3521193547, win 65160, options [mss 1460,sackOK,TS val 4181934224 ecr 830098422,nop,wscale 7], length 0
12:29:31.354935 IP 10.10.0.6.49896 > 10.10.1.2.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 830098422 ecr 4181934224], length 0
12:29:31.355023 IP 10.10.0.6.49896 > 10.10.1.2.80: Flags [P.], seq 1:81, ack 1, win 502, options [nop,nop,TS val 830098422 ecr 4181934224], length 80: HTTP: GET / HTTP/1.1
12:29:31.355031 IP 10.10.1.2.80 > 10.10.0.6.49896: Flags [.], ack 81, win 509, options [nop,nop,TS val 4181934224 ecr 830098422], length 0
12:29:31.355883 IP 10.10.1.2.80 > 10.10.0.6.49896: Flags [P.], seq 1:311, ack 81, win 509, options [nop,nop,TS val 4181934225 ecr 830098422], length 310: HTTP: HTTP/1.1 200 OK
12:29:31.355939 IP 10.10.0.6.49896 > 10.10.1.2.80: Flags [.], ack 311, win 501, options [nop,nop,TS val 830098423 ecr 4181934225], length 0
12:29:31.356156 IP 10.10.0.6.49896 > 10.10.1.2.80: Flags [F.], seq 81, ack 311, win 501, options [nop,nop,TS val 830098423 ecr 4181934225], length 0
12:29:31.356246 IP 10.10.1.2.80 > 10.10.0.6.49896: Flags [F.], seq 311, ack 82, win 509, options [nop,nop,TS val 4181934225 ecr 830098423], length 0
12:29:31.356340 IP 10.10.0.6.49896 > 10.10.1.2.80: Flags [.], ack 312, win 501, options [nop,nop,TS val 830098423 ecr 4181934225], length 0

root@myk8s-worker2:/# tcpdump -i $VETH1 tcp port 9000 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on veth9bbeeb96, link-type EN10MB (Ethernet), snapshot length 262144 bytes
...

[ myk8s-worker3 ]

root@myk8s-worker3:/# tcpdump -i $VETH1 tcp port 80 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on veth3dd7c033, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:29:31.330962 IP 10.10.0.6.49852 > 10.10.2.3.80: Flags [S], seq 3570306752, win 64240, options [mss 1460,sackOK,TS val 830098398 ecr 0,nop,wscale 7], length 0
12:29:31.330976 IP 10.10.2.3.80 > 10.10.0.6.49852: Flags [S.], seq 2144570794, ack 3570306753, win 65160, options [mss 1460,sackOK,TS val 1945568758 ecr 830098398,nop,wscale 7], length 0
12:29:31.331003 IP 10.10.0.6.49852 > 10.10.2.3.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 830098398 ecr 1945568758], length 0
12:29:31.331100 IP 10.10.0.6.49852 > 10.10.2.3.80: Flags [P.], seq 1:81, ack 1, win 502, options [nop,nop,TS val 830098398 ecr 1945568758], length 80: HTTP: GET / HTTP/1.1
12:29:31.331108 IP 10.10.2.3.80 > 10.10.0.6.49852: Flags [.], ack 81, win 509, options [nop,nop,TS val 1945568758 ecr 830098398], length 0
12:29:31.331511 IP 10.10.2.3.80 > 10.10.0.6.49852: Flags [P.], seq 1:311, ack 81, win 509, options [nop,nop,TS val 1945568758 ecr 830098398], length 310: HTTP: HTTP/1.1 200 OK
12:29:31.331583 IP 10.10.0.6.49852 > 10.10.2.3.80: Flags [.], ack 311, win 501, options [nop,nop,TS val 830098398 ecr 1945568758], length 0
12:29:31.331749 IP 10.10.0.6.49852 > 10.10.2.3.80: Flags [F.], seq 81, ack 311, win 501, options [nop,nop,TS val 830098399 ecr 1945568758], length 0
12:29:31.331803 IP 10.10.2.3.80 > 10.10.0.6.49852: Flags [F.], seq 311, ack 82, win 509, options [nop,nop,TS val 1945568759 ecr 830098399], length 0
12:29:31.331844 IP 10.10.0.6.49852 > 10.10.2.3.80: Flags [.], ack 312, win 501, options [nop,nop,TS val 830098399 ecr 1945568759], length 0

root@myk8s-worker3:/#
root@myk8s-worker3:/# tcpdump -i $VETH1 tcp port 9000 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on veth3dd7c033, link-type EN10MB (Ethernet), snapshot length 262144 bytes
...
  • VETH 의 80번 포트를 ngrep 명령어로 네트워크 패킷을 캡처하고 필터링하여 내용을 출력합니다.
root@myk8s-worker:~# ngrep -tW byline -d $VETH1 '' 'tcp port 80'
interface: veth72a21f90 (10.10.3.1/255.255.255.255)
filter: ( tcp port 80 ) and ((ip || ip6) || (vlan && (ip || ip6)))
####
T 2024/09/23 12:36:17.547410 10.10.0.6:51504 -> 10.10.3.2:80 [AP] #4
GET / HTTP/1.1.
Host: 10.200.1.118:9000.
User-Agent: curl/8.7.1.
Accept: */*.
.

##
T 2024/09/23 12:36:17.547787 10.10.3.2:80 -> 10.10.0.6:51504 [AP] #6
HTTP/1.1 200 OK.
Date: Mon, 23 Sep 2024 12:36:17 GMT.
Content-Length: 192.
Content-Type: text/plain; charset=utf-8.
.
Hostname: webpod1
IP: 127.0.0.1
IP: ::1
IP: 10.10.3.2
IP: fe80::7cf7:7bff:fe30:81ed
RemoteAddr: 10.10.0.6:51504
GET / HTTP/1.1.
Host: 10.200.1.118:9000.
User-Agent: curl/8.7.1.
Accept: */*.
.

IPTABLES 정책

 


  • PREROUTING
    • PREROUTING 체인은 외부에서 들어오는 패킷이 시스템의 네트워크 스택으로 진입할 때 가장 먼저 적용되는 규칙을 설정합니다. 이 체인은 패킷의 목적지를 결정하는 데 사용됩니다.
    • PREROUTING은 다음과 같은 기능을 수행합니다:
      • 패킷의 목적지를 변경(예: 포트 포워딩)
      • 패킷을 특정 서비스로 전달

  • iptables의 NAT(Network Address Translation) 테이블의 PREROUTING 체인을 확인합니다.
    • 1555: 이 규칙에 매칭된 패킷 수.
    • 93270: 이 규칙에 매칭된 총 바이트 수.
    • KUBE-SERVICES: 이 규칙이 매핑하는 타겟 체인입니다. Kubernetes 서비스 포털로 패킷을 전달합니다. 
      • KUBE-SERVICES는 Kubernetes의 기본 네트워크 규칙을 관리하는 체인입니다. 이 체인은 NAT(Network Address Translation) 테이블의 일부로, 클러스터 내의 서비스에 대한 트래픽을 처리합니다.
      • 즉, 클러스터 외부에서 들어오는 요청을 적절한 파드로 전달하는 역할을 합니다. KUBE-SERVICES는 이러한 요청을 매핑하여 서비스를 올바른 파드로 라우팅합니다.
    • 0.0.0.0/0: 출발지와 목적지가 모든 IP 주소를 포함함을 의미합니다.
    •  
    • 2: 이 규칙에 매칭된 패킷 수.
    • 170: 이 규칙에 매칭된 총 바이트 수.
    • DOCKER_OUTPUT: 이 규칙이 매핑하는 타겟 체인입니다. Docker의 출력 체인으로 패킷을 전달합니다.
      • DOCKER_OUTPUT 체인은 Docker 컨테이너에서 외부로 나가는 트래픽을 처리하는 규칙들을 포함하고 있습니다. 즉, Docker 컨테이너가 외부 네트워크(예: 인터넷)로 요청을 보낼 때, 이 체인을 통해 패킷이 전달됩니다.
    • 0.0.0.0/0: 출발지 주소가 모든 IP를 포함함을 의미합니다.
    • 172.18.0.1: 특정 목적지 IP 주소입니다.
root@myk8s-control-plane:/# iptables -v --numeric --table nat --list PREROUTING
Chain PREROUTING (policy ACCEPT 202 packets, 12168 bytes)
 pkts bytes target     prot opt in     out     source               destination
 1555 93270 KUBE-SERVICES  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    2   170 DOCKER_OUTPUT  0    --  *      *       0.0.0.0/0            172.18.0.1

  • KUBE-SERVICES 체인은 클러스터 외부에서 들어오는 요청을 Kubernetes 서비스로 라우팅합니다.
  • 각 서비스는 클러스터 내에서 특정 IP 주소를 가지고 있습니다.
  • KUBE-SVC(SerViCe)-{ }
    • 이 체인은 쿠버네티스 서비스(예: 클러스터 IP)에 대한 트래픽을 처리합니다. 각 서비스마다 별도의 체인이 생성됩니다. 
    • 클러스터 IP로 들어오는 트래픽을 처리합니다. 예를 들어, 클러스터 IP가 10.200.1.1인 경우, 이 IP로 들어온 요청을 이 체인에서 처리하며, 이 서비스가 연결된 포드들 중 하나로 트래픽을 전달하게 됩니다.
    • 체인의 각 규칙은 KUBE-SEP(Kubernetes Service EndPoint)라는 또 다른 체인으로 트래픽을 전달합니다. KUBE-SEP 체인들은 실제로 트래픽을 수신할 수 있는 포드들을 가리킵니다. 이 방식으로 트래픽이 적절한 포드로 전달됩니다.
root@myk8s-control-plane:/# iptables -v --numeric --table nat --list KUBE-SERVICES
Chain KUBE-SERVICES (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-SVC-NPX46M4PTMTKRN6Y  6    --  *      *       0.0.0.0/0            10.200.1.1           /* default/kubernetes:https cluster IP */ tcp dpt:443
    0     0 KUBE-SVC-TCOU7JCQXEZGVUNU  17   --  *      *       0.0.0.0/0            10.200.1.10          /* kube-system/kube-dns:dns cluster IP */ udp dpt:53
    0     0 KUBE-SVC-ERIFXISQEP7F7OF4  6    --  *      *       0.0.0.0/0            10.200.1.10          /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:53
    0     0 KUBE-SVC-JD5MR3NA4I4DYORP  6    --  *      *       0.0.0.0/0            10.200.1.10          /* kube-system/kube-dns:metrics cluster IP */ tcp dpt:9153
    0     0 KUBE-SVC-7EJNTS7AENER2WX5  6    --  *      *       0.0.0.0/0            10.200.1.47          /* kube-system/kube-ops-view:http cluster IP */ tcp dpt:8080
   60  3600 KUBE-SVC-KBDEBIL6IU6WL7RF  6    --  *      *       0.0.0.0/0            10.200.1.118         /* default/svc-clusterip:svc-webport cluster IP */ tcp dpt:9000
 5938  356K KUBE-NODEPORTS  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

  • 쿠버네티스 서비스의 트래픽을 특정 포드로 전달하는 규칙을 정의합니다.
    • KUBE-MARK-MASQ :
      • ClusterIP 10.200.1.118 (서비스 svc-webport의 IP)로 오는 TCP 포트 9000 패킷에 마스커레이드 마크를 추가합니다.
      • 패킷에 마스커레이드 마크를 추가함으로써 이 패킷이 NAT 처리를 받아야 한다는 것을 표시합니다.
    • KUBE-SEP-TBW2IYJKUCAC7GB3
      • 모든 패킷을 포드 10.10.1.2의 TCP 포트 80로 전달 (33% 확률).
    • KUBE-SEP-SZHENXPAXVOCHRDA :
      • 모든 패킷을 포드 10.10.2.3의 TCP 포트 80로 전달 (50% 확률).
    • KUBE-SEP-2TLZC6QOUTI37HEJ
      • 모든 패킷을 포드 10.10.3.2의 TCP 포트 80로 전달.
  • KUBE-SEP (Kubernetes Endpoint)
    • Kubernetes 서비스의 특정 엔드포인트(포드)를 나타내는 iptables 체인입니다. 이는 서비스를 제공하는 포드들의 IP 주소와 포트를 관리하고, 클라이언트 요청이 해당 포드로 라우팅되도록 합니다.
      • 트래픽 분산: 클라이언트가 서비스에 요청을 보내면 KUBE-SEP 체인이 사용되어 요청을 서비스의 여러 포드로 분산합니다. 이 과정에서 각 포드의 IP 주소와 포트가 사용됩니다.
      • 부하 분산: 여러 엔드포인트가 있을 경우 KUBE-SEP는 랜덤이나 라운드 로빈 방식으로 트래픽을 분배하여 부하를 조절합니다.
root@myk8s-control-plane:/# iptables -v --numeric --table nat --list KUBE-SVC-KBDEBIL6IU6WL7RF
Chain KUBE-SVC-KBDEBIL6IU6WL7RF (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-MARK-MASQ  6    --  *      *      !10.10.0.0/16         10.200.1.118         /* default/svc-clusterip:svc-webport cluster IP */ tcp dpt:9000
  443 26580 KUBE-SEP-TBW2IYJKUCAC7GB3  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/svc-clusterip:svc-webport -> 10.10.1.2:80 */ statistic mode random probability 0.33333333349
  452 27120 KUBE-SEP-SZHENXPAXVOCHRDA  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/svc-clusterip:svc-webport -> 10.10.2.3:80 */ statistic mode random probability 0.50000000000
  435 26100 KUBE-SEP-2TLZC6QOUTI37HEJ  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/svc-clusterip:svc-webport -> 10.10.3.2:80 */

  • Kubernetes 서비스의 특정 엔드포인트(포드)를 나타내는 iptables 체인으로, 이 체인의 규칙을 통해 서비스와 포드 간의 트래픽을 관리합니다.
    • KUBE-MARK-MASQ
      • 패킷에 마스커레이드 마크 추가.
      • 출발지 IP가 10.10.1.2인 패킷에 대해, 외부에서 보이지 않도록 IP 주소를 변환.
    • 두 번째 규칙 (DNAT):
      • 요청을 특정 포드로 리디렉션.
      • 모든 출발지의 요청을 포드 10.10.1.2의 80 포트로 전송
root@myk8s-control-plane:/# iptables -v --numeric --table nat --list KUBE-SEP-TBW2IYJKUCAC7GB3
Chain KUBE-SEP-TBW2IYJKUCAC7GB3 (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-MARK-MASQ  0    --  *      *       10.10.1.2            0.0.0.0/0            /* default/svc-clusterip:svc-webport */
  446 26760 DNAT       6    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/svc-clusterip:svc-webport */ tcp to:10.10.1.2:80

root@myk8s-control-plane:/# iptables -v --numeric --table nat --list KUBE-SEP-SZHENXPAXVOCHRDA
Chain KUBE-SEP-SZHENXPAXVOCHRDA (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-MARK-MASQ  0    --  *      *       10.10.2.3            0.0.0.0/0            /* default/svc-clusterip:svc-webport */
  454 27240 DNAT       6    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/svc-clusterip:svc-webport */ tcp to:10.10.2.3:80

root@myk8s-control-plane:/# iptables -v --numeric --table nat --list KUBE-SEP-2TLZC6QOUTI37HEJ
Chain KUBE-SEP-2TLZC6QOUTI37HEJ (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-MARK-MASQ  0    --  *      *       10.10.3.2            0.0.0.0/0            /* default/svc-clusterip:svc-webport */
  440 26400 DNAT       6    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/svc-clusterip:svc-webport */ tcp to:10.10.3.2:80

  • iptables를 사용하여 NAT(Network Address Translation) 테이블의 POSTROUTING 체인과 KUBE-POSTROUTING 체인의 규칙을 확인합니다.
    • RETURN
      • 특정 조건을 만족하는 패킷을 체인 처리에서 제외.
      • 패킷이 마크가 0x4000이 아닌 경우 처리하지 않고 반환.
    • MARK
      • 패킷에 마크 추가.
      • 모든 패킷에 0x4000 마크를 XOR 방식으로 추가.
    • MASQUERADE:
      • 출발지 IP를 변환.
      • Kubernetes 서비스 트래픽에 대해 SNAT를 수행하여 클러스터 외부에서 내부 IP를 숨김 처리.
root@myk8s-control-plane:/# iptables -t nat --zero

root@myk8s-control-plane:/# iptables -v --numeric --table nat --list cali-POSTROUTING; echo ; iptables -v --numeric --table nat --list KUBE-POSTROUTING; echo ; iptables -v --numeric --table nat --list cali-nat-outgoing
iptables v1.8.9 (nf_tables): chain `cali-POSTROUTING' in table `nat' is incompatible, use 'nft' tool.

Chain KUBE-POSTROUTING (1 references)
 pkts bytes target     prot opt in     out     source               destination
  106  6360 RETURN     0    --  *      *       0.0.0.0/0            0.0.0.0/0            mark match ! 0x4000/0x4000
    0     0 MARK       0    --  *      *       0.0.0.0/0            0.0.0.0/0            MARK xor 0x4000
    0     0 MASQUERADE  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ random-fully

iptables v1.8.9 (nf_tables): chain `cali-nat-outgoing' in table `nat' is incompatible, use 'nft' tool.

  • -N KUBE-POSTROUTING
    • 새로운 체인 KUBE-POSTROUTING을 생성합니다. 이 체인은 Kubernetes가 네트워크 패킷의 Postrouting(출발지 주소 변환) 처리를 위해 사용합니다.
  • -A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
    • POSTROUTING 체인에 규칙을 추가하여 KUBE-POSTROUTING 체인으로 트래픽을 전달합니다. 즉, 패킷이 라우팅된 후 KUBE-POSTROUTING 체인에서 추가적인 처리를 하도록 지정합니다.
    • --comment 옵션을 사용해 이 규칙이 Kubernetes의 Postrouting 처리 규칙임을 명시적으로 설명합니다.
  • -A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
    • 패킷에 마크가 없으면(! --mark 0x4000/0x4000), 더 이상 이 체인에서 처리를 하지 않고 **반환(RETURN)**합니다. 즉, 이 규칙은 이미 처리된 패킷을 필터링하기 위해 사용됩니다.
  • -A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
    • 모든 패킷에 0x4000 값을 마크로 설정합니다. 이 마크는 다음 규칙에서 패킷을 구별하거나 추가적인 처리를 하는 데 사용될 수 있습니다.
  • -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully
    • MASQUERADE를 사용하여 패킷의 출발지 IP 주소를 변환합니다. 주로 클러스터 외부로 나가는 트래픽에 대해 SNAT(Source Network Address Translation) 처리를 수행합니다.
    • --random-fully 옵션은 NAT 변환 시 포트 번호를 무작위로 완전히 설정하여 보안을 강화합니다. 이는 포트 충돌을 방지하고 추적을 어렵게 만듭니다.
root@myk8s-control-plane:/# iptables -t nat -S | grep KUBE-POSTROUTING
-N KUBE-POSTROUTING
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully

sessionAffinity

  • Kubernetes 서비스에서 클라이언트 요청을 특정 파드에 지속적으로 보내도록 하는 설정입니다. 
  • sessionAffinity ClientIP로 설정하면, 같은 클라이언트 IP에서 온 요청은 항상 같은 파드로 전달됩니다. 이는 세션 상태를 유지해야 하는 경우에 유용합니다.

  • sessionAffinity: None은 서비스의 트래픽이 특정 파드에 고정되지 않도록 하여, 시스템의 부하 분산을 최적화하는 설정입니다.
  • 이는 상태 비저장 애플리케이션에 적합하며, 클라이언트의 요청이 매번 다른 파드로 전달되도록 합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc svc-clusterip -o yaml | grep sessionAffinity
  sessionAffinity: None

  • sessionAffinity를 ClientIP로 변경함으로써 클라이언트의 세션 상태를 유지합니다.
  • sessionAffinity: ClientIP
    • 클라이언트의 IP 주소에 따라 요청을 특정 파드로 라우팅합니다. 즉, 같은 IP에서 오는 요청은 항상 동일한 파드로 전달됩니다. 이를 통해 세션 상태를 유지할 수 있습니다
(⎈|kind-myk8s:N/A) root@kind:~# kubectl patch svc svc-clusterip -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/svc-clusterip patched

(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc svc-clusterip -o yaml | grep sessionAffinity -A2
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800

  • 100번의 요청 중 모든 요청이 Hostname: webpod3라는 응답을 받았음을 나타냅니다. 즉, $SVC1 서비스가 항상 webpod3라는 파드로 라우팅되었습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- zsh -c "for i in {1..100};  do curl -s $SVC1:9000 | grep Hostname; done | sort | uniq -c | sort -nr"
    100 Hostname: webpod3
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- zsh -c "for i in {1..1000};  do curl -s $SVC1:9000 | grep Hostname; done | sort | uniq -c | sort -nr"
   1000 Hostname: webpod3

  • Kubernetes의 서비스와 파드 간의 네트워크 트래픽을 처리하기 위한 iptables 규칙을 확인합니다.
  •  KUBE-SEP-2TLZC6QOUTI37HEJ
    • TCP 요청을 처리하고, 클라이언트 IP를 기록.
    • 목적지: 10.10.3.2:80으로 DNAT.
  •  KUBE-SEP-TBW2IYJKUCAC7GB3
    •  TCP 요청을 처리하고, 클라이언트 IP를 기록.
    • 목적지: 10.10.1.2:80으로 DNAT.
  •  KUBE-SEP-W5ROWLZT7Z7YVFGJ
    • TCP 요청을 처리하고, 클라이언트 IP를 기록.
    • 목적지: 10.10.2.4:80으로 DNAT.
  •  KUBE-SVC-KBDEBIL6IU6WL7RF
    • 서비스 트래픽을 처리하고, 클라이언트 IP 기록 여부 확인.
    • 세션 유효 시간: 3시간 (10800초)
    • 기록된 IP에 따라 해당 SEP 규칙으로 요청 라우팅.
root@myk8s-control-plane:/# iptables -t nat -S | grep recent

-A KUBE-SEP-2TLZC6QOUTI37HEJ -p tcp -m comment --comment "default/svc-clusterip:svc-webport" -m recent --set --name KUBE-SEP-2TLZC6QOUTI37HEJ --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 10.10.3.2:80
-A KUBE-SEP-TBW2IYJKUCAC7GB3 -p tcp -m comment --comment "default/svc-clusterip:svc-webport" -m recent --set --name KUBE-SEP-TBW2IYJKUCAC7GB3 --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 10.10.1.2:80
-A KUBE-SEP-W5ROWLZT7Z7YVFGJ -p tcp -m comment --comment "default/svc-clusterip:svc-webport" -m recent --set --name KUBE-SEP-W5ROWLZT7Z7YVFGJ --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 10.10.2.4:80

-A KUBE-SVC-KBDEBIL6IU6WL7RF -m comment --comment "default/svc-clusterip:svc-webport -> 10.10.1.2:80" -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-TBW2IYJKUCAC7GB3 --mask 255.255.255.255 --rsource -j KUBE-SEP-TBW2IYJKUCAC7GB3
-A KUBE-SVC-KBDEBIL6IU6WL7RF -m comment --comment "default/svc-clusterip:svc-webport -> 10.10.2.4:80" -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-W5ROWLZT7Z7YVFGJ --mask 255.255.255.255 --rsource -j KUBE-SEP-W5ROWLZT7Z7YVFGJ
-A KUBE-SVC-KBDEBIL6IU6WL7RF -m comment --comment "default/svc-clusterip:svc-webport -> 10.10.3.2:80" -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-2TLZC6QOUTI37HEJ --mask 255.255.255.255 --rsource -j KUBE-SEP-2TLZC6QOUTI37HEJ
Comments