Ssoon

[5주차] IPVS 본문

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

[5주차] IPVS

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

 


✅ 기본 환경

🧿 1개의 컨트롤 플레인 노드와 3개의 워커 노드를 갖춘, IPVS를 사용하는 Kubernetes 클러스터를 설정합니다.

(⎈|N/A:N/A) root@kind:~# cat <<EOT> kind-svc-2w-ipvs.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  "InPlacePodVerticalScaling": true	#파드의 CPU 또는 메모리 리소스를 중단 없이 조정하는 기능을 활성화합니다.
  "MultiCIDRServiceAllocator": true	#여러 CIDR 범위를 서비스 할당에 사용할 수 있게 합니다.
nodes:
- role: control-plane
  labels:
    mynode: control-plane
    topology.kubernetes.io/zone: ap-northeast-2a
  extraPortMappings:	#컨테이너 내부의 포트를 호스트 머신의 포트와 매핑합니다. 
  - containerPort: 30000	#컨테이너 내부 포트
    hostPort: 30000	#호스트 포트
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
  - containerPort: 30003
    hostPort: 30003
  - containerPort: 30004
    hostPort: 30004
  kubeadmConfigPatches:	#kubeadm 설정을 패치하는 부분
  - |
    kind: ClusterConfiguration
    apiServer:
      extraArgs:
        runtime-config: api/all=true	# API 서버에서 모든 API 기능을 활성화합니다.
    controllerManager:	#컨트롤러 매니저의 설정
      extraArgs:
        bind-address: 0.0.0.0	#모든 인터페이스에서 컨트롤러 매니저가 수신하도록 설정합니다.
    etcd:
      local:
        extraArgs:
          listen-metrics-urls: http://0.0.0.0:2381	#etcd의 메트릭을 모든 인터페이스에서 수신하도록 설정합니다.
    scheduler:
      extraArgs:
        bind-address: 0.0.0.0	#모든 인터페이스에서 스케줄러가 수신하도록 설정합니다.
  - |
    kind: KubeProxyConfiguration
    metricsBindAddress: 0.0.0.0	#KubeProxy 메트릭 서버를 모든 인터페이스에서 수신하게 설정합니다.
    ipvs:
      strictARP: true	# IPVS 모드에서 ARP 요청이 들어올 때 잘못된 응답을 방지하도록 합니다.
- role: worker
  labels:
    mynode: worker1
    topology.kubernetes.io/zone: ap-northeast-2a
- role: worker
  labels:
    mynode: worker2
    topology.kubernetes.io/zone: ap-northeast-2b
- role: worker
  labels:
    mynode: worker3
    topology.kubernetes.io/zone: ap-northeast-2c
networking:
  podSubnet: 10.10.0.0/16	#파드에 할당될 IP 서브넷 범위를 정의합니다.
  serviceSubnet: 10.200.1.0/24	#서비스에 할당될 IP 서브넷 범위를 정의합니다.
  kubeProxyMode: "ipvs"	#KubeProxy가 IPVS 모드를 사용하도록 설정합니다.
EOT

🧿 Kind를 사용해 YAML 파일을 기반으로 Kubernetes 클러스터를 생성합니다.

(⎈|N/A:N/A) root@kind:~# kind create cluster --config kind-svc-2w-ipvs.yaml --name myk8s --image kindest/node:v1.31.0
Creating cluster "myk8s" ...
 ✓ Ensuring node image (kindest/node:v1.31.0) 🖼
 ✓ Preparing nodes 📦 📦 📦 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining worker nodes 🚜
Set kubectl context to "kind-myk8s"
You can now use your cluster with:

kubectl cluster-info --context kind-myk8s

Thanks for using kind! 😊

🧿 myk8s 클러스터는 1개의 컨트롤 플레인 노드와 3개의 워커 노드로 구성되어 있으며, 모두 정상적으로 실행 중입니다. 또한, 별도로 네트워크 진단용 netshoot 컨테이너도 실행 중입니다.

  • myk8s-control-plane 컨테이너
    • 0.0.0.0:30000-30004->30000-30004/tcp
      • 호스트의 포트 30000부터 30004까지의 요청이 컨테이너의 동일한 포트로 포워딩된다는 것을 나타냅니다. 즉, 외부에서 해당 포트에 접근하면 이 컨테이너의 포트로 연결됩니다.
    • 127.0.0.1:41827->6443/tcp
      • 호스트의 로컬 주소(127.0.0.1)의 포트 41827가 컨테이너의 6443 포트로 포워딩됩니다. 6443 포트는 Kubernetes API 서버에 일반적으로 사용되는 포트입니다. 따라서, 이 포트를 통해 Kubernetes 클러스터와 통신할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS                                                             NAMES
975b606b8e75   kindest/node:v1.31.0   "/usr/local/bin/entr…"   48 seconds ago   Up 33 seconds                                                                     myk8s-worker3
200f5448e5ba   kindest/node:v1.31.0   "/usr/local/bin/entr…"   48 seconds ago   Up 33 seconds                                                                     myk8s-worker2
00cf15622861   kindest/node:v1.31.0   "/usr/local/bin/entr…"   48 seconds ago   Up 32 seconds   0.0.0.0:30000-30004->30000-30004/tcp, 127.0.0.1:39391->6443/tcp   myk8s-control-plane
4f6a1ace6a3d   kindest/node:v1.31.0   "/usr/local/bin/entr…"   48 seconds ago   Up 33 seconds                                                                     myk8s-worker
a5c3fa4fc5de   nicolaka/netshoot      "sleep infinity"         19 hours ago     Up 19 hours                                                                       mypc

 


🧿 Kubernetes 클러스터의 제어 평면 노드와 세 개의 워커 노드에 필요한 패키지를 설치합니다.

(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bsdmainutils bridge-utils net-tools dnsutils ipset ipvsadm nfacct tcpdump ngrep iputils-ping arping git vim arp-scan -y'

(⎈|kind-myk8s:N/A) root@kind:~# for i in worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-$i sh -c 'apt update && apt install tree psmisc lsof wget bsdmainutils bridge-utils net-tools dnsutils ipset ipvsadm nfacct tcpdump ngrep iputils-ping arping -y'; echo; done

🧿 kube-proxy의 설정 맵(ConfigMap)을 조회하여 그 설정을 확인합니다.

  • kube-proxy는 클러스터 내에서 네트워킹을 관리하며, 서비스와 파드 간 트래픽 라우팅을 담당합니다. 
  • ConfigMap kube-proxy의 설정을 저장하는 파일로, ipvs 모드의 상세 설정이 포함되어 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl describe cm -n kube-system kube-proxy
Name:         kube-proxy
Namespace:    kube-system
Labels:       app=kube-proxy
Annotations:  <none>

Data
====
config.conf:
----
...
ipvs:
  excludeCIDRs: null	#특정 CIDR을 제외하고 싶은 경우, 여기서 지정합니다. 현재는 null로 설정되어 있어 제외된 CIDR이 없습니다.
  minSyncPeriod: 0s		#IPVS 상태가 동기화되는 최소 간격을 정의합니다. 0s로 설정되어 있어, 동기화 간격을 지정하지 않았습니다.
  scheduler: ""			#IPVS 스케줄러 알고리즘을 지정할 수 있는 부분입니다. 현재는 빈 문자열로 설정되어 있으며, 이는 기본값이 사용됨을 의미합니다.
  strictARP: true		#true로 설정되면 IPVS가 외부 네트워크에서 올바른 노드에 대한 ARP 응답만 허용하도록 제한합니다. 이를 통해 네트워크에서 잘못된 ARP 응답을 방지할 수 있습니다.
  syncPeriod: 0s		# IPVS 상태가 동기화되는 주기를 정의합니다. 0s로 설정되어 있어 동기화 주기가 지정되지 않았습니다.
  tcpFinTimeout: 0s		# TCP 연결이 종료된 후 FIN 상태에서 대기하는 시간을 설정합니다. 0s로 설정되어 있어 기본값이 사용됩니다
  tcpTimeout: 0s		#TCP 연결이 유지될 수 있는 최대 시간을 설정합니다. 0s로 설정되어 있어 기본값이 사용됩니다
  udpTimeout: 0s		#UDP 연결이 유지될 수 있는 최대 시간을 설정합니다. 0s로 설정되어 있어 기본값이 사용됩니다.
...

🧿 각 Kubernetes 노드(myk8s-control-plane, myk8s-worker, myk8s-worker2, myk8s-worker3)의 네트워크 라우팅 테이블을 확인합니다.

  • default via 172.18.0.1 dev eth0:
    • 172.18.0.1을 기본 게이트웨이로 설정하여 외부 네트워크로의 출구를 설정하고 있습니다. eth0 인터페이스를 통해 외부 네트워크에 연결됩니다.
  • 10.10.0.2, 10.10.0.3, 10.10.0.4:
    • 이 IP들은 veth 네트워크 인터페이스에 연결된 컨테이너나 파드의 네트워크입니다. 각 파드가 10.10.0.0/24 서브넷 내에서 할당된 IP를 사용하며, scope host는 로컬에서만 접근 가능함을 의미합니다.
  • 10.10.1.0/24 via 172.18.0.5 dev eth0:
    • 10.10.1.0/24 네트워크로 가는 트래픽은 172.18.0.5를 통해 eth0 인터페이스로 전달됩니다. 즉, myk8s-worker 노드가 관리하는 서브넷인 것으로 보입니다.
  • 10.10.2.0/24 via 172.18.0.3 dev eth0:
    • 10.10.2.0/24 네트워크로 가는 트래픽은 172.18.0.3을 통해 eth0으로 전달되며, 이는 myk8s-worker2의 서브넷을 나타냅니다.
  • 10.10.3.0/24 via 172.18.0.2 dev eth0:
    • 10.10.3.0/24 서브넷의 트래픽은 172.18.0.2를 통해 eth0으로 전달되며, myk8s-worker3 노드가 관리하는 서브넷을 나타냅니다.
  • 172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.4:
    • 172.18.0.0/16 네트워크는 도커 네트워크이며, eth0 인터페이스를 통해 이 네트워크와 연결되어 있습니다. src 172.18.0.4는 이 노드의 IP가 172.18.0.4임을 나타냅니다.
(⎈|kind-myk8s:N/A) root@kind:~# for i in control-plane worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-$i ip -c route; echo; done
>> node myk8s-control-plane <<
default via 172.18.0.1 dev eth0
10.10.0.2 dev veth828a3a27 scope host
10.10.0.3 dev vethdd18dee2 scope host
10.10.0.4 dev veth419877f5 scope host
10.10.1.0/24 via 172.18.0.5 dev eth0
10.10.2.0/24 via 172.18.0.3 dev eth0
10.10.3.0/24 via 172.18.0.2 dev eth0
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.4

>> node myk8s-worker <<
default via 172.18.0.1 dev eth0
10.10.0.0/24 via 172.18.0.4 dev eth0
10.10.2.0/24 via 172.18.0.3 dev eth0
10.10.3.0/24 via 172.18.0.2 dev eth0
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.5

🧿 각 노드에서 kube-ipvs0 인터페이스의 IP 주소를 확인합니다.

  • kube-ipvs0는 IPVS 를 통해 가상 IP 주소를 관리하는 가상 인터페이스입니다
  • 모든 노드에서 10.200.1.10/32 와 10.200.1.1/32 주소가 할당되어 있습니다.
  • kube-ipvs0 인터페이스는 모든 노드에서 DOWN 상태이지만, IP 주소가 설정되어 있어 IPVS를 통해 서비스 로드밸런싱을 준비하고 있습니다.
  • 10.200.1.1은 클러스터 기본 게이트웨이 IP, 10.200.1.10은 svc-clusterip 서비스의 클러스터 IP입니다.
(⎈|kind-myk8s:N/A) root@kind:~# for i in control-plane worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-$i ip -br -c addr show kube-ipvs0; echo; done
>> node myk8s-control-plane <<
kube-ipvs0       DOWN           10.200.1.10/32 10.200.1.1/32

>> node myk8s-worker <<
kube-ipvs0       DOWN           10.200.1.10/32 10.200.1.1/32

>> node myk8s-worker2 <<
kube-ipvs0       DOWN           10.200.1.1/32 10.200.1.10/32

>> node myk8s-worker3 <<
kube-ipvs0       DOWN           10.200.1.10/32 10.200.1.1/32

🧿  Kubernetes 클러스터에서 서비스(svc)와 엔드포인트(ep) 리소스를 확인합니다.

  • service/kubernetes:
    • TYPE: ClusterIP: 클러스터 내부에서만 접근할 수 있는 서비스입니다.
    • CLUSTER-IP: 10.200.1.1: 이 IP는 클러스터 내부에서 API 서버에 접근할 때 사용됩니다.
    • PORT(S): 443/TCP: API 서버는 HTTPS 프로토콜을 사용하는 포트 443에서 트래픽을 수신합니다.
  • service/kube-dns:
    • TYPE: ClusterIP: 이 서비스는 클러스터 내에서 DNS 요청을 처리하기 위한 Kubernetes DNS 서비스입니다.
    • CLUSTER-IP: 10.200.1.10: DNS 서비스에 연결하는 데 사용되는 클러스터 IP입니다.
    • PORT(S): 53/UDP, 53/TCP: DNS는 포트 53에서 UDP와 TCP를 통해 트래픽을 처리합니다.
    • PORT(S): 9153/TCP: kube-dns의 메트릭을 노출하는 추가 포트입니다

  • endpoints/kubernetes:
    • ENDPOINTS: 172.18.0.4:6443: 이 엔드포인트는 Kubernetes API 서버를 나타내며, 172.18.0.4에서 포트 6443으로 접근할 수 있습니다. 이는 myk8s-control-plane 노드의 IP 주소입니다.
  • endpoints/kube-dns:
    • ENDPOINTS: 10.10.0.2:53, 10.10.0.3:53, ...: kube-dns는 여러 파드에서 실행 중입니다. 이 IP들은 각각의 파드가 실행 중인 노드의 IP이며, 포트 53에서 DNS 요청을 처리합니다.
    • 10.10.0.2 와 10.10.0.3 은 각각의 kube-dns 파드가 위치한 노드의 IP입니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc,ep -A
NAMESPACE     NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.200.1.1    <none>        443/TCP                  13m
kube-system   service/kube-dns     ClusterIP   10.200.1.10   <none>        53/UDP,53/TCP,9153/TCP   13m

NAMESPACE     NAME                   ENDPOINTS                                            AGE
default       endpoints/kubernetes   172.18.0.4:6443                                      13m
kube-system   endpoints/kube-dns     10.10.0.2:53,10.10.0.3:53,10.10.0.2:53 + 3 more...   13m

✅ IPVS Proxy 모드

🧿 3개의 파드가 각각 클러스터의 다른 워커 노드(myk8s-worker, myk8s-worker2, myk8s-worker3)에서 실행됩니다.

  • 모든 파드는 Traefik의 whoami 컨테이너 이미지를 사용하여 기본 웹 응답을 제공하게 됩니다.
cat <<EOT> 3pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: webpod1
  labels:
    app: webpod
spec:
  nodeName: myk8s-worker
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
---
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

🧿 컨트롤 플레인 노드(myk8s-control-plane)에서 네트워크 진단 툴을 제공하는 netshoot 파드를 실행합니다.

(⎈|kind-myk8s:N/A) root@kind:~# cat <<EOT> netpod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: net-pod
spec:
  nodeName: myk8s-control-plane	#이 파드는 클러스터의 myk8s-control-plane 노드에서 실행됩니다.
  containers:
  - name: netshoot-pod	#컨테이너의 이름
    image: nicolaka/netshoot
    command: ["tail"]	#컨테이너가 종료되지 않고 계속 실행되도록 설정합니다
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0	#파드를 종료할 때 유예 기간 없이 즉시 종료
EOT

🧿 app=webpod 레이블을 가진 파드들에 대한 내부 서비스를 정의합니다.

  • 이 서비스는 클러스터 내에서 9000번 포트로 접근할 수 있으며, 실제 파드에서는 80번 포트로 트래픽을 전달합니다.
  • 서비스 유형은 ClusterIP이므로, 외부에서 직접 접근할 수 없고 클러스터 내부에서만 사용됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# cat <<EOT> svc-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc-clusterip
spec:
  ports:
    - name: svc-webport
      port: 9000	#클러스터 내에서 노출될 포트
      targetPort: 80	#실제 파드에서 수신 대기하는 포트
  selector:	#서비스가 트래픽을 전달할 파드를 선택하기 위한 라벨 셀렉터
    app: webpod	#app=webpod 라벨을 가진 파드들이 이 서비스의 대상으로 선택됩니다.
  type: ClusterIP	#서비스 유형을 ClusterIP로 설정합니다
EOT

🧿 3pod.yaml, netpod.yaml, svc-clusterip.yaml 파일을 사용하여 세 개의 파드와 하나의 서비스 리소스를 생성합니다.

(⎈|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 클러스터의 cluster-cidr  service-cluster-ip-range에 대한 정보를 확인합니다.

  • --service-cluster-ip-range=10.200.1.0/24:
    • 이 설정은 클러스터 내에서 서비스가 사용할 수 있는 IP 주소 범위를 정의합니다.
    • 10.200.1.0/24: 이 CIDR 블록은 256개의 IP 주소 (10.200.1.0 ~ 10.200.1.255)를 포함하며, 이 범위 내의 IP 주소들은 Kubernetes 서비스가 클러스터 내에서 사용할 수 있습니다.
    • 기본적으로 Kubernetes에서 서비스는 이 범위 내의 IP 주소를 통해 생성되며, 이 주소로는 ClusterIP 타입의 서비스에 접근할 수 있습니다.
  • --cluster-cidr=10.10.0.0/16:
    • 이 설정은 클러스터 내에서 파드가 사용할 수 있는 IP 주소 범위를 정의합니다.
    • 10.10.0.0/16: 이 CIDR 블록은 65,536개의 IP 주소 (10.10.0.0 ~ 10.10.255.255)를 포함하며, 이 범위 내의 IP 주소들은 Kubernetes 클러스터의 파드들 간의 통신을 위한 것입니다.
    • 클러스터의 각 노드에서 생성된 파드들은 이 주소 범위 내의 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",

🧿 Kubernetes 클러스터 내의 모든 파드에 대한 정보를 확인합니다.

  • net-pod, webpod1, webpod2, webpod3 모두 Running 상태이며, 각각의 파드에 대해 정상적으로 IP가 할당되어 있습니다. 
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP          NODE                  NOMINATED NODE   READINESS GATES
net-pod   1/1     Running   0          26s   10.10.0.5   myk8s-control-plane   <none>           <none>
webpod1   1/1     Running   0          26s   10.10.1.2   myk8s-worker          <none>           <none>
webpod2   1/1     Running   0          26s   10.10.2.2   myk8s-worker2         <none>           <none>
webpod3   1/1     Running   0          26s   10.10.3.2   myk8s-worker3         <none>           <none>

🧿 Kubernetes 클러스터에서 svc-clusterip 서비스 정보를 확인합니다.

  • svc-clusterip는 ClusterIP 타입의 서비스로, 클러스터 내부에서만 접근할 수 있는 IP 주소 10.200.1.17이 할당되었습니다. 이 서비스는 9000번 포트를 통해 트래픽을 수신하고 있습니다.
(⎈|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.17   <none>        9000/TCP   31s

🧿 Kubernetes 클러스터에서 svc-clusterip 서비스에 대한 상세 정보를 확인합니다.

  • svc-clusterip는 ClusterIP 타입의 서비스로, app=webpod 레이블을 가진 파드에 트래픽을 전달합니다. 서비스의 클러스터 IP는 10.200.1.17이며, 9000/TCP 포트로 외부에서 접근할 수 있습니다. 이 서비스는 webpod1, webpod2, webpod3의 IP 주소와 포트에 트래픽을 라우팅하여 클러스터 내에서의 통신을 가능하게 합니다.
(⎈|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.17	#서비스에 할당된 클러스터 IP 주소
IPs:                      10.200.1.17
Port:                     svc-webport  9000/TCP	#서비스가 사용하는 포트
TargetPort:               80/TCP	#이 서비스가 트래픽을 전달할 파드의 포트
Endpoints:                10.10.3.2:80,10.10.1.2:80,10.10.2.2:80	#이 서비스가 트래픽을 전달할 파드의 IP 주소와 포트 목록
Session Affinity:         None
Internal Traffic Policy:  Cluster	#내부 트래픽 정책을 나타냅니다. Cluster는 클러스터 내에서의 트래픽만 처리됨을 의미합니다.
Events:                   <none>

🧿 Kubernetes 클러스터에서 svc-clusterip 서비스의 엔드포인트 정보를 확인합니다.

  • svc-clusterip 서비스는 10.10.1.2, 10.10.2.2, 10.10.3.2의 IP 주소와 80 포트를 가진 세 개의 파드로 트래픽을 라우팅할 수 있습니다. 이 엔드포인트들은 webpod1, webpod2, webpod3에 해당하며, 이 서비스를 통해 클러스터 내에서 요청을 처리하게 됩니다.

  • svc-clusterip 서비스와 관련된 엔드포인트 슬라이스 svc-clusterip-tfrz5는 IPv4 주소 형식을 사용하며, 포트 80에서 10.10.3.2, 10.10.1.2, 10.10.2.2의 IP 주소를 가진 파드로 트래픽을 전달할 수 있습니다.
    • EndpointSlice는 Kubernetes에서 서비스의 엔드포인트를 보다 효율적으로 관리하고 확장하기 위해 도입된 리소스입니다. 기존의 Endpoints 리소스는 단일 객체로 모든 엔드포인트 정보를 저장하지만, EndpointSlice는 여러 개의 슬라이스로 엔드포인트를 나누어 저장할 수 있습니다. 이 방식은 큰 클러스터에서 더 나은 성능과 관리성을 제공합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get endpoints svc-clusterip
NAME            ENDPOINTS                                AGE
svc-clusterip   10.10.1.2:80,10.10.2.2:80,10.10.3.2:80   40s

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

🧿각 노드에서 kube-ipvs0 인터페이스의 IP 주소를 확인합니다.

  • 10.200.1.10/32: 클러스터 DNS 서비스의 IP 주소입니다.
  • 10.200.1.1/32: 클러스터의 기본 서비스 IP 주소입니다.
  • 10.200.1.17/32: svc-clusterip 서비스의 ClusterIP 주소입니다.
(⎈|kind-myk8s:N/A) root@kind:~# for i in control-plane worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-$i ip -br -c addr show kube-ipvs0; echo; done
>> node myk8s-control-plane <<
kube-ipvs0       DOWN           10.200.1.10/32 10.200.1.1/32 10.200.1.17/32

>> node myk8s-worker <<
kube-ipvs0       DOWN           10.200.1.10/32 10.200.1.1/32 10.200.1.17/32

>> node myk8s-worker2 <<
kube-ipvs0       DOWN           10.200.1.1/32 10.200.1.10/32 10.200.1.17/32

>> node myk8s-worker3 <<
kube-ipvs0       DOWN           10.200.1.10/32 10.200.1.1/32 10.200.1.17/32

🧿 kube-ipvs0 인터페이스의 상세 정보를 확인합니다.

(⎈|kind-myk8s:N/A) root@kind:~# for i in control-plane worker worker2 worker3; do echo ">> node myk8s-$i <<"; docker exec -it myk8s-$i ip -d -c addr show kube-ipvs0; echo; done
>> node myk8s-control-plane <<
2: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
    link/ether 16:f9:7e:8b:42:bc brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 0 maxmtu 0
    dummy numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.200.1.10/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.200.1.1/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.200.1.17/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever

>> node myk8s-worker <<
2: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
    link/ether 12:4b:a4:c2:40:f9 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 0 maxmtu 0
    dummy numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.200.1.10/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.200.1.1/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.200.1.17/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
...

🧿 Kubernetes 서비스의 클러스터 IP와 포트 번호를 변수를 저장합니다.

  • 10.200.1.17: svc-clusterip 서비스의 클러스터 IP 주소입니다.
  • 9000: 서비스가 노출하는 포트 번호입니다.
(⎈|kind-myk8s:N/A) root@kind:~# CIP=$(kubectl get svc svc-clusterip -o jsonpath="{.spec.clusterIP}")
CPORT=$(kubectl get svc svc-clusterip -o jsonpath="{.spec.ports[0].port}")
echo $CIP $CPORT
10.200.1.17 9000

🧿 $CIP $CPORT 변수를 사용하여 svc-clusterip 서비스에 대한 IPVS의 로드 밸런싱 상태를 확인합니다.

  • ipvsadm 명령어는 IPVS(IPvS, IP Virtual Server) 상태를 표시하는 데 사용됩니다.
    • LocalAddress:Port: 로컬 서비스의 IP와 포트 (여기서는 10.200.1.17:9000).
    • Scheduler: 로드 밸런싱 스케줄러의 종류 (여기서는 rr = round-robin).
    • Flags: 플래그 설정 (예: Masq는 NAT를 의미).
    • RemoteAddress:Port: 백엔드 서버의 IP와 포트.
    • Forward: 포워딩 방법 (여기서는 Masq).
    • Weight: 서버의 가중치 (여기서는 모두 1로 동일).
    • ActiveConn: 현재 활성 연결 수.
    • InActConn: 비활성 연결 수.
  • TCP 10.200.1.17:9000 rr
    • 10.200.1.17의 9000 포트에 대해 라운드 로빈 방식으로 요청을 분산.
  • 세 개의 백엔드 서버 (10.10.1.2, 10.10.2.2, 10.10.3.2)가 포트 80에서 요청을 처리하고 있습니다. 현재 모든 백엔드 서버에는 활성 연결이 없으며, 각 서버에 대한 비활성 연결 수는 0입니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane ipvsadm -Ln -t $CIP:$CPORT
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.200.1.17:9000 rr
  -> 10.10.1.2:80                 Masq    1      0          0
  -> 10.10.2.2:80                 Masq    1      0          0
  -> 10.10.3.2:80                 Masq    1      0          0

🧿 IPVS의 특정 서비스에 대한 통계 정보( --stats )를 확인합니다.

  • Conns: 현재 연결 수 (여기서는 0).
  • InPkts: 수신 패킷 수 (여기서는 0).
  • OutPkts: 송신 패킷 수 (여기서는 0).
  • InBytes: 수신 바이트 수 (여기서는 0).
  • OutBytes: 송신 바이트 수 (여기서는 0).
  • svc-clusterip 서비스에 대한 현재 통계 정보를 보여줍니다. 모든 연결, 패킷 및 바이트 수치가 0인 것으로 나타나, 아직 클러스터 IP 서비스로의 요청이 없음을 확인할 수 있습니다. 이 상태는 서비스가 설정되었지만, 클라이언트에서 해당 서비스에 접근하지 않았거나 트래픽이 발생하지 않았음을 의미합니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane ipvsadm -Ln -t $CIP:$CPORT --stats
Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
  -> RemoteAddress:Port
TCP  10.200.1.17:9000                    0        0        0        0        0
  -> 10.10.1.2:80                        0        0        0        0        0
  -> 10.10.2.2:80                        0        0        0        0        0
  -> 10.10.3.2:80                        0        0        0        0        0

🧿 IPVS에 설정된 특정 서비스의 패킷 전송 속도( --rate )를 확인합니다.

  • CPS: 초당 연결 수 (Connections Per Second).
  • InPPS: 초당 수신 패킷 수 (Incoming Packets Per Second).
  • OutPPS: 초당 송신 패킷 수 (Outgoing Packets Per Second).
  • InBPS: 초당 수신 바이트 수 (Incoming Bytes Per Second).
  • OutBPS: 초당 송신 바이트 수 (Outgoing Bytes Per Second).
  • svc-clusterip 서비스에 대한 현재 패킷 전송 속도 정보를 보여줍니다. 모든 연결 및 패킷 전송 속도가 0인 것으로 나타나, 해당 서비스로의 요청이 없음을 확인할 수 있습니다. 이는 서비스가 설정되었지만, 클라이언트에서 해당 서비스에 접근하지 않았거나 트래픽이 발생하지 않았음을 의미합니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane ipvsadm -Ln -t $CIP:$CPORT --rate
Prot LocalAddress:Port                 CPS    InPPS   OutPPS    InBPS   OutBPS
  -> RemoteAddress:Port
TCP  10.200.1.17:9000                    0        0        0        0        0
  -> 10.10.1.2:80                        0        0        0        0        0
  -> 10.10.2.2:80                        0        0        0        0        0
  -> 10.10.3.2:80                        0        0        0        0        0

 


🧿 Kubernetes 클러스터 내에서 서비스의 NAT(Network Address Translation) 설정을 확인합니다.

  • iptables -t nat -S: NAT 테이블의 현재 설정을 출력합니다.
  • grep KUBE-CLUSTER-IP: 출력 중에서 KUBE-CLUSTER-IP와 관련된 규칙만 필터링하여 보여줍니다

  • -A KUBE-SERVICES: KUBE-SERVICES 체인에 규칙을 추가합니다.
  • ! -s 10.10.0.0/16: 소스 IP가 10.10.0.0/16 범위가 아닌 경우에만 이 규칙을 적용합니다. 이는 클러스터 내부의 IP를 제외한 외부 IP에 해당됩니다.
  • -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose": 규칙에 대한 설명을 추가합니다.
  • -m set --match-set KUBE-CLUSTER-IP dst,dst: 목적지 IP가 KUBE-CLUSTER-IP 세트에 포함된 경우 이 규칙을 적용합니다.
  • -j KUBE-MARK-MASQ: 매칭되는 패킷을 NAT 마스커레이드로 표시합니다. 즉, 외부에서 내부로 패킷이 전달될 때 출발지 주소를 변환합니다.
클러스터 외부에서 오는 요청이 클러스터 IP로 향할 때, NAT 마스커레이드 규칙을 적용하여 요청이 내부로 전달될 수 있도록 합니다.

  • -A KUBE-SERVICES: 다시 KUBE-SERVICES 체인에 규칙을 추가합니다.
  • -m set --match-set KUBE-CLUSTER-IP dst,dst: 목적지 IP가 KUBE-CLUSTER-IP 세트에 포함된 경우 이 규칙을 적용합니다.
  • -j ACCEPT: 매칭되는 패킷을 허용합니다. 즉, 클러스터 IP로 향하는 패킷은 차단되지 않고 통과합니다.
클러스터 IP에 대한 패킷을 허용하여, 클러스터 내의 서비스가 접근 가능하도록 합니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane iptables -t nat -S | grep KUBE-CLUSTER-IP
-A KUBE-SERVICES ! -s 10.10.0.0/16 -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose" -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ
-A KUBE-SERVICES -m set --match-set KUBE-CLUSTER-IP dst,dst -j ACCEPT

🧿 Kubernetes 클러스터에서 KUBE-CLUSTER-IP라는 이름의 IP 집합을 확인합니다.

  • KUBE-CLUSTER-IP는 Kubernetes 클러스터 내에서 서비스 IP를 관리하기 위해 사용되는 IP 집합입니다.
  • 이 집합은 클러스터 IP와 포트를 빠르게 조회할 수 있도록 해시 형태로 저장됩니다.
  • 각 IP와 포트 조합은 특정 서비스로의 트래픽을 라우팅하는 데 사용됩니다.
  • 이 정보를 통해 Kubernetes 클러스터 내에서 네트워크 트래픽을 효율적으로 관리하고, 필요한 경우 NAT 규칙에 따라 패킷을 전달할 수 있습니다.

  • Members:
    • 실제로 집합에 포함된 IP:포트 조합의 목록입니다.
    • 10.200.1.10,tcp:9153: IP 10.200.1.10에서 TCP 프로토콜을 사용하는 9153 포트.1
    • 10.200.1.17,tcp:9000: IP 10.200.1.17에서 TCP 프로토콜을 사용하는 9000 포트.
    • 10.200.1.10,tcp:53: IP 10.200.1.10에서 TCP 프로토콜을 사용하는 53 포트 (DNS).
    • 10.200.1.1,tcp:443: IP 10.200.1.1에서 TCP 프로토콜을 사용하는 443 포트 (HTTPS).
    • 10.200.1.10,udp:53: IP 10.200.1.10에서 UDP 프로토콜을 사용하는 53 포트 (DNS).

ipset은 Linux에서 IP 주소 및 포트 정보를 관리하는 도구로, 대규모 네트워크 환경에서 필터링 및 트래픽 관리에 유용합니다. 특히 방화벽 규칙을 설정할 때 IP 주소를 효율적으로 관리하고 성능을 향상시키기 위해 사용됩니다.

(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane ipset list KUBE-CLUSTER-IP
Name: KUBE-CLUSTER-IP
Type: hash:ip,port
Revision: 6
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0x020b3afa
Size in memory: 440
References: 3
Number of entries: 5
Members:
10.200.1.10,tcp:9153
10.200.1.17,tcp:9000
10.200.1.10,tcp:53
10.200.1.1,tcp:443
10.200.1.10,udp:53

🧿 Kubernetes 클러스터 svc-clusterip 서비스의  IP 주소를 가져와서 변수에 저장합니다.

(⎈|kind-myk8s:N/A) root@kind:~# SVC1=$(kubectl get svc svc-clusterip -o jsonpath={.spec.clusterIP})
echo $SVC1
10.200.1.17

🧿 Kubernetes 클러스터 내의 net-pod라는 이름의 파드에서 특정 서비스에 대해 HTTP 요청을 실행하고, 그 결과에서 호스트 이름을 추출하는 과정을 확인합니다.

  • 클러스터 내의 서비스가 여러 파드에 분산되어 있는 경우, 요청이 서로 다른 파드에 랜덤하게 라우팅되는 모습을 관찰할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1:9000
Hostname: webpod2	#응답을 반환하는 파드의 이름.
IP: 127.0.0.1	#요청을 처리하는 파드의 IP 주소
IP: ::1
IP: 10.10.2.2
IP: fe80::48bb:54ff:fe2b:55e0
RemoteAddr: 10.10.0.5:57694	#클라이언트의 IP 주소와 포트 번호
GET / HTTP/1.1
Host: 10.200.1.17:9000	#요청을 보낸 서비스의 IP 주소 및 포트.
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: webpod1
(⎈|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
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1:9000 | grep Hostname
Hostname: webpod1
(⎈|kind-myk8s:N/A) root@kind:~# kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1:9000 | grep Hostname
Hostname: webpod3

🧿 Kubernetes 클러스터의 로드 밸런싱 정보를 확인합니다.

  • 총 10회 요청 중 webpod2가 4회, webpod3가 3회, webpod1이 3회 응답했습니다.
  • 총 100회 요청 중 webpod1이 34회, webpod3와 webpod2가 각각 33회 응답했습니다.
  • 총 1000회 요청 중 webpod3가 334회, webpod2와 webpod1이 각각 333회 응답했습니다.
  • 로드 밸런싱: 요청 수가 증가함에 따라 각 파드에 대한 응답 횟수가 거의 비슷하게 유지되는 것은 Kubernetes의 서비스가 요청을 여러 파드에 균등하게 분산하는 로드 밸런싱 기능을 보여줍니다.
(⎈|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"
      4 Hostname: webpod2
      3 Hostname: webpod3
      3 Hostname: webpod1
(⎈|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"
     34 Hostname: webpod1
     33 Hostname: webpod3
     33 Hostname: webpod2
(⎈|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"
    334 Hostname: webpod3
    333 Hostname: webpod2
    333 Hostname: webpod1

'쿠버네티스 네트워크 스터디 3기' 카테고리의 다른 글

[6주차] Gateway API  (0) 2024.10.08
[6주차] Ingress  (0) 2024.10.07
[5주차] LoadBalancer - MetalLB  (16) 2024.10.02
[5주차] 실습기본환경구성  (3) 2024.10.02
[4주차] NodePort  (0) 2024.09.24
Comments