[Study 5주차] 쿠버네티스 Service - IPVS Proxy 모드
- -
CoudNet@ 팀의 가시다님께서 리딩하시는 KANS Study (Kubernetes Advanced Networking Study) 5주차 스터디 내용 정리
이번 글에는 Service 의 동작 방식 중 IPVS Proxy 에 대해서 알아보겠습니다.
1. IPVS Proxy 모드
IPVS 모드는 리눅스 커널에서 제공하는 IPVS 가 서비스 프록시 역할을 수행하는 모드입니다.
IPVS 는 넷필터에서 동작하는 Layer 4 로드밸런서 입니다.
기존의 iptables 보다 높은 성능 처리를 보여주고, 규칙 개수도 줄일 수 있습니다.
또한 아래와 같은 다양한 부하분산 알고리즘도 제공해줍니다.
IPVS 가 제공하는 다양한 부하분산 알고리즘
1. 라운드 로빈
우선순위를 두지 않고, 요청을 대상 목적지 파드로 돌아가면서 전달
2. 최소 연결
목적지 파드의 연결 개수가 가장 적은 곳을 우선해서 전달
3. 목적지 해싱
목적지 IP 주소로 해시값을 계산하여 목적지 파드를 결정하여 전달
4. 출발지 해싱
출발지 IP 주소로 해시값을 계산하여 목적지 파드를 결정하여 전달
5. 최단 지연
응답 속도가 가장 빠른 목적지 파드 선택
1.1. 실습환경 구성
실습 환경은 kind 를 사용하여 구성했습니다.
cat <<EOT> kind-svc-2w-ipvs.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
"InPlacePodVerticalScaling": true
"MultiCIDRServiceAllocator": true
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:
- |
kind: ClusterConfiguration
apiServer:
extraArgs:
runtime-config: api/all=true
controllerManager:
extraArgs:
bind-address: 0.0.0.0
etcd:
local:
extraArgs:
listen-metrics-urls: http://0.0.0.0:2381
scheduler:
extraArgs:
bind-address: 0.0.0.0
- |
kind: KubeProxyConfiguration
metricsBindAddress: 0.0.0.0
ipvs:
strictARP: true
- 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
serviceSubnet: 10.200.1.0/24
kubeProxyMode: "ipvs"
EOT
# k8s 클러스터 설치
kind create cluster --config kind-svc-2w-ipvs.yaml --name myk8s --image kindest/node:v1.31.0
# 노드에 기본 툴 설치
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'
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
# 테스트용 컨테이너 생성
docker run -d --rm --name mypc --network kind --ip 172.18.0.100 nicolaka/netshoot sleep infinity
파드 환경 구성
# 목적지 파드 생성
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
# 클라이언트 파드 생성
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"]
terminationGracePeriodSeconds: 0
EOT
# 서비스 생성
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
# 배포
kubectl apply -f 3pod.yaml,netpod.yaml,svc-clusterip.yaml
1.2. IPVS Proxy 모드 확인
ipvs 기본값 확인
# 로그 확인용 툴 설치
kubectl krew install stern
# Kube-Proxy 로그 확인
kubectl stern -n kube-system -l k8s-app=kube-proxy --since 2h | egrep '(ipvs|IPVS)'
# 기본 모드 정보 확인
kubectl get cm -n kube-system kube-proxy -o yaml | egrep 'mode|strictARP|scheduler'
노드 별 네트워크 정보 확인
kube-ipvs0 네트워크 인터페이스가 있는 것을 확인할 수 있습니다.
또한, Service ClusterIP 생성 시 kube-ipvs0 인터페이스에 해당 IP 가 할당되는 것을 알 수 있습니다.
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
IPVS Proxy 모드 부하분산 확인
# 변수 지정
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
# IPVS 부하분산 테이블 확인
docker exec -it myk8s-control-plane ipvsadm -Ln -t $CIP:$CPORT
# 컨트롤플레인에서 ipvsadm 모니터링
watch -d "docker exec -it myk8s-control-plane ipvsadm -Ln -t $CIP:$CPORT --stats; echo; docker exec -it myk8s-control-plane ipvsadm -Ln -t $CIP:$CPORT --rate"
# 서비스 접근
SVC1=$(kubectl get svc svc-clusterip -o jsonpath={.spec.clusterIP})
kubectl exec -it net-pod -- curl -s --connect-timeout 1 $SVC1:9000
# 10번 접속
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"
# 100번 접속
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"
# 1000번 접속
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"
iptables 모드에 비해 월등하게 균등한 부하 분산이 이루어지는 것을 알 수 있습니다.
IPVS Proxy 모드는 기존의 iptables 모드에 비해 성능이 좋기 때문에,
IPVS Proxy 모드를 사용할 수 있는 환경이라면 적극 고려해보는 것도 좋을 것 같습니다.
'Kubernetes' 카테고리의 다른 글
[Study 6주차] 쿠버네티스 Gateway API (3) | 2024.10.13 |
---|---|
[Study 6주차] 쿠버네티스 Ingress (4) | 2024.10.13 |
[Study 5주차] 쿠버네티스 Service - LoadBalancer (MetalLB) (0) | 2024.10.02 |
[Study 4주차] 쿠버네티스 Service - NodePort (1) | 2024.09.28 |
[Study 4주차] 쿠버네티스 Service - ClusterIP (0) | 2024.09.28 |