Ssoon
[5주차] IPVS 본문
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 클러스터와 통신할 수 있습니다.
- 0.0.0.0:30000-30004->30000-30004/tcp
(⎈|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 인터페이스를 통해 외부 네트워크에 연결됩니다.
- 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는 로컬에서만 접근 가능함을 의미합니다.
- 이 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.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.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 노드가 관리하는 서브넷을 나타냅니다.
- 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