Ssoon
[4주차] ClusterIP 본문
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 클러스터의 네트워크 설정을 확인합니다.
- --service-cluster-ip-range=10.200.1.0/24:
- 서비스 클러스터 IP 범위를 정의합니다.
- 클러스터 내에서 Kubernetes 서비스가 사용하는 IP 주소 범위를 나타냅니다. 여기서 10.200.1.0/24는 서비스에 할당할 수 있는 IP 주소 범위를 의미합니다.
- --cluster-cidr=10.10.0.0/16:
- 클러스터 CIDR은 Pod들이 사용하는 IP 주소 범위를 나타냅니다.
- 10.10.0.0/16는 클러스터 내에서 Pod에 할당되는 IP 주소 범위를 나타냅니다. 각 Pod은 이 범위 내의 IP를 할당받아 네트워크 통신을 하게 됩니다.
- --service-cluster-ip-range=10.200.1.0/24:
(⎈|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] 에 대한 현재 커넥션 트래킹 상태를 나열합니다
- 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]
- sport=60674 dport=9000
- sport=60674: 출발지 포트 번호.
- dport=9000: 목적지 포트 번호. 이 경우, 서비스 포트입니다.
- 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
- sport=80 dport=60674
- sport=80: 서버의 출발지 포트 번호 (HTTP 서비스 포트).
- dport=60674: 클라이언트의 포트 번호.
- src=10.10.0.6 dst=10.200.1.118:
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] 에 대한 현재 커넥션 트래킹 상태를 나열합니다.
- 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]
- sport=45996 dport=9000:
- sport=45996: 출발지 포트 번호 (클라이언트의 포트).
- dport=9000: 목적지 포트 번호 (서비스의 포트).
- 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=45996:
- sport=80: 서버의 출발지 포트 번호 (HTTP 서비스 포트).
- dport=45996: 클라이언트의 포트 번호.
- src=10.10.0.6 dst=10.200.1.118:
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
...
- Bridge chain: INPUT, entries: 0, policy: ACCEPT:
- Bridge chain: INPUT: 이 체인은 브리지에서 수신되는 패킷을 처리합니다.
- entries: 0: 현재 이 체인에 등록된 규칙의 수입니다. 여기서는 규칙이 없습니다.
- policy: ACCEPT: 기본 정책입니다. 즉, 규칙이 없을 경우 수신된 패킷을 허용합니다.
- Bridge chain: FORWARD, entries: 0, policy: ACCEPT:
- Bridge chain: FORWARD: 이 체인은 브리지를 통해 전달되는 패킷을 처리합니다.
- entries: 0: 현재 이 체인에 등록된 규칙이 없습니다.
- policy: ACCEPT: 기본 정책은 패킷을 허용합니다.
- 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
- default via 172.18.0.1 dev eth0:
- 기본 경로로, 어떤 목적지 IP가 명시되지 않았을 때 패킷이 172.18.0.1로 전송됩니다. 사용되는 인터페이스는 eth0입니다.
- 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 인터페이스로 전송됩니다.
- 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 인터페이스로 전송됩니다.
- 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 인터페이스로 전송됩니다.
- 10.10.3.2 dev veth72a21f90 scope host:
- 10.10.3.2에 대한 경로입니다. 패킷은 veth72a21f90 인터페이스를 통해 전송되며, 이 IP는 호스트 내에서만 유효합니다.
- 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에서 통신하는 패킷만 캡처하겠다는 조건입니다.
- ngrep -tW byline -d eth0 '' 'tcp port 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-MARK-MASQ :
- KUBE-SEP (Kubernetes Endpoint)
- Kubernetes 서비스의 특정 엔드포인트(포드)를 나타내는 iptables 체인입니다. 이는 서비스를 제공하는 포드들의 IP 주소와 포트를 관리하고, 클라이언트 요청이 해당 포드로 라우팅되도록 합니다.
- 트래픽 분산: 클라이언트가 서비스에 요청을 보내면 KUBE-SEP 체인이 사용되어 요청을 서비스의 여러 포드로 분산합니다. 이 과정에서 각 포드의 IP 주소와 포트가 사용됩니다.
- 부하 분산: 여러 엔드포인트가 있을 경우 KUBE-SEP는 랜덤이나 라운드 로빈 방식으로 트래픽을 분배하여 부하를 조절합니다.
- Kubernetes 서비스의 특정 엔드포인트(포드)를 나타내는 iptables 체인입니다. 이는 서비스를 제공하는 포드들의 IP 주소와 포트를 관리하고, 클라이언트 요청이 해당 포드로 라우팅되도록 합니다.
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 포트로 전송
- KUBE-MARK-MASQ
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를 숨김 처리.
- RETURN
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
'쿠버네티스 네트워크 스터디 3기' 카테고리의 다른 글
[5주차] 실습기본환경구성 (3) | 2024.10.02 |
---|---|
[4주차] NodePort (0) | 2024.09.24 |
[4주차] 기본 구성 정보 (0) | 2024.09.23 |
[3주차] Calico Mode : Direct 모드 / CrossSubnet 모드 (0) | 2024.09.13 |
[3주차] 다른 Node 에서 Pod ↔ Pod 간 통신 (0) | 2024.09.13 |
Comments