로컬에서 쿠버네티스 api 서버에 List 호출 테스트

쿠버네티스 버전이 33으로 변경되면서 List 호출에 대해 성능이 많이 개선되었다고 하여 실제로 비교해보며 정말로 줄어들었는지 확인해보려고 합니다. 

 

관련 글)

https://kubernetes.io/blog/2025/05/09/kubernetes-v1-33-streaming-list-responses/

 

Kubernetes v1.33: Streaming List responses

Managing Kubernetes cluster stability becomes increasingly critical as your infrastructure grows. One of the most challenging aspects of operating large-scale clusters has been handling List requests that fetch substantial datasets - a common operation tha

kubernetes.io

 

클러스터 생성하기

1.32 클러스터 생성하기

kind create cluster --name k8s-32 --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: ClusterConfiguration
    controllerManager:
      extraArgs:
        bind-address: "0.0.0.0"
    scheduler:
      extraArgs:
        bind-address: "0.0.0.0"
EOF

 

1.33 클러스터 생성하기

kind create cluster --name k8s-33 --image kindest/node:v1.33.2 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: ClusterConfiguration
    controllerManager:
      extraArgs:
        bind-address: "0.0.0.0"
    scheduler:
      extraArgs:
        bind-address: "0.0.0.0"
EOF

 

테스트 구성하기

테스트 결과는 perf-dash의 다음 대시보드에서 보이는 결과로 유사하게 구성해보려고 합니다. 

https://perf-dash.k8s.io/#/?jobname=benchmark%20list&metriccategoryname=E2E&metricname=Resources&Resource=memory&PodName=kube-apiserver-benchmark-list-master%2Fkube-apiserver

 

https://perf-dash.k8s.io/#/?jobname=benchmark%20list&metriccategoryname=E2E&metricname=Resources&Resource=memory&PodName=kube-apiserver-benchmark-list-master%2Fkube-apiserver

{{jobName}} {{metricCategoryName}} {{metricName}} {{item}} Runs over time Click a data point to see build logs. CTRL+click anywhere to trim outliers.

perf-dash.k8s.io

 

테스트  준비

위의 블로그글에 보면 각각 1GB의 데이터를 반환하는 10개의 목록 요청을 동시에 실행하는 새로운 목록 벤치마크를 했다고 합니다. 

https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/list

 

perf-tests/clusterloader2/testing/list at master · kubernetes/perf-tests

Performance tests and benchmarks. Contribute to kubernetes/perf-tests development by creating an account on GitHub.

github.com

classloader2로 테스트한것 같아 동일하게 진행해보겠습니다.

 

먼저 perf-tests를 로컬에 다운 받아 줍니다.

git clone https://github.com/kubernetes/perf-tests.git

 

그런 뒤 다음의 폴더로 들어갑니다. 

cd perf-tests/clusterloader2/testing/list

 

테스트 설정 파일을 한번 확인해보겠습니다.

# List benchmark
{{$configMapBytes := DefaultParam .CL2_LIST_CONFIG_MAP_BYTES 100000}}
{{$configMapNumber := DefaultParam .CL2_LIST_CONFIG_MAP_NUMBER 10000}}
{{$configMapGroup := DefaultParam .CL2_LIST_CONFIG_MAP_GROUP "list-configmap"}}

{{$listReplicas := DefaultParam .CL2_LIST_BENCHMARK_PODS 1}}
{{$contentType := DefaultParam .CL2_LIST_BENCHMARK_CONTENT_TYPE "json"}}

name: list-benchmark
namespace:
  number: 1
tuningSets:
- name: Sequence # 튜닝셋 이름
  parallelismLimitedLoad:
    parallelismLimit: 10 # 최대 10개까지 병렬로 실행
steps:
- name: Setup namespace for list benchmark pods
  phases:
  - replicasPerNamespace: 1
    tuningSet: Sequence 
    objectBundle:
    - basename: list-benchmark
      objectTemplatePath: namespace.yaml
- name: Setup permissions
  phases:
  - replicasPerNamespace: 1
    tuningSet: Sequence
    objectBundle:
    - basename: list-clusterrole
      objectTemplatePath: clusterrole.yaml
  - replicasPerNamespace: 1
    tuningSet: Sequence
    objectBundle:
    - basename: list-clusterrolebinding
      objectTemplatePath: clusterrolebinding.yaml
  - namespaceRange:
      min: 1
      max: 1
    replicasPerNamespace: 1
    tuningSet: Sequence
    objectBundle:
    - basename: list-rolebinding
      objectTemplatePath: rolebinding.yaml

- name: Create configmaps
  phases:
  - namespaceRange:
      min: 1
      max: 1
    tuningSet: Sequence
    replicasPerNamespace: {{$configMapNumber}}
    objectBundle:
    - basename: {{$configMapGroup}}
      objectTemplatePath: configmap.yaml
      templateFillMap:
        bytes: {{$configMapBytes}}
        group: {{$configMapGroup}}

- module:
    path: modules/list-benchmark.yaml
    params:
      namePrefix: "list-configmaps-"
      replicas: {{$listReplicas}}
      uri: /api/v1/configmaps?resourceVersion=0
      namespaced: false
      contentType: {{$contentType}}
- module:
    path: /modules/measurements.yaml
    params:
      action: start
- name: Wait 5 minutes
  measurements:
    - Identifier: Wait
      Method: Sleep
      Params:
        duration: 5m
- module:
    path: /modules/measurements.yaml
    params:
      action: gather
- module:
    path: modules/list-benchmark.yaml
    params:
      namePrefix: "list-configmaps-"
      replicas: 0

 

정리를 해보면 위의 테스트로는 다음의 

  • 네임스페이스 / 권한 세팅
    • 테스트 용 namespace 1개 생성
    • ClusterRole, RoleBinding 등 권한 구성
  • ConfigMap 대량 생성
    • CL2_LIST_CONFIG_MAP_NUMBER 개수만큼 ConfigMap을 생성 (기본 10,000개)
    • 각 ConfigMap은 CL2_LIST_CONFIG_MAP_BYTES 바이트 크기의 데이터를 가짐 (기본 100KB)
  • List Benchmark Pod 실행
    • modules/list-benchmark.yaml 모듈을 실행해서 ConfigMap LIST 요청을 반복 실행하는 Deployment를 생성
    • /api/v1/configmaps?resourceVersion=0 엔드포인트를 대상으로 대량의 LIST 요청을 발생
    • 동시에 WaitForControlledPodsRunning measurement를 사용해 Deployment 파드가 정상 기동되는지 확인
    • 이 과정에서 Prometheus 기반 측정이 함께 수행되며
      • APIResponsivenessPrometheus → API 응답 지연 시간(p50, p90, p99) 수집
      • TestMetrics → 전체 테스트 실행 관련 메트릭(QPS, 요청 성공/실패 등) 수집
  • 측정 (measurements.yaml)
    • 위에서 진행한 측정을 5분 동안 대기 (부하 지속) 그 후 결과 수집
  • 벤치마크 종료
    • list-benchmark pod 삭제

 

테스트 시작

테스트를 시작해봅니다 먼저 1.32 클러스터에 테스트를 진행해봅니다. 

export CL2_ENABLE_CONTAINER_RESOURCES_MEASUREMENT=true
export CL2_PROMETHEUS_TOLERATE_MASTER=true
go run ../../cmd/clusterloader.go --provider kind -v=4 \
 --testconfig ./config.yaml \
 --kubeconfig $HOME/.kube/config \
 --enable-prometheus-server=true \
 --prometheus-scrape-kube-proxy=false \
 --prometheus-apiserver-scrape-port=6443 \
 --prometheus-scrape-master-kubelets \
 --report-dir=report/v1.32.8 # <-- 여기만 수정

 

실행이 되면 자동으로 prometheus와 grafana를 설치합니다. 

 

그리고 prometheus가 뜨기까지 기다리는데 그동안 다음과 같은 로그가 확인됩니다. 

 

그 이후엔 2개의 네임스페이스가 확인되는데 

 

테스트 네임스페이스(test-cpo2xs-1)에서 만개의 configmap이 생성된 것을 확인할 수 있습니다. 

 

 

이제 1.33 버전에서도 동일하게 테스트를 진행해봅니다.

export CL2_ENABLE_CONTAINER_RESOURCES_MEASUREMENT=true
export CL2_PROMETHEUS_TOLERATE_MASTER=true
go run ../../cmd/clusterloader.go --provider kind -v=4 \
 --testconfig ./config.yaml \
 --kubeconfig $HOME/.kube/config \
 --enable-prometheus-server=true \
 --prometheus-scrape-kube-proxy=false \
 --prometheus-apiserver-scrape-port=6443 \
 --prometheus-scrape-master-kubelets \
 --report-dir=report/v1.33.2 # <-- 여기만 수정

 

테스트 결과 확인하기

perfdash로 확인하기

perfdash로 확인을 해보려고합니다. perfdash는 테스트 결과를 s3혹은 gcs 버킷에 업로드를 해야하기 때문에 먼저 테스트 결과를 s3 버킷에 업로드합니다.

cd perf-tests/clusterloader2/testing/list/report
aws s3 cp . \
  s3://<bucket name>/cl2/list-benchmark/2/artifacts/ \
  --recursive

 

이제 perfdash를 실행시켜보겠습니다.  먼저 바이너리 파일을 생성합니다. 

cd perf-tests/perfdash
# perfdash 빌드
make perfdash

 

periodics:
- name: <job-name>
  tags:
  - "perfDashPrefix: <표시/그룹 이름>"
  - "perfDashJobType: <jobType>"
  - "perfDashBuildsCount: <정수>"          # 선택
  - "perfDashArtifactsDir: <서브디렉터리>" # 선택, 기본 'artifacts'

 

어떤 데이터를 볼것인지 위와 같이 정리를 해야합니다.

periodics:
- name: list-benchmark
  tags:
  - "perfDashPrefix: list-benchmark" # (필수) 패널에서 어떤 이름으로 묶어 보여줄지
  - "perfDashJobType: benchmarkList" # (필수) 어떤 메트릭 묶음(파서 세트)을 쓸지
  - "perfDashBuildsCount: 1" # 몇 개의 빌드(과거 런) 를 처리/표시할지
  - "perfDashArtifactsDir: artifacts" # 기본값 artifacts,각 빌드 폴더에서 아티팩트를 찾을 하위 디렉터리 이름

 

이제 실행시켜보겠습니다. 

./perfdash \
  --www \
  --mode=s3 \ # s3에 데이터가 있어서 
  --aws-region=ap-northeast-2 \
  --logsBucket=<bucket name> \
  --logsPath=cl2 \
  --builds=1  \ # 최근 1개 런만 (artifacts 의 개수)
  --configPath=test/jobs.yaml

 

테스트를 한번만 진행했기 때문에 결과가 1개밖에 보이지 않습니다. 

 

쿠버네티스 1.27, 28 ... 31,32 테스트 결과

사전에 1.27 버전이랑 1.33 이랑 비교를 하려고 했는데 1.27 버전은 로컬 PC에서 테스트를 진행하다보니 테스트를 제대로 마치지 못하고 끝내게 되어 제대로된 결과를 얻지 못했습니다. 동일하게 1.28, 1.31, 1.32 도 마찬가지였습니다 흑흑..

로컬 환경에서도 List 부하를 버틸수 있었다는거 자체가 1.33 버전이 많이 개선이 되었다고 할수 있을 것 같습니다.

기회가 되면 ec2에 생성해서 테스트해보겠습니다.