Ssoon

[4주차] NodePort 본문

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

[4주차] NodePort

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

✅ 기본 구성 정보

  • 목적지 디플로이먼트(Pod) 파일을 생성합니다. [echo-deploy.yaml]
(⎈|kind-myk8s:N/A) root@kind:~# cat <<EOT> echo-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-echo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: deploy-websrv
  template:
    metadata:
      labels:
        app: deploy-websrv
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: kans-websrv
        image: mendhak/http-https-echo
        ports:
        - containerPort: 8080
EOT
  • 서비스(NodePort) 파일 생성을 생성합니다. [svc-nodeport.yaml]
(⎈|kind-myk8s:N/A) root@kind:~# cat <<EOT> svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc-nodeport
spec:
  ports:
    - name: svc-webport
      port: 9000        # 서비스 ClusterIP 에 접속 시 사용하는 포트 port 를 의미
      targetPort: 8080  # 타킷 targetPort 는 서비스를 통해서 목적지 파드로 접속 시 해당 파드로 접속하는 포트를 의미
  selector:
    app: deploy-websrv
  type: NodePort
EOT
  • 디플로이먼트와 서비스를 생성하고 생성된 정보를 확인합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f echo-deploy.yaml,svc-nodeport.yaml
deployment.apps/deploy-echo created
service/svc-nodeport created

(⎈|kind-myk8s:N/A) root@kind:~# kubectl get deploy,pod -o wide
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS    IMAGES                    SELECTOR
deployment.apps/deploy-echo   3/3     3            3           34s   kans-websrv   mendhak/http-https-echo   app=deploy-websrv

NAME                               READY   STATUS    RESTARTS   AGE   IP          NODE            NOMINATED NODE   READINESS GATES
pod/deploy-echo-5c689d5454-dgx8k   1/1     Running   0          34s   10.10.3.2   myk8s-worker    <none>           <none>
pod/deploy-echo-5c689d5454-pdr6g   1/1     Running   0          34s   10.10.2.2   myk8s-worker3   <none>           <none>
pod/deploy-echo-5c689d5454-rpxr2   1/1     Running   0          34s   10.10.1.2   myk8s-worker2   <none>           <none>
  • 서비스 (NodePort) 정보를 확인합니다.
    • Selector: app=deploy-websrv: 서비스가 선택하는 파드의 셀렉터가 app=deploy-websrv입니다. 즉, app=deploy-websrv 레이블을 가진 파드들에 트래픽을 전달합니다.
    • Type: NodePort: 서비스의 유형이 NodePort입니다. NodePort 서비스는 클러스터의 모든 노드에서 특정 포트를 개방해 외부에서 트래픽을 받아들입니다.
    • Port: svc-webport 9000/TCP: 서비스에서 사용할 포트 9000/TCP입니다. 외부 트래픽이 이 포트를 통해 서비스로 들어옵니다.
    • TargetPort: 8080/TCP: 서비스가 트래픽을 전달할 파드의 포트 8080/TCP입니다. 즉, 서비스로 들어온 트래픽은 파드의 8080 포트로 전달됩니다.
    • NodePort: svc-webport 31449/TCP: 클러스터 외부에서 서비스에 접근할 수 있는 NodePort 31449/TCP입니다. 외부 사용자는 클러스터의 노드 IP와 포트 31449를 통해 이 서비스에 접근할 수 있습니다.
    • Endpoints: 10.10.3.2:8080,10.10.2.2:8080,10.10.1.2:8080: 서비스가 트래픽을 전달할 엔드포인트 목록입니다. 각각의 IP는 서비스에 의해 선택된 파드들의 IP이며, 트래픽은 각 파드의 8080 포트로 전달됩니다.
    • Session Affinity: None: 이 서비스는 세션 어피니티를 사용하지 않습니다. 세션 어피니티가 없는 경우, 클라이언트의 요청은 매번 다른 파드로 분산될 수 있습니다.
    • External Traffic Policy: Cluster: 외부 트래픽 정책 Cluster로 설정되어 있습니다. 외부 트래픽은 클러스터 내부의 여러 노드에서 처리될 수 있으며, 트래픽이 어떤 노드로 들어오더라도 파드들로 전달됩니다.
    • Internal Traffic Policy: Cluster: 내부 트래픽 정책 Cluster로 설정되어 있습니다. 클러스터 내부 트래픽도 동일하게 여러 노드에서 처리될 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc svc-nodeport
NAME           TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
svc-nodeport   NodePort   10.200.1.26   <none>        9000:31449/TCP   63s

(⎈|kind-myk8s:N/A) root@kind:~# kubectl get endpoints svc-nodeport
NAME           ENDPOINTS                                      AGE
svc-nodeport   10.10.1.2:8080,10.10.2.2:8080,10.10.3.2:8080   67s

(⎈|kind-myk8s:N/A) root@kind:~# kubectl describe svc svc-nodeport
Name:                     svc-nodeport
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=deploy-websrv
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.200.1.26
IPs:                      10.200.1.26
Port:                     svc-webport  9000/TCP
TargetPort:               8080/TCP
NodePort:                 svc-webport  31449/TCP
Endpoints:                10.10.3.2:8080,10.10.2.2:8080,10.10.1.2:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Internal Traffic Policy:  Cluster
Events:                   <none>

서비스(NodePort) 접속 확인

🧿 외부 [mypc] 에서 접속 확인 및 서비스 (NodePort) 에서 부하분산 확인

  •  [mypc] 를 생성합니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker run -d --rm --name mypc --network kind --ip 172.18.0.100 nicolaka/netshoot sleep infinity
7aba07586115993c45c3ed55fe1405419599fec9341a7cf5055451ca853f2a7b

(⎈|kind-myk8s:N/A) root@kind:~# docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS          PORTS                                                             NAMES
7aba07586115   nicolaka/netshoot      "sleep infinity"         7 seconds ago   Up 6 seconds                                                                      mypc
  • svc-nodeport 서비스의 NodePort 값을 가져와서 NPORT  변수에 저장합니다.
(⎈|kind-myk8s:N/A) root@kind:~# NPORT=$(kubectl get service svc-nodeport -o jsonpath='{.spec.ports[0].nodePort}')
(⎈|kind-myk8s:N/A) root@kind:~# echo $NPORT
31449
  • app=deploy-websrv 라는 레이블을 가진 모든 파드의 로그를 실시간으로 확인합니다.
  • 노드의 IP와 NodePort를 변수에 저장합니다.
CNODE=172.18.0.5 
NODE1=172.18.0.2
NODE2=172.18.0.4
NODE3=172.18.0.3
  • [mypc]  에서 curl을 이용해 IP 주소 $CNODE:$NPORT (172.18.0.5:31449) 에 HTTP GET 요청을 보냈고, 그 결과로 서버에서 요청 정보를 JSON 형식으로 반환
  • deploy-echo-5c689d5454-rpxr2 는 myk8s-worker2  에 있는 pod
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it mypc curl -s $CNODE:$NPORT | jq
{
  "path": "/",
  "headers": {
    "host": "172.18.0.5:31449",	#요청을 받은 서버의 IP 주소와 포트
    "user-agent": "curl/8.7.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "172.18.0.5",	#요청을 받은 서버의 호스트 이름 또는 IP 주소
  "ip": "::ffff:172.18.0.5",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-rpxr2"	#이 요청을 처리한 서버의 호스트 이름
  },
  "connection": {}
}
  • $CNODE, $NODE1, $NODE2, $NODE3 변수에 담긴 네 개의 노드 각각에 대해  [mypc] 라는 컨테이너 안에서 해당 노드로 curl 명령을 실행하여 그 결과를 출력합니다
(⎈|kind-myk8s:N/A) root@kind:~# for i in $CNODE $NODE1 $NODE2 $NODE3 ; do echo ">> node $i <<"; docker exec -it mypc curl -s $i:$NPORT; echo; done
>> node 172.18.0.5 <<
{
  "path": "/",
  "headers": {
    "host": "172.18.0.5:31449",
    "user-agent": "curl/8.7.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "172.18.0.5",
  "ip": "::ffff:172.18.0.5",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-pdr6g"
  },
  "connection": {}
}
>> node 172.18.0.2 <<
{
  "path": "/",
  "headers": {
    "host": "172.18.0.2:31449",
    "user-agent": "curl/8.7.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "172.18.0.2",
  "ip": "::ffff:172.18.0.2",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-pdr6g"
  },
  "connection": {}
}
>> node 172.18.0.4 <<
{
  "path": "/",
  "headers": {
    "host": "172.18.0.4:31449",
    "user-agent": "curl/8.7.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "172.18.0.4",
  "ip": "::ffff:172.18.0.4",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-dgx8k"
  },
  "connection": {}
}
>> node 172.18.0.3 <<
{
  "path": "/",
  "headers": {
    "host": "172.18.0.3:31449",
    "user-agent": "curl/8.7.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "172.18.0.3",
  "ip": "::ffff:172.18.0.3",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-dgx8k"
  },
  "connection": {}
}
  • 서비스(NodePort) 가 부하분산되어 접속되는 것을 확인합니다. 
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it mypc zsh -c "for i in {1..100}; do curl -s $CNODE:$NPORT | grep hostname; done | sort | uniq -c | sort -nr"
    100   "hostname": "172.18.0.5",
     40     "hostname": "deploy-echo-5c689d5454-pdr6g"
     31     "hostname": "deploy-echo-5c689d5454-rpxr2"
     29     "hostname": "deploy-echo-5c689d5454-dgx8k"
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it mypc zsh -c "for i in {1..100}; do curl -s $NODE1:$NPORT | grep hostname; done | sort | uniq -c | sort -nr"    
    100   "hostname": "172.18.0.2",
     37     "hostname": "deploy-echo-5c689d5454-dgx8k"
     34     "hostname": "deploy-echo-5c689d5454-pdr6g"
     29     "hostname": "deploy-echo-5c689d5454-rpxr2"
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it mypc zsh -c "for i in {1..100}; do curl -s $NODE2:$NPORT | grep hostname; done | sort | uniq -c | sort -nr"
    100   "hostname": "172.18.0.4",
     37     "hostname": "deploy-echo-5c689d5454-dgx8k"
     32     "hostname": "deploy-echo-5c689d5454-rpxr2"
     31     "hostname": "deploy-echo-5c689d5454-pdr6g"
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it mypc zsh -c "for i in {1..100}; do curl -s $NODE3:$NPORT | grep hostname; done | sort | uniq -c | sort -nr"
    100   "hostname": "172.18.0.3",
     36     "hostname": "deploy-echo-5c689d5454-pdr6g"
     32     "hostname": "deploy-echo-5c689d5454-rpxr2"
     32     "hostname": "deploy-echo-5c689d5454-dgx8k"
  • app 라벨이 deploy-websrv로 설정된 파드의 로그를 실시간으로 확인 합니다.
  • 노드의 IP [myk8s-control-plane] : 172.18.0.5 로 SNAT 되는것을 확인
(⎈|kind-myk8s:N/A) root@kind:~# kubectl logs -l app=deploy-websrv -f
...
}
::ffff:172.18.0.5 - - [24/Sep/2024:12:22:28 +0000] "GET / HTTP/1.1" 200 397 "-" "curl/8.7.1"
{
...
  • 9000:31449/TCP:
    • 9000: 클러스터 내에서 이 서비스에 접근할 때 사용하는 포트 번호입니다.
    • 31449: 클러스터의 각 노드에서 사용할 수 있는 포트 번호입니다. 외부 클라이언트는 클러스터 노드의 IP와 이 포트를 사용해 서비스에 접근할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc svc-nodeport
NAME           TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
svc-nodeport   NodePort   10.200.1.26   <none>        9000:31449/TCP   23m
  • 클러스터 IP 와 클러스터 포트 를 변수에 저장합니다.
(⎈|kind-myk8s:N/A) root@kind:~# CIP=$(kubectl get service svc-nodeport -o jsonpath="{.spec.clusterIP}")
(⎈|kind-myk8s:N/A) root@kind:~# CIPPORT=$(kubectl get service svc-nodeport -o jsonpath="{.spec.ports[0].port}")
(⎈|kind-myk8s:N/A) root@kind:~# echo $CIP $CIPPORT
10.200.1.26 9000
  • myk8s-control-plane 에서 curl 명령을 통해 [CLUSTER-IP:CLUSTER-PORT] 10.200.1.26:9000 주소로 HTTP GET 요청을 보낸 후 응답으로 받은 정보
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane curl -s $CIP:$CIPPORT | jq
{
  "path": "/",
  "headers": {
    "host": "10.200.1.26:9000",	#요청을 받은 서버의 주소와 포트 [CLUSTER-IP:CLUSTER-PORT]
    "user-agent": "curl/7.88.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "10.200.1.26",	#요청을 처리한 서버의 호스트 이름이나 IP 주소 [CLUSTER-IP]
  "ip": "::ffff:172.18.0.5",	#실제 IPv4 주소 [myk8s-control-plane]
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-rpxr2"	#이 요청을 처리한 서버의 호스트 이름 [myk8s-worker2]
  },
  "connection": {}
}
  • 외부 [mypc] 에서 CLUSTER-IP:PORT 로 접속되지 않습니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it mypc curl -s $CIP:$CIPPORT

IPTABLES 정책 확인

  • myk8s-control-plane 컨테이너 내에서 NAT 테이블의 카운터를 0으로 초기화
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# iptables -t nat --zero
  • NAT 테이블의 PREROUTING 체인에 대한 규칙을 나열하고, 그 중에서 PREROUTING에 관련된 규칙만 필터링합니다.
root@myk8s-control-plane:/# iptables -t nat -S | grep PREROUTING
-P PREROUTING ACCEPT
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A PREROUTING -d 172.18.0.1/32 -j DOCKER_OUTPUT
  • -P : 기본 정책(default policy)을 설정하는 옵션입니다.
  • PREROUTING : 패킷이 네트워크 인터페이스로 들어오기 전에 적용되는 체인입니다.
  • ACCEPT : 기본 정책이 수신된 패킷을 허용하겠다는 의미입니다. 즉, 특별한 규칙이 적용되지 않는 한 패킷을 모두 허용합니다.

 

  • -A PREROUTING: PREROUTING 체인에 새로운 규칙을 추가합니다.
  • -m comment --comment "kubernetes service portals": 이 규칙에 대한 설명을 추가합니다. 
  • -j KUBE-SERVICES: 이 패킷을 KUBE-SERVICES라는 사용자 정의 체인으로 전달합니다. 

 

  • -A PREROUTING: PREROUTING 체인에 추가합니다.
  • -d 172.18.0.1/32: 이 규칙은 목적지 IP가 172.18.0.1인 패킷을 대상으로 합니다. /32는 단일 IP 주소를 의미합니다.
  • -j DOCKER_OUTPUT: 이 패킷을 DOCKER_OUTPUT 체인으로 전달합니다. 즉, 이 규칙은 Docker의 OUTPUT 체인으로 패킷을 보내, Docker가 관리하는 출력 트래픽을 처리하도록 합니다.
    • DOCKER_OUTPUT 체인
      • Docker에서 컨테이너의 출력을 처리하는 iptables 체인입니다.
      • 컨테이너에서 나가는 패킷의 필터링 및 규칙 적용을 통해, Docker 환경에서의 네트워크 트래픽을 관리합니다.

  • NAT 테이블에서 KUBE-SERVICES 체인에 대한 규칙을 나열하고, 그 중에서 KUBE-NODEPORTS 체인으로 연결되는 규칙을 필터링합니다.
root@myk8s-control-plane:/# iptables -t nat -S | grep KUBE-SERVICES
...
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
  • --dst-type LOCAL: 목적지 주소가 로컬 주소인 경우에만 이 규칙이 적용된다는 것을 의미합니다. 즉, 요청이 클러스터 내의 로컬 주소로 들어올 때 이 규칙이 적용됩니다.
  • -j KUBE-NODEPORTS : KUBE-NODEPORTS라는 다른 체인으로 패킷을 전달

🧿 NodePort 서비스로 들어오는 트래픽을 처리하는 iptables 규칙

root@myk8s-control-plane:/# NPORT=$(kubectl get service svc-nodeport -o jsonpath='{.spec.ports[0].nodePort}')
root@myk8s-control-plane:/# echo $NPORT
31449

root@myk8s-control-plane:/# iptables -t nat -S | grep KUBE-NODEPORTS | grep $NPORT
-A KUBE-NODEPORTS -d 127.0.0.0/8 -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 31449 -m nfacct --nfacct-name  localhost_nps_accepted_pkts -j KUBE-EXT-VTR7MTHHNMFZ3OFS
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 31449 -j KUBE-EXT-VTR7MTHHNMFZ3OFS

  • -A KUBE-NODEPORTS: KUBE-NODEPORTS 체인에 이 규칙을 추가하라는 뜻입니다. KUBE-NODEPORTS는 Kubernetes가 관리하는 체인으로, NodePort 서비스에 대한 트래픽을 처리합니다.
  • -d 127.0.0.0/8: 이 규칙은 127.0.0.0/8 네트워크 대역(로컬 루프백 주소)로 목적지가 설정된 패킷에만 적용됩니다. 즉, 이 규칙은 localhost에서 들어오는 트래픽에만 적용됩니다.
  • -p tcp: 이 규칙은 TCP 프로토콜을 사용하는 패킷에만 적용됩니다.
  • -m comment --comment "default/svc-nodeport:svc-webport": 이 부분은 이 규칙에 대한 설명을 나타냅니다. 
  • -m tcp --dport 31449: TCP 패킷의 목적지 포트가 31449인 경우에만 이 규칙이 적용됩니다. 이 NodePort는 외부에서 Kubernetes 클러스터 내부 서비스로 연결될 때 사용하는 포트입니다.
  • -m nfacct --nfacct-name localhost_nps_accepted_pkts: 이 규칙은 패킷을 추적하기 위해 Netfilter Accounting(nfacct) 모듈을 사용합니다. 여기서는 localhost_nps_accepted_pkts라는 이름으로 패킷 계수를 저장합니다. 패킷 계수는 트래픽을 분석할 때 사용됩니다.
  • -j KUBE-EXT-VTR7MTHHNMFZ3OFS: KUBE-EXT-VTR7MTHHNMFZ3OFS 체인으로 트래픽을 넘기겠다는 뜻입니다. 이 규칙에 매칭되는 패킷은 이 체인으로 전달되어 추가 처리를 받습니다. 이 체인은 Kubernetes에서 자동으로 생성한 것입니다.

  • -A KUBE-NODEPORTS: 이 규칙도 KUBE-NODEPORTS 체인에 추가됩니다.
  • -p tcp: TCP 프로토콜을 사용하는 패킷에 적용됩니다.
  • -m tcp --dport 31449: 목적지 포트가 31449인 경우에만 적용됩니다. 이는 NodePort로, 외부 트래픽이 이 포트로 들어올 때 규칙이 적용됩니다.
  • -j KUBE-EXT-VTR7MTHHNMFZ3OFS: 이 규칙에 매칭되는 트래픽은 KUBE-EXT-VTR7MTHHNMFZ3OFS 체인으로 전달되어 후속 처리를 받습니다

🧿 iptables에서 KUBE-EXT-VTR7MTHHNMFZ3OFS 체인에 대한 규칙

root@myk8s-control-plane:/# iptables -t nat -S | grep "A KUBE-EXT-VTR7MTHHNMFZ3OFS"
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "masquerade traffic for default/svc-nodeport:svc-webport external destinations" -j KUBE-MARK-MASQ
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -j KUBE-SVC-VTR7MTHHNMFZ3OFS
  • -A KUBE-EXT-VTR7MTHHNMFZ3OFS: KUBE-EXT-VTR7MTHHNMFZ3OFS 체인에 규칙을 추가한다는 뜻입니다. KUBE-EXT-VTR7MTHHNMFZ3OFS는 Kubernetes에서 자동으로 생성한 체인으로, 특정 서비스 트래픽을 처리하기 위한 체인입니다.
  • -m comment --comment "masquerade traffic for default/svc-nodeport:svc-webport external destinations": 이 부분은 주석으로, 해당 규칙이 어떤 역할을 하는지 설명해 줍니다. 이 주석은 NodePort 서비스(svc-nodeport:svc-webport)가 외부 목적지로 나가는 트래픽에 마스커레이드(Masquerade) 처리를 한다는 뜻입니다.
    • Masquerade는 NAT(Network Address Translation)의 일종으로, 내부 IP를 외부로 보낼 때 IP 주소를 외부 IP로 변경하는 기능입니다. 즉, 클러스터 내부 IP를 외부 트래픽에 맞게 변경하여 전송합니다.
  • -j KUBE-MARK-MASQ: 이 부분이 핵심입니다. 트래픽을 KUBE-MARK-MASQ 체인으로 전달하라는 뜻입니다. 이 체인에서는 해당 트래픽에 대해 마스커레이드 처리를 하게 됩니다. 이를 통해 트래픽이 외부로 나갈 때 클러스터의 외부 IP로 IP 주소를 변경합니다.

  • -A KUBE-EXT-VTR7MTHHNMFZ3OFS: 첫 번째와 동일하게, KUBE-EXT-VTR7MTHHNMFZ3OFS 체인에 규칙을 추가하는 명령입니다.
  • -j KUBE-SVC-VTR7MTHHNMFZ3OFS: 트래픽을 KUBE-SVC-VTR7MTHHNMFZ3OFS 체인으로 넘기라는 뜻입니다. 이 체인은 Kubernetes에서 자동으로 생성한 서비스 관련 체인입니다. 여기서 실제로 서비스의 로드밸런싱이나 트래픽 분배 작업이 수행됩니다.

🧿 iptables 에서 KUBE-SVC-VTR7MTHHNMFZ3OFS체인에 대한 규칙

  • svc-nodeport:svc-webport 서비스로 들어오는 트래픽을 3개의 백엔드 파드(10.10.1.2, 10.10.2.2, 10.10.3.2) (Endpoints) 로 분배합니다.
  • iptables는 확률 기반 로드밸런싱을 사용하여 트래픽을 고르게 분배합니다.
root@myk8s-control-plane:/# iptables -t nat -S | grep "A KUBE-SVC-VTR7MTHHNMFZ3OFS -"
-A KUBE-SVC-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.1.2:8080" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-5TQGRJJ4PFRHXDI6
-A KUBE-SVC-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.2.2:8080" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-3X3XSQUPZHVZ5LJI
-A KUBE-SVC-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.3.2:8080" -j KUBE-SEP-FLUOEW5DZRFHN2WU
  • -A KUBE-SVC-VTR7MTHHNMFZ3OFS: KUBE-SVC-VTR7MTHHNMFZ3OFS 체인에 규칙을 추가합니다. 이 체인은 Kubernetes 서비스와 관련된 체인으로, 서비스 트래픽이 여기에서 처리됩니다.
  • -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.1.2:8080": 이 부분은 규칙에 대한 설명(주석)으로, 트래픽이 svc-nodeport:svc-webport 서비스에서 IP 주소 10.10.1.2 8080 포트로 연결된다는 것을 나타냅니다. 이 IP 주소는 백엔드 파드 엔드포인트입니다.
  • -m statistic --mode random --probability 0.33333333349: 랜덤 방식의 확률적 로드밸런싱을 수행합니다. 0.33333333349는 약 33.33%의 확률을 의미하며, 들어오는 트래픽 중 33.33%는 이 규칙에 해당하는 엔드포인트(10.10.1.2:8080)로 전달됩니다.
  • -j KUBE-SEP-5TQGRJJ4PFRHXDI6: 트래픽을 KUBE-SEP-5TQGRJJ4PFRHXDI6라는 체인으로 전달합니다. KUBE-SEP-xxxx 체인은 Kubernetes가 각 **엔드포인트(SEP: Service Endpoint)**를 관리하기 위해 생성한 체인입니다. 이 체인에서는 트래픽이 실제로 엔드포인트로 전달됩니다.

  • -A KUBE-SVC-VTR7MTHHNMFZ3OFS: KUBE-SVC-VTR7MTHHNMFZ3OFS 체인에 규칙을 추가합니다.
  • -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.2.2:8080": 이 규칙은 10.10.2.2 IP 주소의 8080 포트로 트래픽을 보내는 규칙입니다. 이 IP 역시 백엔드 파드 또는 엔드포인트입니다.
  • -m statistic --mode random --probability 0.50000000000: 약 50%의 확률로 트래픽을 이 엔드포인트로 전달합니다. 즉, 들어오는 트래픽의 절반은 이 규칙에 따라 10.10.2.2:8080으로 전달됩니다.
  • -j KUBE-SEP-3X3XSQUPZHVZ5LJI: 트래픽을 KUBE-SEP-3X3XSQUPZHVZ5LJI 체인으로 전달합니다. 이 체인은 10.10.2.2 엔드포인트로 트래픽을 라우팅합니다.

  • -A KUBE-SVC-VTR7MTHHNMFZ3OFS: KUBE-SVC-VTR7MTHHNMFZ3OFS 체인에 규칙을 추가합니다.
  • -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.3.2:8080": 이 규칙은 10.10.3.2 IP 주소의 8080 포트로 트래픽을 라우팅하는 규칙입니다. 이는 또 다른 백엔드 엔드포인트입니다.
  • (확률 관련 옵션 없음): 이 규칙에는 확률 설정이 없습니다. 이것은 이 규칙에 도달한 나머지 모든 트래픽이 10.10.3.2:8080으로 라우팅된다는 것을 의미합니다. 즉, 앞선 두 규칙에 해당되지 않은 나머지 트래픽이 여기로 전달됩니다.
  • -j KUBE-SEP-FLUOEW5DZRFHN2WU: 트래픽을 KUBE-SEP-FLUOEW5DZRFHN2WU 체인으로 전달합니다. 이 체인은 해당 엔드포인트로 트래픽을 전달하는 역할을 합니다.

🧿 iptables에서 KUBE-POSTROUTING 체인에서 트래픽 처리

  • 이 체인은 출발지 NAT(SNAT) 처리를 위해 사용되며, 클러스터 내부에서 외부로 나가는 트래픽을 관리합니다.
root@myk8s-control-plane:/# iptables -t nat -S | grep "A 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
  • -A KUBE-POSTROUTING: KUBE-POSTROUTING 체인에 규칙을 추가합니다. POSTROUTING 체인은 트래픽이 시스템을 떠날 때, 즉 출발지 NAT(SNAT)를 수행하기 전에 적용됩니다.
  • -m mark ! --mark 0x4000/0x4000: 이 규칙은 마크가 **0x4000**으로 설정되지 않은 패킷을 대상으로 합니다. !는 부정 연산자로, 마크가 **0x4000**이 아닌 패킷만 이 규칙에 매칭된다는 뜻입니다.
  • -j RETURN: 이 규칙에 매칭되는 패킷은 더 이상 이 체인에서 처리되지 않고 즉시 반환됩니다. 즉, 0x4000 마크가 없는 패킷은 더 이상 KUBE-POSTROUTING 체인의 다른 규칙에 의해 처리되지 않습니다.

  • -A KUBE-POSTROUTING: KUBE-POSTROUTING 체인에 규칙을 추가합니다.
  • -j MARK --set-xmark 0x4000/0x0: 이 규칙은 패킷에 0x4000 이라는 마크를 설정합니다. xmark는 패킷을 식별하기 위한 32비트 마스크를 나타냅니다. 이 마크는 Kubernetes가 트래픽을 추적하거나 특수한 처리(예: NAT)를 위해 설정하는 것입니다.

  • -A KUBE-POSTROUTING: KUBE-POSTROUTING 체인에 규칙을 추가합니다.
  • -m comment --comment "kubernetes service traffic requiring SNAT": 이 규칙이 SNAT(Souce NAT) 처리가 필요한 Kubernetes 서비스 트래픽에 적용된다는 것을 나타냅니다. SNAT는 클러스터 내부의 트래픽이 외부로 나갈 때 출발지 IP 주소를 변경하는 NAT 방식입니다.
  • -j MASQUERADE --random-fully: MASQUERADE는 IP 주소를 변환하는 NAT 규칙입니다. 클러스터 내부의 IP를 외부로 나갈 때 변경하는 작업을 수행합니다. --random-fully 옵션은 소스 포트를 무작위로 설정해 NAT 충돌을 방지합니다. 이는 많은 트래픽을 처리할 때 유용합니다.

externalTrafficPolicy

# 기본 정보 확인

(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc svc-nodeport -o json | grep 'TrafficPolicy"'
        "externalTrafficPolicy": "Cluster",
        "internalTrafficPolicy": "Cluster",

 

# 기존 통신 연결 정보(conntrack) 제거 후 아래 실습 진행하자! : (모든 노드에서) conntrack -F

(⎈|kind-myk8s:N/A) root@kind:~# for i in control-plane worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-$i conntrack -F; echo; done
>> node myk8s-control-plane <<
conntrack v1.4.7 (conntrack-tools): connection tracking table has been emptied.

>> node myk8s-worker <<
conntrack v1.4.7 (conntrack-tools): connection tracking table has been emptied.

>> node myk8s-worker2 <<
conntrack v1.4.7 (conntrack-tools): connection tracking table has been emptied.

>> node myk8s-worker3 <<
conntrack v1.4.7 (conntrack-tools): connection tracking table has been emptied.

(⎈|kind-myk8s:N/A) root@kind:~# kubectl delete -f svc-nodeport.yaml
service "svc-nodeport" deleted
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f svc-nodeport.yaml
service/svc-nodeport created

# externalTrafficPolicy: local 설정 변경

(⎈|kind-myk8s:N/A) root@kind:~# kubectl patch svc svc-nodeport -p '{"spec":{"externalTrafficPolicy": "Local"}}'
service/svc-nodeport patched

(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc svc-nodeport -o json | grep 'TrafficPolicy"'
        "externalTrafficPolicy": "Local",
        "internalTrafficPolicy": "Cluster",

 

# 파드 3개를 2개로 줄임

(⎈|kind-myk8s:N/A) root@kind:~# kubectl scale deployment deploy-echo --replicas=2
deployment.apps/deploy-echo scaled
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get pod -owide
NAME                           READY   STATUS    RESTARTS   AGE    IP          NODE            NOMINATED NODE   READINESS GATES
deploy-echo-5c689d5454-pdr6g   1/1     Running   0          137m   10.10.2.2   myk8s-worker3   <none>           <none>
deploy-echo-5c689d5454-rpxr2   1/1     Running   0          137m   10.10.1.2   myk8s-worker2   <none>           <none>

# 노드의 IP와 NodePort를 변수에 지정

(⎈|kind-myk8s:N/A) root@kind:~# CNODE=172.18.0.5
NODE1=172.18.0.2
NODE2=172.18.0.4
NODE3=172.18.0.3

(⎈|kind-myk8s:N/A) root@kind:~# NPORT=$(kubectl get service svc-nodeport -o jsonpath='{.spec.ports[0].nodePort}')

 

# 서비스(NodePort) 부하분산 접속 확인 : 파드가 존재하지 않는 노드로는 접속 실패!, 파드가 존재하는 노드는 접속 성공 및 클라이언트 IP 확인

(⎈|kind-myk8s:N/A) root@kind:~# for i in $CNODE $NODE1 $NODE2 $NODE3 ; do echo ">> node $i <<"; docker exec -it mypc curl -s --connect-timeout 1 $i:$NPORT; echo; done
>> node 172.18.0.5 <<

>> node 172.18.0.2 <<

>> node 172.18.0.4 <<
{
  "path": "/",
  "headers": {
    "host": "172.18.0.4:32746",
    "user-agent": "curl/8.7.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "172.18.0.4",
  "ip": "::ffff:172.18.0.100",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-rpxr2"
  },
  "connection": {}
}
>> node 172.18.0.3 <<
{
  "path": "/",
  "headers": {
    "host": "172.18.0.3:32746",
    "user-agent": "curl/8.7.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,
  "hostname": "172.18.0.3",
  "ip": "::ffff:172.18.0.100",
  "ips": [],
  "protocol": "http",
  "query": {},
  "subdomains": [],
  "xhr": false,
  "os": {
    "hostname": "deploy-echo-5c689d5454-pdr6g"
  },
  "connection": {}
}

🧿 서비스와 연결된 pod 가  있는 노드에서 IPTABLES 정책 확인 [myk8s-worker2]

  • -A KUBE-NODEPORTS: KUBE-NODEPORTS 체인에 규칙을 추가(-A)한다는 의미입니다. 이 체인은 Kubernetes가 노드 포트 서비스에 대한 트래픽을 관리하기 위해 사용합니다.
  • -d 127.0.0.0/8: 목적지 IP가 루프백 주소(127.0.0.0/8)인 패킷에만 적용되는 규칙입니다. 즉, 이 규칙은 로컬 호스트(127.0.0.1)에서 들어오는 트래픽을 처리합니다.
  • -p tcp: TCP 프로토콜에 적용되는 규칙입니다.
  • -m comment --comment "default/svc-nodeport:svc-webport": 규칙에 대한 주석입니다. 이 주석은 이 규칙이 default 네임스페이스의 svc-nodeport 서비스와 관련된 것임을 나타냅니다.
  • -m tcp --dport 32746: 목적지 포트가 32746일 때 이 규칙이 적용된다는 의미입니다. 32746은 Kubernetes에서 할당된 노드 포트입니다.
  • -m nfacct --nfacct-name localhost_nps_accepted_pkts: Netfilter Accounting 기능을 사용하여 패킷을 추적합니다. 이 규칙에 의해 추적되는 패킷은 localhost_nps_accepted_pkts 이름으로 계정에 기록됩니다.
  • -j KUBE-EXT-VTR7MTHHNMFZ3OFS: 패킷이 이 규칙에 일치하면, KUBE-EXT-VTR7MTHHNMFZ3OFS라는 체인으로 점프(-j)합니다. 이 체인은 후속 작업을 처리할 수 있습니다.

  • 목적지 IP 조건(-d 127.0.0.0/8)이 없습니다. 즉, 모든 IP 주소에서 들어오는 트래픽에 적용됩니다.
  • 32746 포트로 들어오는 TCP 트래픽에 대해서는 이 규칙이 적용됩니다.
  • 마찬가지로, 트래픽은 KUBE-EXT-VTR7MTHHNMFZ3OFS 체인으로 전달됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-worker2 bash
root@myk8s-worker2:/# iptables -t nat -S | grep 32746
-A KUBE-NODEPORTS -d 127.0.0.0/8 -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 32746 -m nfacct --nfacct-name  localhost_nps_accepted_pkts -j KUBE-EXT-VTR7MTHHNMFZ3OFS
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 32746 -j KUBE-EXT-VTR7MTHHNMFZ3OFS

-A KUBE-EXT-VTR7MTHHNMFZ3OFS -s 10.10.0.0/16 -m comment --comment "pod traffic for default/svc-nodeport:svc-webport external destinations" -j KUBE-SVC-VTR7MTHHNMFZ3OFS
  • -A KUBE-EXT-VTR7MTHHNMFZ3OFS: KUBE-EXT-VTR7MTHHNMFZ3OFS 체인에 규칙을 추가하는 부분입니다.
  • -s 10.10.0.0/16: 출발지 IP 주소가 10.10.0.0/16 대역에 속하는 트래픽에 대해 규칙을 적용합니다. 이 IP 대역은 클러스터 내부의 Pod 네트워크일 가능성이 높습니다.
  • -m comment --comment "pod traffic for default/svc-nodeport:svc-webport external destinations": 이 규칙에 대한 설명(주석)으로, default 네임스페이스에 있는 svc-nodeport 서비스(svc-webport)와 관련된 트래픽을 처리하는 규칙임을 나타냅니다.
  • -j KUBE-SVC-VTR7MTHHNMFZ3OFS: 이 규칙에 매칭되는 트래픽은 KUBE-SVC-VTR7MTHHNMFZ3OFS 체인으로 전달됩니다. 즉, 이 트래픽에 대한 추가 처리를 위해 다른 체인으로 전달합니다.

-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "masquerade LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ
  • -m comment --comment "masquerade LOCAL traffic for default/svc-nodeport:svc-webport external destinations": 주석으로, 이 규칙은 svc-nodeport 서비스와 관련된 로컬 트래픽을 masquerading하는 역할을 한다는 것을 나타냅니다.
    • Masquerading: 이 작업은 출발지 IP 주소를 변경하는 NAT 기능의 일종입니다. 외부로 나가는 트래픽이 로컬 IP에서 발생한 경우, 외부 네트워크와 통신할 때 출발지 IP를 노드의 IP로 변경합니다.
  • -m addrtype --src-type LOCAL: 출발지 IP가 로컬 트래픽(클러스터 내 노드에서 발생한 트래픽)일 때 이 규칙이 적용됩니다.
  • -j KUBE-MARK-MASQ: 트래픽에 masquerade 마커를 붙입니다. 나중에 NAT가 이 트래픽의 출발지 IP를 변경할 수 있도록 마킹하는 규칙입니다.

-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "route LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-SVC-VTR7MTHHNMFZ3OFS
  • 이 규칙도 로컬 트래픽에 대해 적용됩니다.
  • -m comment --comment "route LOCAL traffic for default/svc-nodeport:svc-webport external destinations": 주석으로, svc-nodeport 서비스에 대한 로컬 트래픽을 외부 목적지로 라우팅한다는 의미입니다.
  • -m addrtype --src-type LOCAL: 로컬 트래픽에만 적용됩니다.
  • -j KUBE-SVC-VTR7MTHHNMFZ3OFS: 트래픽을 KUBE-SVC-VTR7MTHHNMFZ3OFS 체인으로 전달합니다. 이 체인은 해당 서비스와 관련된 추가 규칙을 적용하는 데 사용됩니다.

-A KUBE-EXT-VTR7MTHHNMFZ3OFS -j KUBE-SVL-VTR7MTHHNMFZ3OFS
  • 모든 트래픽을 KUBE-SVL-VTR7MTHHNMFZ3OFS 체인으로 전달합니다.
root@myk8s-worker2:/# iptables -t nat -S | grep 'A KUBE-EXT-VTR7MTHHNMFZ3OFS'
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -s 10.10.0.0/16 -m comment --comment "pod traffic for default/svc-nodeport:svc-webport external destinations" -j KUBE-SVC-VTR7MTHHNMFZ3OFS
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "masquerade LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "route LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-SVC-VTR7MTHHNMFZ3OFS
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -j KUBE-SVL-VTR7MTHHNMFZ3OFS

  • -j KUBE-SEP-5TQGRJJ4PFRHXDI6:
    • 이 규칙에 일치하는 트래픽은 KUBE-SEP-5TQGRJJ4PFRHXDI6 체인으로 점프(-j)합니다. SEP는 Service EndPoint를 의미하며, 이는 파드에 대한 실제 엔드포인트입니다.
    • KUBE-SEP-5TQGRJJ4PFRHXDI6 체인은 이 트래픽을 10.10.1.2:8080 파드로 전달하는 역할을 합니다.
  • svc-nodeport 서비스가 외부에서 받은 트래픽을 클러스터 내부의 특정 파드(10.10.1.2)로 전달하는 방식입니다. 이 파드는 8080 포트에서 애플리케이션이 동작 중입니다.
root@myk8s-worker2:/# iptables -t nat -S | grep 'A KUBE-SVL-VTR7MTHHNMFZ3OFS'
-A KUBE-SVL-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.1.2:8080" -j KUBE-SEP-5TQGRJJ4PFRHXDI6

  • 첫 번째 규칙은 출발지 IP가 10.10.1.2인 트래픽에 대해 masquerading 마커를 설정합니다. 이는 파드에서 나가는 트래픽이 외부로 나갈 때 클러스터의 IP로 변환되어 나갈 수 있게 해줍니다.
  • 두 번째 규칙은 TCP 트래픽에 대해 DNAT를 적용하여, 들어오는 트래픽을 특정 파드(10.10.1.2)의 8080 포트로 전달합니다. 이 규칙에 의해, NodePort를 통해 받은 트래픽은 해당 파드로 정확히 라우팅됩니다.
root@myk8s-worker2:/# iptables -t nat -S | grep 'A KUBE-SEP-5TQGRJJ4PFRHXDI6'
-A KUBE-SEP-5TQGRJJ4PFRHXDI6 -s 10.10.1.2/32 -m comment --comment "default/svc-nodeport:svc-webport" -j KUBE-MARK-MASQ
-A KUBE-SEP-5TQGRJJ4PFRHXDI6 -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp -j DNAT --to-destination 10.10.1.2:8080

  • 서비스와 연결된 pod 가  있는 노드 worker2는 10.10.1.2로, worker3는 10.10.2.2로 트래픽을 전달합니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane iptables -t nat -S | grep 'A KUBE-SVL-VTR7MTHHNMFZ3OFS'
(⎈|kind-myk8s:N/A) root@kind:~# for i in control-plane worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-$i iptables -t nat -S | grep 'A KUBE-SVL-VTR7MTHHNMFZ3OFS'; echo; done
>> node myk8s-control-plane <<

>> node myk8s-worker <<

>> node myk8s-worker2 <<
-A KUBE-SVL-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.1.2:8080" -j KUBE-SEP-5TQGRJJ4PFRHXDI6

>> node myk8s-worker3 <<
-A KUBE-SVL-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.2.2:8080" -j KUBE-SEP-3X3XSQUPZHVZ5LJI

🧿 서비스와 연결된 pod 가  없는 노드에서 IPTABLES 정책 확인 [myk8s-control-plane, myk8s-worker]

  •  첫 번째 규칙은 127.0.0.0/8 루프백 주소에서 오는 트래픽을 처리하는 데 사용됩니다.
  • 트래픽은 KUBE-EXT-VTR7MTHHNMFZ3OFS 체인으로 전달되며, 이 체인에서 서비스 뒤에 있는 파드로 라우팅됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# iptables -t nat -S | grep 32746
-A KUBE-NODEPORTS -d 127.0.0.0/8 -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 32746 -m nfacct --nfacct-name  localhost_nps_accepted_pkts -j KUBE-EXT-VTR7MTHHNMFZ3OFS
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 32746 -j KUBE-EXT-VTR7MTHHNMFZ3OFS

(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-worker bash
root@myk8s-worker:/# iptables -t nat -S | grep 32746
-A KUBE-NODEPORTS -d 127.0.0.0/8 -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 32746 -m nfacct --nfacct-name  localhost_nps_accepted_pkts -j KUBE-EXT-VTR7MTHHNMFZ3OFS
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/svc-nodeport:svc-webport" -m tcp --dport 32746 -j KUBE-EXT-VTR7MTHHNMFZ3OFS

 

  • 첫 번째 규칙: 클러스터 내에서 Pod로부터 나오는 트래픽을 KUBE-SVC-VTR7MTHHNMFZ3OFS 체인으로 전달하여 서비스 엔드포인트로 라우팅합니다.
  • 두 번째 규칙: 로컬 노드에서 발생한 트래픽에 Masquerading을 적용하여, 트래픽이 외부로 나갈 때 노드의 IP로 변환합니다.
  • 세 번째 규칙: 로컬 노드에서 발생한 트래픽을 KUBE-SVC-VTR7MTHHNMFZ3OFS 체인으로 전달하여 서비스 엔드포인트로 라우팅합니다.
root@myk8s-control-plane:/# iptables -t nat -S | grep 'A KUBE-EXT-VTR7MTHHNMFZ3OFS'
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -s 10.10.0.0/16 -m comment --comment "pod traffic for default/svc-nodeport:svc-webport external destinations" -j KUBE-SVC-VTR7MTHHNMFZ3OFS
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "masquerade LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "route LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-SVC-VTR7MTHHNMFZ3OFS

root@myk8s-worker:/# iptables -t nat -S | grep 'A KUBE-EXT-VTR7MTHHNMFZ3OFS'
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -s 10.10.0.0/16 -m comment --comment "pod traffic for default/svc-nodeport:svc-webport external destinations" -j KUBE-SVC-VTR7MTHHNMFZ3OFS
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "masquerade LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ
-A KUBE-EXT-VTR7MTHHNMFZ3OFS -m comment --comment "route LOCAL traffic for default/svc-nodeport:svc-webport external destinations" -m addrtype --src-type LOCAL -j KUBE-SVC-VTR7MTHHNMFZ3OFS

 

  • 첫 번째 규칙: 클러스터 외부에서 들어오는 트래픽(클러스터 내부 IP가 아닌 출발지)을 ClusterIP(10.200.1.112)로 라우팅하면서 Masquerading을 적용합니다.
  • 두 번째 규칙: svc-nodeport 서비스에 대한 트래픽을 50%의 확률로 IP 10.10.1.2:8080에 있는 파드로 라우팅합니다.
  • 세 번째 규칙: 나머지 50%의 트래픽을 IP 10.10.2.2:8080에 있는 파드로 라우팅합니다.
root@myk8s-control-plane:/# iptables -t nat -S | grep 'A KUBE-SVC-VTR7MTHHNMFZ3OFS'
-A KUBE-SVC-VTR7MTHHNMFZ3OFS ! -s 10.10.0.0/16 -d 10.200.1.112/32 -p tcp -m comment --comment "default/svc-nodeport:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-MARK-MASQ
-A KUBE-SVC-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.1.2:8080" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-5TQGRJJ4PFRHXDI6
-A KUBE-SVC-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.2.2:8080" -j KUBE-SEP-3X3XSQUPZHVZ5LJI

root@myk8s-worker:/#  iptables -t nat -S | grep 'A KUBE-SVC-VTR7MTHHNMFZ3OFS'
-A KUBE-SVC-VTR7MTHHNMFZ3OFS ! -s 10.10.0.0/16 -d 10.200.1.112/32 -p tcp -m comment --comment "default/svc-nodeport:svc-webport cluster IP" -m tcp --dport 9000 -j KUBE-MARK-MASQ
-A KUBE-SVC-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.1.2:8080" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-5TQGRJJ4PFRHXDI6
-A KUBE-SVC-VTR7MTHHNMFZ3OFS -m comment --comment "default/svc-nodeport:svc-webport -> 10.10.2.2:8080" -j KUBE-SEP-3X3XSQUPZHVZ5LJI
Comments