쿠버네티스 성능테스트 도구를 소개합니다. 쿠버네티스 API 서버에 동시에 여러 List 요청을 보내는 경우 API 서버에 부하가 가서 OOM이 발생할 수 있습니다. 관련해서 API 서버에 기능 개선을 한 내용도 공식 블로그에 나와있습니다.
https://kubernetes.io/blog/2024/12/17/kube-apiserver-api-streaming/
Enhancing Kubernetes API Server Efficiency with API Streaming
Managing Kubernetes clusters efficiently is critical, especially as their size is growing. A significant challenge with large clusters is the memory overhead caused by list requests. In the existing implementation, the kube-apiserver processes list request
kubernetes.io
kube-burner
설치방법
먼저 바이너리를 설치하겠습니다. M1 기준으로 작성되었습니다. kind-control-plane 노드에 들어갑니다.
docker exec -it kind-control-plane bash
curl -LO https://github.com/kube-burner/kube-burner/releases/download/v1.17.3/kube-burner-V1.17.3-linux-arm64.tar.gz \
&& tar -xzf kube-burner-V1.17.3-linux-arm64.tar.gz \
&& mv kube-burner /usr/local/bin/ \
&& rm kube-burner-V1.17.3-linux-arm64.tar.gz
잘 설치되었는지도 확인해봅니다.
kube-burner -h
check-alerts Evaluate alerts for the given time range
completion Generates completion scripts for bash shell
destroy Destroy old namespaces labeled with the given UUID.
health-check Check for Health Status of the cluster
help Help about any command
import Import metrics tarball
index Index kube-burner metrics
init Launch benchmark
measure Take measurements for a given set of resources without running workload
version Print the version number of kube-burner
# 버전 확인
kube-burner version
Version: 1.17.3
사용법
테스트 스크립트와 어떤 형식의 오브젝트를 생성할 것인지 템플릿을 작성합니다.
global:
measurements:
- name: none
jobs:
- name: create-deployments
jobType: create
jobIterations: 1 # How many times to execute the job , 해당 job을 5번 반복 실행
qps: 1 # Limit object creation queries per second , 초당 최대 요청 수 (평균 속도 제한) - qps: 10이면 초당 10개 요청
burst: 1 # Maximum burst for throttle , 순간적으로 처리 가능한 요청 최대치 (버퍼) - burst: 20이면 한순간에 최대 20개까지 처리 가능
namespace: kube-burner-test
namespaceLabels: {kube-burner-job: delete-me}
waitWhenFinished: true # false
verifyObjects: false
preLoadImages: true # false
preLoadPeriod: 30s # default 1m
objects:
- objectTemplate: s1-deployment.yaml
replicas: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-{{ .Iteration}}-{{.Replica}}
labels:
app: test-{{ .Iteration }}-{{.Replica}}
kube-burner-job: delete-me
spec:
replicas: 1
selector:
matchLabels:
app: test-{{ .Iteration}}-{{.Replica}}
template:
metadata:
labels:
app: test-{{ .Iteration}}-{{.Replica}}
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
이렇게 한다음에 다음과 같이 실행해주면 테스트가 실행됩니다.
kube-burner init -c <테스트 파일>
pre-load를 하는 동안 네임스페이스가 생성이 되었다가
삭제되고 테스트케이스 설정에서 정의한 테스트 네임스페이스가 생성이 됩니다.
테스트 해보기
테스트 환경 구축하기
클러스터 kind로 생성하기
프로메테우스에서 메트릭을수집할 수 있도록 bind-address와 metric-urls를 변경해서 배포합니다.
kind create cluster --name myk8s --image kindest/node:v1.33.2 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001
hostPort: 30001
- containerPort: 30002
hostPort: 30002
- containerPort: 30003
hostPort: 30003
kubeadmConfigPatches: # Prometheus Target connection refused bind-address 설정
- |
kind: ClusterConfiguration
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
EOF
메트릭 서버 배포하기
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm upgrade --install metrics-server metrics-server/metrics-server --set 'args[0]=--kubelet-insecure-tls' -n kube-system
프로메테우스 스택 배포하기
프로메테우스 헬름 배포를 위한 레포 추가를 합니다.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
이제 프로메테우스 스택을 배포해보겠습니다. 설치가 완료되면 브라우저에서 127.0.0.1:3002로 그라파나에 접근 가능합니다. 비밀번호 (admin/prom-operator)
cat <<EOF > monitor-values.yaml
prometheus:
prometheusSpec:
scrapeInterval: "15s"
evaluationInterval: "15s"
service:
type: NodePort
nodePort: 30001
grafana:
defaultDashboardsTimezone: Asia/Seoul
adminPassword: prom-operator
service:
type: NodePort
nodePort: 30002
alertmanager:
enabled: false
defaultRules:
create: false
prometheus-windows-exporter:
prometheus:
monitor:
enabled: false
EOF
# 배포
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 75.15.1 \
-f monitor-values.yaml --create-namespace --namespace monitoring
시나리오 1 : 디플로이먼트 1개(파드 1개) 생성 → 삭제
cat << EOF > s1-config.yaml
global:
measurements:
- name: none
jobs:
- name: create-deployments
jobType: create
jobIterations: 1 # How many times to execute the job , 해당 job을 5번 반복 실행
qps: 1 # Limit object creation queries per second , 초당 최대 요청 수 (평균 속도 제한) - qps: 10이면 초당 10개 요청
burst: 1 # Maximum burst for throttle , 순간적으로 처리 가능한 요청 최대치 (버퍼) - burst: 20이면 한순간에 최대 20개까지 처리 가능
namespace: kube-burner-test
namespaceLabels: {kube-burner-job: delete-me}
waitWhenFinished: true # false
verifyObjects: false
preLoadImages: true # false
preLoadPeriod: 30s # default 1m
objects:
- objectTemplate: s1-deployment.yaml
replicas: 1
EOF
deployment는 아래의 형식으로 만들게 됩니다. 위의 objects의 템플릿 파일입니다.
cat << EOF > s1-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-{{ .Iteration}}-{{.Replica}}
labels:
app: test-{{ .Iteration }}-{{.Replica}}
kube-burner-job: delete-me
spec:
replicas: 1
selector:
matchLabels:
app: test-{{ .Iteration}}-{{.Replica}}
template:
metadata:
labels:
app: test-{{ .Iteration}}-{{.Replica}}
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
EOF
위의 파일을 생성했으면 이제 실행해보겠습니다.
kube-burner init -c s1-config.yaml --log-level debug
정확하게 iteration 번호와 Replica 번호에 맞춰 deployment가 생성된것을 확인할 수 있습니다.
테스트를 완료되었으니 이제 삭제해 보겠습니다.
cat << EOF > s1-config-delete.yaml
# global:
# measurements:
# - name: none
jobs:
- name: delete-deployments-namespace
qps: 500
burst: 500
namespace: kube-burner-test
jobType: delete
waitWhenFinished: true
objects:
- kind: Deployment
labelSelector: {kube-burner-job: delete-me}
apiVersion: apps/v1
- kind: Namespace
labelSelector: {kube-burner-job: delete-me}
EOF
위의 파일을 만들어서 다음과 같이 실행하면 삭제가 됩니다.
kube-burner init -c s1-config-delete.yaml --log-level debug
위의 명령어를 통해 테스트하는동안 생성되었든 네임스페이스가 삭제된 것을 확인할 수 있습니다.
시나리오 2 : 노드 1대에 최대 파드(150개) 배포 시도
cat << EOF > s2-config.yaml
global:
measurements:
- name: none
jobs:
- name: create-deployments
jobType: create
jobIterations: 150 # create-deployment를 150번 수행한다
qps: 300 #
burst: 300 #
namespace: kube-burner-test
namespaceLabels: {kube-burner-job: delete-me}
waitWhenFinished: true # false
verifyObjects: false
preLoadImages: true # false
preLoadPeriod: 30s # default 1m
objects:
- objectTemplate: s1-deployment.yaml
replicas: 1
EOF
이제 실행해보겠습니다.
kube-burner init -c s2-config.yaml --log-level debug
수행해보니 급격하게 API서버의 메트릭 상태를 확인했을 때 급격하게 goroutine의 갯수와 메모리, CPU의 사용량이 증가한 것을 확인할 수 있었습니다.
그리고 한개의 노드에 150개의 파드를 생성하려고 하니 max-pod 리밋에 막혀 뜨지 않는 파드들이 생성되었습니다.
kubectl describe node myk8s-control-plane
러닝 중인 파드의 수도 110개로 150개의 파드를 1개의 노드에서 생성하지 못합니다.
해당 리밋은 kubelet의 설정(/var/lib/kubelet/config.yaml)을 변경해줘야하고, kubelet을 재시작 하면 적용이 됩니다.
kubelet을 재시작 시켜준 뒤에는 잘 적용된 것을 확인할 수 있습니다.
시나리오 3 : 노드 1대에 최대 파드(300개) 배포 시도
cat << EOF > s3-config.yaml
global:
measurements:
- name: none
jobs:
- name: create-deployments
jobType: create
jobIterations: 300 #
qps: 300 #
burst: 300 #
namespace: kube-burner-test
namespaceLabels: {kube-burner-job: delete-me}
waitWhenFinished: true # false
verifyObjects: false
preLoadImages: true # false
preLoadPeriod: 30s # default 1m
objects:
- objectTemplate: s1-deployment.yaml
replicas: 1
EOF
이제 실행해보겠습니다.
kube-burner init -c s3-config.yaml --log-level debug
이번에는 maxpod수가 400임에도 다 배포가 되지 않고 Pending이 되어있습니다.
뜨지 않고 있는 파드를 하나 잡아 확인해보니 다음과 같이 노드의 아이피가 고갈되어 파드에 아이피를 할당할 수 없어 파드를 생성할 수 없다는 에러가 보입니다.
노드의 파드 대역이 24비트로 총 245개만을 할당할 수 있기 때문입니다.
'K8S > 🔥 network study🔥' 카테고리의 다른 글
로컬에서 쿠버네티스 api 서버에 List 호출 테스트 (1) | 2025.08.30 |
---|---|
perf-tests로 쿠버네티스 성능 테스트해보기 (0) | 2025.08.30 |
[cilium] Mutual Authentication 테스트 해보기 (진행 중) (1) | 2025.08.22 |
[cilium] gateway API로 트래픽 분할하기 (0) | 2025.08.22 |
[cilium] TProxy 이해해보기 (0) | 2025.08.22 |