devlos
Devlos Archive
devlos
전체 방문자
오늘
어제
12-12 01:19

최근 글

  • 분류 전체보기 (107)
    • 프로젝트 (1)
    • MSA 설계 & 도메인주도 설계 (9)
    • 클라우드 컴퓨팅 & NoSQL (87)
      • [Cilium Study] 실리움 스터디 (8)
      • [KANS] 쿠버네티스 네트워크 심화 스터디 (12)
      • [T101] 테라폼 4기 스터디 (8)
      • [CICD] CICD 맛보기 스터디 (3)
      • [T101] 테라폼 기초 입문 스터디 (6)
      • [AEWS] Amazon EKS 워크숍 스터디 (7)
      • [PKOS] 쿠버네티스 실무 실습 스터디 (7)
      • Kubernetes (13)
      • Docker (7)
      • Redis (1)
      • Jenkins (3)
      • Terraform (1)
      • Ansible (4)
      • Kafka (1)
    • 프로그래밍 (7)
      • Spring Boot (5)
      • Broker (1)
    • 성능과 튜닝 (1)
    • ALM (0)
    • 기타 (2)

인기 글

태그

  • cilium
  • t101 4기
  • 도커
  • MSA
  • CloudNet@
  • PKOS
  • 쿠버네티스
  • docker
  • 데브옵스
  • Kubernetes
  • DevOps
  • 테라폼
  • kOps
  • terraform
  • 쿠버네티스 스터디

티스토리

최근 댓글

hELLO · Designed By 정상우.
devlos

Devlos Archive

[7주차 - Cilium 스터디] K8S/Cilium Performance (25.08.24)
클라우드 컴퓨팅 & NoSQL/[Cilium Study] 실리움 스터디

[7주차 - Cilium 스터디] K8S/Cilium Performance (25.08.24)

2025. 8. 30. 16:59
반응형

들어가며

안녕하세요! Devlos입니다.
이번 포스팅은 CloudNet@ 커뮤니티에서 주최하는 Cilium Study 7주 차 주제인 "K8S/Cilium Performance"에 대해서 정리한 내용입니다.

실습환경 구성

이번 주차 실습 환경은 mac M3 Pro max 환경에서 실습을 진행했고, VㅣKind를 사용해 구성했어요.
실습환경은 다음과 같습니다
버전

  • k8s(1.33.2)

실습환경 구성
이번주는 k8s와 cilium 이 적용된 k8s에서 퍼포먼스를 비교하는 실습을 진행했습니다.
Kind 를 이용한 k8s 구축

# Prometheus Target connection refused bind-address 설정 : kube-controller-manager , kube-scheduler , etcd , kube-proxy
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

# kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30003 --set env.TZ="Asia/Seoul" --namespace kube-system
open "http://localhost:30003/#scale=1.5"
open "http://localhost:30003/#scale=2"

# metrics-server
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

# 확인
kubectl top node
kubectl top pod -A --sort-by='cpu'
kubectl top pod -A --sort-by='memory'

Prometheus Stack 설치

# 파라미터 파일 생성
cat <<EOT > 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
EOT
cat monitor-values.yaml

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 배포
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 75.15.1 \
-f monitor-values.yaml --create-namespace --namespace monitoring

# 웹 접속 실행
open http://127.0.0.1:30001 # macOS prometheus 웹 접속
open http://127.0.0.1:30002 # macOS grafana 웹 접속 ( admin , prom-operator )

그라파나 대시보드

K8S new 15661
K8S API old 12006

K8S new 15661 대시보드입니다.
Kubernetes 클러스터의 전체적인 상태와 리소스 사용 현황을 한눈에 모니터링할 수 있도록 다양한 메트릭을 시각화해줍니다.
노드, 파드, 네임스페이스별 리소스 사용량(CPU, 메모리 등), 클러스터 이벤트, 워크로드 상태 등 주요 정보를 실시간으로 확인할 수 있어, 클러스터 운영 및 장애 대응에 매우 유용하게 활용할 수 있습니다.

K8S API old 12006 대시보드 입니다.
Kubernetes API 서버의 주요 메트릭(요청 수, 지연 시간, 에러율 등)을 시각화하여 클러스터의 API 서버 상태를 한눈에 파악할 수 있도록 도와줍니다.
운영 중인 클러스터의 API 서버 성능 및 장애 상황을 모니터링할 때 유용하게 활용할 수 있습니다.

kube-burner

Kube-burner는 Kubernetes 클러스터의 성능과 확장성을 테스트하기 위한 오케스트레이션 프레임워크입니다. 퍼포먼스 테스트를 진행하는 용도입니다! Go 언어로 작성되었으며, 현재 버전은 v1.17.3입니다.

주요 특징

  1. 대규모 리소스 관리
    • Kubernetes 리소스의 생성, 삭제, 읽기, 패치 작업을 대규모로 수행
    • 클러스터의 한계를 테스트하고 성능 병목 지점을 발견
  2. 모니터링 및 메트릭 수집
    • Prometheus 메트릭 수집 및 인덱싱
    • 실시간 성능 측정 및 분석
  3. 측정 및 알림
    • 다양한 성능 지표 측정
    • 임계값 기반 알림 시스템
  4. 기술적 구현
    • Go 언어로 작성된 바이너리 애플리케이션
    • Kubernetes 공식 클라이언트 라이브러리인 client-go를 광범위하게 활용

활용 사례

  • 클러스터 성능 테스트: 대량의 Pod, Service, ConfigMap 등을 생성하여 클러스터의 처리 능력 측정
  • 확장성 검증: 클러스터가 얼마나 많은 워크로드를 처리할 수 있는지 확인
  • 성능 병목 분석: 어떤 구성 요소가 성능 저하의 원인이 되는지 파악
  • 부하 테스트: 실제 운영 환경과 유사한 부하 상황을 시뮬레이션

관련 링크

  • GitHub: https://github.com/kube-burner/kube-burner
  • 공식 문서: https://kube-burner.github.io/kube-burner/v1.17.1/
  • 예제 코드: https://github.com/kube-burner/kube-burner/tree/main/examples

kube-burner 사용 실습

설치

# 다운로드
git clone https://github.com/kube-burner/kube-burner.git
cd kube-burner

# 바이너리 설치(추천) : mac M1
curl -LO https://github.com/kube-burner/kube-burner/releases/download/v1.17.3/kube-burner-V1.17.3-darwin-arm64.tar.gz # mac M
tar -xvf kube-burner-V1.17.3-darwin-arm64.tar.gz

curl -LO https://github.com/kube-burner/kube-burner/releases/download/v1.17.3/kube-burner-V1.17.3-linux-x86_64.tar.gz # Windows
tar -xvf kube-burner-V1.17.3-linux-x86_64.tar.gz

sudo cp kube-burner /usr/local/bin

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

# 버전 확인 : 혹은 go run cmd/kube-burner/kube-burner.go -h
kube-burner version
Version: 1.17.3

시나리오 1 : 디플로이먼트 1개 (파드 1개) 생성 → 삭제 ( jobIterations qps burst 의미 확인)

#
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

# job 에 선언한 내용이 주입됨
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: 10
  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-ops-view
watch -d kubectl get ns,pod -A


# 부하 발생 실행 Launch benchmark
kube-burner init -h
kube-burner init -c s1-config.yaml --log-level debug
...

#
kubectl get deploy -A -l kube-burner-job=delete-me
kubectl get pod -A -l kube-burner-job=delete-me
kubectl get ns -l kube-burner-job=delete-me

#
ls kube-burner-*.log
kube-burner-86508d5e-52dc-45de-88ab-d933f48ae0c8.log
cat kube-burner-*.log


# 삭제!
## deployment 는 s1-deployment.yaml 에 metadata.labels 에 추가한 labels 로 지정
## namespace 는 config.yaml 에 job.name 값을 labels 로 지정
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
Every 2.0s: kubectl get ns,pod -A                                                                                                        devlos-mac.local: Sat Aug 30 12:20:48 2025

NAME                            STATUS   AGE
namespace/default               Active   44m
namespace/kube-node-lease       Active   44m
namespace/kube-public           Active   44m
namespace/kube-system           Active   44m
namespace/local-path-storage    Active   44m
namespace/monitoring            Active   43m
namespace/preload-kube-burner   Active   16s

실행 로그

❯ kube-burner init -c s1-config.yaml --log-level debug
time="2025-08-30 12:20:32" level=info msg="🔥 Starting kube-burner (1.17.3@917540ff45a89386bb25de45af9b96c9fc360e93) with UUID f604ea46-b733-495a-9ac2-00d1b897206e" file="job.go:91"
time="2025-08-30 12:20:32" level=warning msg="Measurement [none] is not supported" file="factory.go:101"
time="2025-08-30 12:20:32" level=debug msg="job.MaxWaitTimeout is zero in create-deployments, override by timeout: 4h0m0s" file="job.go:361"
time="2025-08-30 12:20:32" level=info msg="QPS: 1" file="job.go:371"
time="2025-08-30 12:20:32" level=info msg="Burst: 1" file="job.go:378"
time="2025-08-30 12:20:32" level=debug msg="Preparing create job: create-deployments" file="create.go:46"
time="2025-08-30 12:20:32" level=debug msg="Rendering template: s1-deployment.yaml" file="create.go:52"
time="2025-08-30 12:20:32" level=info msg="Job create-deployments: 1 iterations with 10 Deployment replicas" file="create.go:84"
time="2025-08-30 12:20:32" level=info msg="Pre-load: images from job create-deployments" file="pre_load.go:73"
time="2025-08-30 12:20:32" level=debug msg="Created namespace: preload-kube-burner" file="namespaces.go:55"
time="2025-08-30 12:20:32" level=info msg="Pre-load: Creating DaemonSet using images [nginx:alpine] in namespace preload-kube-burner" file="pre_load.go:195"
time="2025-08-30 12:20:32" level=info msg="Pre-load: Sleeping for 30s" file="pre_load.go:86"
time="2025-08-30 12:21:02" level=info msg="Deleting 1 namespaces with label: kube-burner-preload=true" file="namespaces.go:67"
time="2025-08-30 12:21:02" level=debug msg="Waiting for 1 namespaces labeled with kube-burner-preload=true to be deleted" file="namespaces.go:90"
...
time="2025-08-30 12:21:07" level=debug msg="Waiting for 1 namespaces labeled with kube-burner-preload=true to be deleted" file="namespaces.go:90"
time="2025-08-30 12:21:08" level=info msg="Triggering job: create-deployments" file="job.go:122"
time="2025-08-30 12:21:08" level=info msg="0/1 iterations completed" file="create.go:119"
time="2025-08-30 12:21:08" level=debug msg="Creating object replicas from iteration 0" file="create.go:122"
time="2025-08-30 12:21:09" level=debug msg="Created namespace: kube-burner-test-0" file="namespaces.go:55"
time="2025-08-30 12:21:09" level=debug msg="Created Deployment/deployment-0-3 in namespace kube-burner-test-0" file="create.go:288"
...
time="2025-08-30 12:21:18" level=debug msg="Created Deployment/deployment-0-5 in namespace kube-burner-test-0" file="create.go:288"
time="2025-08-30 12:21:18" level=info msg="Waiting up to 4h0m0s for actions to be completed" file="create.go:169"
time="2025-08-30 12:21:19" level=debug msg="Waiting for replicas from Deployment in ns kube-burner-test-0 to be ready" file="waiters.go:152"
time="2025-08-30 12:21:20" level=info msg="Actions in namespace kube-burner-test-0 completed" file="waiters.go:74"
time="2025-08-30 12:21:20" level=info msg="Job create-deployments took 12s" file="job.go:191"
time="2025-08-30 12:21:20" level=info msg="Finished execution with UUID: f604ea46-b733-495a-9ac2-00d1b897206e" file="job.go:264"
time="2025-08-30 12:21:20" level=info msg="👋 Exiting kube-burner f604ea46-b733-495a-9ac2-00d1b897206e" file="kube-burner.go:90"

실행 로그 분석

  1. kube-burner 시작
    • 🔥 Starting kube-burner ... with UUID ...
      → kube-burner가 실행되며, 고유 UUID가 할당됩니다.
    • Measurement [none] is not supported
      → 측정 항목으로 'none'이 지정되어 있지만, 지원되지 않는다는 경고입니다.
  2. Job 파라미터 확인
    • job.MaxWaitTimeout is zero ... override by timeout: 4h0m0s
      → 대기 타임아웃이 0으로 설정되어 있어 기본값(4시간)으로 오버라이드됩니다.
    • QPS: 1, Burst: 1
      → 초당 요청 수(QPS)와 버스트 값이 1로 설정되어 있습니다.
  3. Job 준비 및 프리로드
    • Preparing create job: create-deployments
      → 'create-deployments'라는 작업을 준비합니다.
    • Rendering template: s1-deployment.yaml
      → 배포에 사용할 템플릿 파일을 렌더링합니다.
    • Job create-deployments: 1 iterations with 10 Deployment replicas
      → 1회 반복(iteration) 동안 10개의 Deployment를 생성할 예정입니다.
    • Pre-load: images from job create-deployments
      → 프리로드 단계에서 필요한 이미지를 미리 준비합니다.
    • Created namespace: preload-kube-burner
      → 프리로드용 네임스페이스를 생성합니다.
    • Pre-load: Creating DaemonSet using images [nginx:alpine] ...
      → preload-kube-burner 네임스페이스에 DaemonSet을 생성하여 이미지를 풀링합니다.
    • Pre-load: Sleeping for 30s
      → 프리로드 후 30초간 대기(캐시 워밍업 등).
  4. 프리로드 네임스페이스 삭제 대기
    • Deleting 1 namespaces with label: kube-burner-preload=true
      → 프리로드 작업이 끝난 네임스페이스를 삭제합니다.
    • Waiting for 1 namespaces labeled with kube-burner-preload=true to be deleted
      → 네임스페이스가 실제로 삭제될 때까지 반복적으로 대기합니다.
  5. 본 작업(Deployment 생성) 시작
    • Triggering job: create-deployments
      → 본격적으로 Deployment 생성 작업을 시작합니다.
    • 0/1 iterations completed
      → 1회 반복 중 0회 완료(즉, 이제 시작).
    • Creating object replicas from iteration 0
      → 첫 번째 반복에서 오브젝트(Deployment) 생성 시작.
  6. Deployment 및 네임스페이스 생성
    • Created namespace: kube-burner-test-0
      → 테스트용 네임스페이스 생성.
    • Created Deployment/deployment-0-X in namespace kube-burner-test-0
      → 10개의 Deployment가 순차적으로 생성됨.
  7. 생성 완료 및 대기
    • Waiting up to 4h0m0s for actions to be completed
      → 모든 작업이 완료될 때까지 최대 4시간 대기.
    • Waiting for replicas from Deployment in ns kube-burner-test-0 to be ready
      → Deployment의 파드가 준비될 때까지 대기.
  8. 작업 완료
    • Actions in namespace kube-burner-test-0 completed
      → 해당 네임스페이스 내 작업이 모두 완료됨.
    • Job create-deployments took 12s
      → 전체 작업 소요 시간: 12초.
    • Finished execution with UUID: ...
      → 실행 종료.
    • 👋 Exiting kube-burner ...
      → kube-burner 프로세스 종료.

preload-kube-burner Pod가 먼저 실행되어 클러스터에 필요한 리소스(예: 네임스페이스, ConfigMap 등)를 미리 생성합니다.
이 과정을 통해 실제 부하테스트에 앞서 환경이 준비되고, 캐시 워밍업 등 초기화 작업이 완료됩니다.
이후 본격적으로 kube-burner를 이용한 공식적인 부하테스트가 시작되어, 클러스터의 성능 지표가 측정됩니다.

kube-burner의 주요 변수와 각 변수의 의미는 다음과 같습니다.

변수명 위치/예시 의미 및 설명
preLoadImages s1-config.yaml (global, jobs) 파드 생성 전 컨테이너 이미지를 미리 풀링할지 여부 true: 미리 이미지 풀링(캐시 워밍업), false: 풀링하지 않음
waitWhenFinished s1-config.yaml (jobs) 작업 완료 후 리소스가 준비될 때까지 대기할지 여부 true: 완료까지 대기, false: 바로 종료
jobIterations s1-config.yaml (jobs) 해당 job을 몇 번 반복 실행할지 지정 예: 5면 5번 반복 실행
objects.replicas s1-deployment.yaml (spec) 각 Deployment가 생성할 파드(Replica) 수 예: 2면 Deployment마다 2개 파드 생성
qps s1-config.yaml (jobs) 초당 생성 요청(Query Per Second) 제한 예: 10이면 초당 최대 10개 오브젝트 생성 요청
burst s1-config.yaml (jobs) 순간적으로 처리 가능한 최대 요청 수(버스트) 예: 20이면 한 번에 최대 20개까지 요청 가능

qps와 burst는 오브젝트 생성 요청의 속도와 순간 처리량을 제어하는 변수로, 함께 동작합니다.

  • qps(Queries Per Second)는 초당 평균적으로 처리할 수 있는 최대 요청 수를 의미합니다. 예를 들어 qps가 10이면, kube-burner는 초당 10개의 오브젝트 생성 요청을 보내도록 속도를 조절합니다.
  • burst는 순간적으로 처리할 수 있는 최대 요청 수(버퍼 역할)를 의미합니다. qps 제한에 걸리지 않는 짧은 순간 동안 burst 값만큼 요청을 한 번에 보낼 수 있습니다.

즉, kube-burner는 burst 값까지는 빠르게 요청을 보낼 수 있지만, 그 이후에는 qps에 맞춰 속도를 조절하며 요청을 보냅니다. burst는 "최대치(버퍼)", qps는 "지속적인 속도"로 이해하면 됩니다.
예를 들어, qps=10, burst=20이면 처음에는 최대 20개까지 빠르게 요청을 보내고, 이후에는 초당 10개씩 요청을 보냅니다.

시나리오 2: 노드 1대에 최대 파드(150개) 배포 시도 1

  • *kube-burner init -c s1-config.yaml --log-level debug*
  • jobIterations: **100**, qps: 300, burst: 300 objects.replicas: 1 변경 후 실행 → 모든 파드가 배포 되는지 확인

pod 상태 확인

❯ kubectl get pod -A | grep -v '1/1     Running'
NAMESPACE             NAME                                                        READY   STATUS    RESTARTS   AGE
kube-burner-test-94   deployment-94-1-8975b9f89-x7tpj                             0/1     Pending   0          66s
kube-burner-test-95   deployment-95-1-665fdd589f-jdddz                            0/1     Pending   0          66s
kube-burner-test-96   deployment-96-1-8cb6966fc-4sx8f                             0/1     Pending   0          65s
kube-burner-test-97   deployment-97-1-d47c6b84c-vsms7                             0/1     Pending   0          65s
kube-burner-test-98   deployment-98-1-5675c67bfc-xfvsn                            0/1     Pending   0          65s
kube-burner-test-99   deployment-99-1-6987649687-p974t                            0/1     Pending   0          65s
monitoring            kube-prometheus-stack-grafana-7d9c86798d-ct4pn              3/3     Running   0          76m
monitoring            prometheus-kube-prometheus-stack-prometheus-0               2/2     Running   0          76m

❯ kubectl describe pod -n kube-burner-test-99 | grep Events: -A5
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  94s   default-scheduler  0/1 nodes are available: 1 Too many pods. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod.

# 원인 확인
❯ kubectl describe node | grep pods: -B10
  InternalIP:  172.18.0.2
  Hostname:    myk8s-control-plane
Capacity:
  cpu:                8
  ephemeral-storage:  61202244Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  hugepages-32Mi:     0
  hugepages-64Ki:     0
  memory:             16356276Ki
  pods:               110
Allocatable:
  cpu:                8
  ephemeral-storage:  61202244Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  hugepages-32Mi:     0
  hugepages-64Ki:     0
  memory:             16356276Ki
  pods:               110

현재 발생한 문제는 노드의 파드 수 제한(pods capacity)으로 인해 더 이상 파드를 스케줄할 수 없다는 점입니다.
kubectl describe node 명령어 결과에서 볼 수 있듯이, 해당 노드의 pods 용량(capacity)과 할당 가능(allocatable) 파드 수가 110개로 제한되어 있습니다.
따라서 100개의 디플로이먼트(각 1개 파드)와 기타 시스템 파드가 함께 존재할 때, 노드의 파드 최대치에 도달하여 추가 파드는 Pending 상태가 됩니다.
이러한 파드 제한은 kubelet의 기본 설정에 의해 결정되며, 필요하다면 kubelet 파라미터(예: --max-pods)를 조정하여 노드당 파드 수를 늘릴 수 있습니다.
배포 문제 해결

# maxPods 항목 없으면 기본값 110개
kubectl get cm -n kube-system kubelet-config -o yaml

#
docker exec -it myk8s-control-plane bash
----------------------------------------
cat /var/lib/kubelet/config.yaml

apt update && apt install vim -y
vim /var/lib/kubelet/config.yaml
maxPods: 150

systemctl restart kubelet
systemctl status kubelet
exit
----------------------------------------

#
❯ kubectl describe node | grep pods -B10
  InternalIP:  172.18.0.2
  Hostname:    myk8s-control-plane
Capacity:
  cpu:                8
  ephemeral-storage:  61202244Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  hugepages-32Mi:     0
  hugepages-64Ki:     0
  memory:             16356276Ki
  pods:               150
Allocatable:
  cpu:                8
  ephemeral-storage:  61202244Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  hugepages-32Mi:     0
  hugepages-64Ki:     0
  memory:             16356276Ki
  pods:               150

kubelet의 maxPods 값을 150으로 설정함으로써, 한 노드에서 스케줄할 수 있는 파드의 최대 개수를 늘릴 수 있었습니다.
이를 통해 100개의 디플로이먼트와 시스템 파드가 함께 존재하더라도 추가 파드가 Pending 상태에 머무르지 않고 정상적으로 배포될 수 있습니다.

시나리오 3: 노드 1대에 최대 파드(300개) 배포 시도 1

#
kubectl get pod -A | grep -v '1/1     Running'
...

# maxPods: 400 상향
docker exec -it myk8s-control-plane bash
----------------------------------------
cat /var/lib/kubelet/config.yaml

apt update && apt install vim -y
vim /var/lib/kubelet/config.yaml
maxPods: 400

systemctl restart kubelet
systemctl status kubelet
exit
----------------------------------------

# 
❯ kubectl describe pod -n kube-burner-test-250 | grep Events: -A5

Events:
  Type     Reason                  Age   From               Message
  ----     ------                  ----  ----               -------
  Normal   Scheduled               10s   default-scheduler  Successfully assigned kube-burner-test-250/deployment-250-1-76bbc7c4b8-swqxv to myk8s-control-plane
  Warning  FailedCreatePodSandBox  9s    kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "dcf07f1d4433c22ae02f62bb8aba4b1e5aaa92b067689fb885a63468b389c051": plugin type="ptp" failed (add): failed to allocate for range 0: no IP addresses available in range set: 10.244.0.1-10.244.0.254

❯ kubectl describe pod -n kube-burner-test-299 | grep Events: -A5
Events:
  Type     Reason                  Age   From               Message
  ----     ------                  ----  ----               -------
  Normal   Scheduled               20s   default-scheduler  Successfully assigned kube-burner-test-299/deployment-299-1-65489c698d-2mrdt to myk8s-control-plane
  Warning  FailedCreatePodSandBox  20s   kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "a05d582cf7c06b4217b777e30ef7621bd91c7da140786698041774cc10cafe21": plugin type="ptp" failed (add): failed to allocate for range 0: no IP addresses available in range set: 10.244.0.1-10.244.0.254
  Warning  FailedCreatePodSandBox  9s    kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "a9fe4b40056ed2916fcf8d82c021bcca5e9df6a02475bd711cecfe43bd367551": plugin type="ptp" failed (add): failed to allocate for range 0: no IP addresses available in range set: 10.244.0.1-10.244.0.254
...

#
❯ kubectl describe node myk8s-control-plane | grep -i podcidr
PodCIDR:                      10.244.0.0/24
PodCIDRs:                     10.244.0.0/24

배포가 되지 않는 원인은 노드의 maxPods 값을 충분히 높였음에도 불구하고, Pod에 할당할 수 있는 IP 주소의 개수가 제한되어 있기 때문입니다.
위에서 확인한 것처럼, 해당 노드의 PodCIDR이 10.244.0.0/24로 설정되어 있어 할당 가능한 IP가 최대 254개(10.244.0.1~10.244.0.254)로 제한됩니다.
따라서 254개 이상의 파드를 생성하려고 하면, 추가 파드들은 IP를 할당받지 못해 Pending 상태가 되거나, "no IP addresses available in range set"과 같은 에러가 발생하게 됩니다.
즉, 파드가 정상적으로 배포되기 위해서는 maxPods 값뿐만 아니라, PodCIDR 범위도 충분히 넓게 설정해야 합니다.

k8s Performance & Tuning

Kubernetes 대규모 클러스터 권장 한계 (v1.33 기준)
단일 클러스터에서 권장하는 최대 규모는 다음과 같습니다.

  • 노드 수: 5,000대 이하
  • 노드당 파드 수: 110개 이하
  • 총 파드 수: 150,000개 이하
  • 총 컨테이너 수: 300,000개

Pod가 많아질 때 발생하는 Control Plane 장애 예시

다읍 챕터는 해당 블로그 내용을 참고하여 작성했습니다. - https://iwanhae.tistory.com/m/2
문제상황

  • 여러 클라이언트(예: 모니터링 도구, 컨트롤러 등)가 동시에 API 서버에 대량의 파드 목록을 요청합니다.
  • API 서버는 etcd에 전체 파드 데이터를 요청하고, etcd는 모든 파드 정보를 메모리로 복사해 응답합니다.
  • 이 과정에서 API 서버와 etcd의 메모리 사용량이 급격히 증가하며, 동시 요청이 많을수록 메모리 부족(OOM)이나 성능 저하가 발생합니다.

kube-apiserver의 역할

  • 정의: Kubernetes 클러스터의 모든 API 요청을 처리하는 중앙 집중식 API 서버
  • 통신 방식: HTTP(S) 프로토콜을 통한 RESTful API 제공
  • 지원 형식: JSON, YAML, Protobuf 등 다양한 데이터 형식 지원
  • 클라이언트: kubectl, kubelet, kube-controller-manager, kube-scheduler 등 모든 Kubernetes 컴포넌트
  • 인증/인가: TLS 인증서, RBAC, Webhook 등을 통한 보안 처리

etcd의 역할

  • 정의: 분산 키-값 저장소로 Kubernetes의 모든 상태 정보 저장
  • 프로토콜: RAFT 합의 알고리즘을 사용한 CP(Consistency & Partition Tolerance) 시스템
  • 데이터 구조: 계층적 키 구조 (/registry/pods/default/pod-name)
  • 복제: Leader-Follower 모델로 데이터 복제 및 고가용성 보장
  • 트랜잭션: ACID 특성을 보장하는 트랜잭션 처리

장단점 분석

  • 장점:
    • 데이터 일관성 보장 (RAFT 합의)
    • 자동 장애 복구
    • 데이터 손실 방지
  • 단점:
    • 대용량 데이터 처리 시 성능 저하
    • 메모리 사용량이 데이터 크기에 비례
    • 복잡한 쿼리 처리 제한

Background: 파드 수에 따른 응답 시간과 크기 변화는 다음과 같습니다.
성능 측정 결과

# 100개 Pod 조회
curl -o /dev/null -s -w 'Total: %{time_total}s\n' 127.0.0.1:8001/api/v1/pods?limit=100
# 결과: Total: 0.031002s (31ms), 크기: 0.45MB

# 10,000개 Pod 조회  
curl -o /dev/null -s -w 'Total: %{time_total}s\n' 127.0.0.1:8001/api/v1/pods?limit=10000
# 결과: Total: 2.131027s (2,131ms), 크기: 44.4MB

 
성능 분석

  • 응답 시간: Pod 1개당 약 0.21ms의 처리 지연 발생
  • 데이터 크기: Pod 1개당 약 4.4KB의 JSON 데이터
  • 선형적 증가: 리소스 수에 비례하여 성능이 선형적으로 저하
  • 네트워크 대역폭: 대용량 조회 시 네트워크 대역폭도 고려 필요

Problem: 메모리 사용량 급증입니다.
etcd 메모리 사용량 분석

# etcd 메모리 사용량 모니터링
pidstat --human -r -p 7 1

# 안정 상태: 171.5M
# 첫 번째 요청: 236.7M (+65.2M)
# 두 번째 요청: 265.0M (+28.3M)
# 세 번째 요청: 265.3M (+0.3M)
# GC 실행 후: 187.1M (-78.2M)

kube-apiserver 메모리 사용량 분석

# kube-apiserver 메모리 사용량 모니터링
pidstat --human -r -p 7 1

# 안정 상태: 691.4M
# 첫 번째 요청: 815.9M (+124.5M)
# 두 번째 요청: 944.0M (+128.1M)
# 세 번째 요청: 1010.8M (+66.8M)
# 네 번째 요청: 1.1G (+100M)

 
메모리 사용량 패턴

  • etcd: 요청당 30~60MB 메모리 증가, GC 후 회복
  • kube-apiserver: 요청당 100MB 내외 메모리 증가, 누적 경향
  • 메모리 누적: 동시 요청 시 메모리가 해제되지 않고 누적
  • OOM 위험: 100개 동시 요청 시 6GB 메모리 사용 가능

문제 발생 원인은 다음과 같습니다.
 
etcd Transaction 메커니즘

// etcd Range 요청 처리 과정
func (s *store) Range(ctx context.Context, key, end []byte, ro RangeOptions) (*RangeResponse, error) {
    // 1. Lock 획득
    s.mu.RLock()
    defer s.mu.RUnlock()

    // 2. 데이터 복제 (메모리 사용량 증가)
    data := make([]byte, len(originalData))
    copy(data, originalData)

    // 3. 응답 반환
    return &RangeResponse{Data: data}, nil
}

 
대량 리소스 누적 사례

  • Airflow: 완료된 DAG 실행 Pod들이 자동 삭제되지 않음
  • Kubeflow: ML 파이프라인 실행 후 Pod 정리 실패
  • CronJob: 실패한 Job의 Pod들이 누적
  • Deployment: 롤백 과정에서 이전 ReplicaSet Pod들 남김

문제 발생 조건
조건 1: 대량 리소스 존재

  • 정의: 한 번에 조회 가능한 리소스 개수가 매우 많음
  • 임계값: 일반적으로 1,000개 이상의 Pod
  • 원인:
    • 자동 정리 정책 부재
    • 애플리케이션 설정 오류
    • 운영자 관리 소홀

조건 2: 동시 요청 증가

  • 정의: 해당 리소스를 조회하는 요청이 매우 많음
  • 시나리오:
    • 네트워크 분단으로 인한 재연결
    • 컨트롤러 재시작
    • 모니터링 도구의 대량 조회

노드 수에 비례하는 컨트롤러들

  • kubelet: 각 노드마다 1개씩, Pod 상태 동기화
  • kube-proxy: 각 노드마다 1개씩, 서비스 엔드포인트 동기화
  • CNI agents: Cilium, Calico 등 네트워크 정책 동기화
  • 문제: 노드가 많을수록 동시 요청 수 증가

해결법: API 관점

Limit/Continue 활용

페이징 처리 원리

# 첫 번째 요청
GET /api/v1/pods?limit=500

# 응답에 continue 토큰 포함
{
  "items": [...],
  "metadata": {
    "continue": "eyJ2IjoibWV0YS5rOHMuaW8vdjEiLCJydiI6MzkzNDcsInN0YXJ0IjoidGVzdC01NzQ2ZDRjNTlmLTJuNTUyXHUwMDAwIn0"
  }
}

# 다음 요청
GET /api/v1/pods?limit=500&continue=eyJ2IjoibWV0YS5rOHMuaW8vdjEiLCJydiI6MzkzNDcsInN0YXJ0IjoidGVzdC01NzQ2ZDRjNTlmLTJuNTUyXHUwMDAwIn0

kubectl 실제 사용 예시

kubectl get po -v6
# GET https://127.0.0.1:6443/api/v1/namespaces/default/pods?limit=500
# GET https://127.0.0.1:6443/api/v1/namespaces/default/pods?continue=...&limit=500
# GET https://127.0.0.1:6443/api/v1/namespaces/default/pods?continue=...&limit=500

장점

  • 메모리 사용량을 500개 단위로 제한
  • 대부분의 Kubernetes 클라이언트에서 기본 적용
  • 구현이 간단하고 안정적
ResourceVersion/ResourceVersionMatch 활용

캐시 활용 전략

# Strong Consistency (기본)
GET /api/v1/pods?resourceVersion=12345

# Weak Consistency (캐시 활용)
GET /api/v1/pods?resourceVersion=0

메모리 사용량 비교

# etcd 직접 조회 (Strong Consistency)
# 메모리 사용량: 60MB 증가

# kube-apiserver 캐시 활용 (Weak Consistency)  
# 메모리 사용량: 거의 증가 없음
# etcd 부하: 거의 없음

적용 사례

  • 모니터링 도구: 실시간 정확성보다는 성능이 중요한 경우
  • 배치 작업: 대량 데이터 조회가 필요한 경우
  • 개발/테스트: 빠른 반복 작업이 필요한 경우
API Priority and Fairness (APF)

FlowSchema 정의

apiVersion: flowcontrol.apiserver.k8s.io/v1beta3
kind: FlowSchema
metadata:
  name: cilium-pods
spec:
  distinguisherMethod:
    type: ByUser
  matchingPrecedence: 1000
  priorityLevelConfiguration:
    name: cilium-pods
  rules:
    - resourceRules:
        - apiGroups: ["cilium.io"]
          clusterScope: true
          namespaces: ["*"]
          resources: ["*"]
          verbs: ["list"]
      subjects:
        - group:
            name: system:serviceaccounts:d8-cni-cilium
          kind: Group

PriorityLevelConfiguration 정의

apiVersion: flowcontrol.apiserver.k8s.io/v1beta3
kind: PriorityLevelConfiguration
metadata:
  name: cilium-pods
spec:
  type: Limited
  limited:
    nominalConcurrencyShares: 5
    limitResponse:
      queuing:
        handSize: 4
        queueLengthLimit: 50
        queues: 16
      type: Queue

APF 장점

  • 요청 격리: 문제가 되는 요청만 제한
  • 유연한 제어: 우선순위별 처리 가능
  • 안정성 보장: 전체 API 서버 보호

시나리오 4 - : api-intensive - 파드를 생성(configmap, secret) 후 삭제

이 실습은 kube-apiserver에 부하를 주기 위해 파드(Pod)를 생성하면서 ConfigMap과 Secret을 마운트하고, 이후 이 리소스들을 삭제하는 과정을 포함합니다. 실습에서는 반복 횟수(jobIterations), 초당 요청 수(QPS), 버스트(burst) 값 등을 클러스터의 규모에 맞게 조정하여 다양한 부하 상황을 테스트할 수 있습니다. 이를 통해 대량의 리소스 생성 및 삭제 시 클러스터의 동작과 한계를 직접 확인할 수 있습니다.

#
tree examples/workloads/api-intensive   # api-intensive workload 디렉토리 구조 확인
examples/workloads/api-intensive
├── api-intensive.yml
└── templates
    ├── configmap.yaml
    ├── deployment_patch_add_label.json
    ├── deployment_patch_add_label.yaml
    ├── deployment_patch_add_pod_2.yaml
    ├── deployment.yaml
    ├── secret.yaml
    └── service.yaml

cd examples/workloads/api-intensive     # api-intensive 디렉토리로 이동

#
cat << EOF > api-intensive-100.yml     # 100회 반복용 workload yaml 생성
jobs:
  - name: api-intensive                # 파드/ConfigMap/Secret/Service 생성 job
    jobIterations: 100                 # 100번 반복
    qps: 100                           # 초당 100개 요청
    burst: 100                         # burst 100
    namespacedIterations: true         # 반복마다 네임스페이스 분리
    namespace: api-intensive           # 네임스페이스 이름
    podWait: false                     # 파드 준비 완료 대기 안함
    cleanup: true                      # 작업 후 리소스 정리
    waitWhenFinished: true             # 작업 완료까지 대기
    preLoadImages: false # true        # 이미지 미리 풀 할지 여부
    objects:
      - objectTemplate: templates/deployment.yaml   # deployment 템플릿
        replicas: 1
      - objectTemplate: templates/configmap.yaml    # configmap 템플릿
        replicas: 1
      - objectTemplate: templates/secret.yaml       # secret 템플릿
        replicas: 1
      - objectTemplate: templates/service.yaml      # service 템플릿
        replicas: 1

  - name: api-intensive-patch           # deployment patch 작업
    jobType: patch
    jobIterations: 10                   # 10회 반복
    qps: 100
    burst: 100
    objects:
      - kind: Deployment
        objectTemplate: templates/deployment_patch_add_label.json   # json patch
        labelSelector: {kube-burner-job: api-intensive}
        patchType: "application/json-patch+json"
        apiVersion: apps/v1
      - kind: Deployment
        objectTemplate: templates/deployment_patch_add_pod_2.yaml   # yaml patch
        labelSelector: {kube-burner-job: api-intensive}
        patchType: "application/apply-patch+yaml"
        apiVersion: apps/v1
      - kind: Deployment
        objectTemplate: templates/deployment_patch_add_label.yaml   # strategic merge patch
        labelSelector: {kube-burner-job: api-intensive}
        patchType: "application/strategic-merge-patch+json"
        apiVersion: apps/v1

  - name: api-intensive-remove          # deployment 삭제 job
    qps: 500
    burst: 500
    jobType: delete
    waitForDeletion: true               # 삭제 완료까지 대기
    objects:
      - kind: Deployment
        labelSelector: {kube-burner-job: api-intensive}
        apiVersion: apps/v1

  - name: ensure-pods-removal           # pod 삭제 job
    qps: 100
    burst: 100
    jobType: delete
    waitForDeletion: true
    objects:
      - kind: Pod
        labelSelector: {kube-burner-job: api-intensive}

  - name: remove-services               # service 삭제 job
    qps: 100
    burst: 100
    jobType: delete
    waitForDeletion: true
    objects:
      - kind: Service
        labelSelector: {kube-burner-job: api-intensive}

  - name: remove-configmaps-secrets     # configmap/secret 삭제 job
    qps: 100
    burst: 100
    jobType: delete
    objects:
      - kind: ConfigMap
        labelSelector: {kube-burner-job: api-intensive}
      - kind: Secret
        labelSelector: {kube-burner-job: api-intensive}

  - name: remove-namespace              # 네임스페이스 삭제 job
    qps: 100
    burst: 100
    jobType: delete
    waitForDeletion: true
    objects:
      - kind: Namespace
        labelSelector: {kube-burner-job: api-intensive}
EOF

# 수행
kube-burner init -c api-intensive-100.yml --log-level debug   # 100 workload 실행

위의 kube-burner init -c api-intensive-100.yml --log-level debug 명령을 실행하면, 다음과 같은 결과가 나타납니다.

  1. 리소스 생성
    • 지정된 workload(api-intensive-100.yml)에 따라 100개의 Deployment, ConfigMap, Secret, Service 오브젝트가 순차적으로 생성됩니다.
    • 각 오브젝트는 api-intensive 네임스페이스에 생성되며, qps: 100, burst: 100 설정에 따라 초당 최대 100개의 요청 속도로 처리됩니다.
  2. Patch 작업
    • 생성된 Deployment 오브젝트에 대해 3가지 patch 작업이 10회 반복 적용됩니다.
    • 각각의 patch는 Deployment에 라벨 추가, 파드 replica 수 변경 등 다양한 변화를 줍니다.
  3. 리소스 삭제
    • 생성된 Deployment, Pod, Service, ConfigMap, Secret, Namespace 오브젝트가 순차적으로 삭제됩니다.
    • 삭제 작업 역시 qps: 100, burst: 100 설정에 따라 빠르게 진행되며, waitForDeletion: true 옵션으로 실제 리소스가 완전히 삭제될 때까지 대기합니다.
cat << EOF > api-intensive-500.yml     # 500 QPS 실험을 위한 workload yaml 생성
jobs:
  # 1. 오브젝트 생성 작업
  - name: api-intensive
    jobIterations: 100                 # 100번 반복 (총 100개의 네임스페이스/오브젝트 생성)
    qps: 500                           # 초당 최대 500개 요청으로 생성
    burst: 500                         # 순간 최대 500개까지 버스트 처리
    namespacedIterations: true         # 각 반복마다 별도 네임스페이스 사용
    namespace: api-intensive           # 네임스페이스 이름 prefix
    podWait: false                     # 파드 준비 완료 대기하지 않음
    cleanup: true                      # 작업 종료 후 자동 정리
    waitWhenFinished: true             # 모든 오브젝트 생성 완료까지 대기
    preLoadImages: false               # 이미지 미리 로드하지 않음 (실험에서는 false)
    objects:
      - objectTemplate: templates/deployment.yaml   # Deployment 1개 생성
        replicas: 1
      - objectTemplate: templates/configmap.yaml    # ConfigMap 1개 생성
        replicas: 1
      - objectTemplate: templates/secret.yaml       # Secret 1개 생성
        replicas: 1
      - objectTemplate: templates/service.yaml      # Service 1개 생성
        replicas: 1

  # 2. Patch 작업 (Deployment에 patch 3종류, 10회 반복)
  - name: api-intensive-patch
    jobType: patch
    jobIterations: 10                 # 10회 반복
    qps: 500                          # 초당 500개 patch 요청
    burst: 500
    objects:
      - kind: Deployment
        objectTemplate: templates/deployment_patch_add_label.json   # json-patch로 라벨 추가
        labelSelector: {kube-burner-job: api-intensive}
        patchType: "application/json-patch+json"
        apiVersion: apps/v1
      - kind: Deployment
        objectTemplate: templates/deployment_patch_add_pod_2.yaml  # apply-patch로 replica 2로 변경
        labelSelector: {kube-burner-job: api-intensive}
        patchType: "application/apply-patch+yaml"
        apiVersion: apps/v1
      - kind: Deployment
        objectTemplate: templates/deployment_patch_add_label.yaml  # strategic-merge-patch로 라벨 추가
        labelSelector: {kube-burner-job: api-intensive}
        patchType: "application/strategic-merge-patch+json"
        apiVersion: apps/v1

  # 3. Deployment 삭제 작업
  - name: api-intensive-remove
    qps: 500
    burst: 500
    jobType: delete
    waitForDeletion: true             # 실제 삭제 완료까지 대기
    objects:
      - kind: Deployment
        labelSelector: {kube-burner-job: api-intensive}
        apiVersion: apps/v1

  # 4. Pod 삭제 작업 (Deployment 삭제 후 남은 Pod 정리)
  - name: ensure-pods-removal
    qps: 500
    burst: 500
    jobType: delete
    waitForDeletion: true
    objects:
      - kind: Pod
        labelSelector: {kube-burner-job: api-intensive}

  # 5. Service 삭제 작업
  - name: remove-services
    qps: 500
    burst: 500
    jobType: delete
    waitForDeletion: true
    objects:
      - kind: Service
        labelSelector: {kube-burner-job: api-intensive}

  # 6. ConfigMap/Secret 삭제 작업
  - name: remove-configmaps-secrets
    qps: 500
    burst: 500
    jobType: delete
    objects:
      - kind: ConfigMap
        labelSelector: {kube-burner-job: api-intensive}
      - kind: Secret
        labelSelector: {kube-burner-job: api-intensive}

  # 7. Namespace 삭제 작업 (최종적으로 네임스페이스 정리)
  - name: remove-namespace
    qps: 500
    burst: 500
    jobType: delete
    waitForDeletion: true
    objects:
      - kind: Namespace
        labelSelector: {kube-burner-job: api-intensive}
EOF

# 수행
kube-burner init -c api-intensive-500.yml --log-level debug   # 500 workload 실행

Kubernetes API 서버에 들어오는 요청의 처리량(QPS, 초당 요청 수)과 각 요청이 처리되는 데 걸리는 평균 지연 시간(latency)을 보여줍니다. 실험에서는 500개의 워크로드(Deployment, Pod, Service 등)를 동시에 생성하고 삭제하는 작업을 수행했으며, 이 과정에서 QPS가 평소보다 급격하게 증가하는 모습을 확인할 수 있습니다.
QPS가 높아진다는 것은 API 서버가 짧은 시간에 많은 요청을 처리하고 있다는 의미입니다. 동시에, 평균 지연 시간도 함께 상승하는데, 이는 요청이 몰리면서 API 서버가 각 요청을 처리하는 데 더 오랜 시간이 걸리기 때문입니다.
즉, 대량의 오브젝트 생성/삭제 작업이 API 서버에 상당한 부하를 주고 있으며, 이로 인해 응답 속도가 느려질 수 있음을 알 수 있습니다.

각 오브젝트(Deployment, Pod, Service, ConfigMap, Secret, Namespace 등)별로 초당 처리된 요청 수(QPS), 평균 처리 시간, 그리고 성공/실패 건수를 상세하게 보여줍니다.
전체 500개의 워크로드 삭제 작업이 수십 초 이내에 모두 완료되어, 대량의 오브젝트를 동시에 삭제하더라도 Kubernetes API 서버가 이를 빠르게 처리할 수 있음을 확인할 수 있습니다.

Api Server 모니터링 실습

Kubernetes API 서버가 최근 5분간 처리한 요청 수(QPS)를 리소스(resource), 요청 동작(verb), 응답 코드(code)별로 집계하여 모니터링할 수 있습니다.

이를 위해 Prometheus의 apiserver_request_total 메트릭을 활용하며, 이 메트릭은 요청이 어떤 리소스에 대해, 어떤 동작(예: GET, POST, DELETE)으로, 어떤 결과(응답 코드)로 처리되었는지 정보를 제공합니다.

주로 rate 또는 irate 함수를 사용하여 초당 요청 수를 계산하고, sum by(resource, code, verb)와 같은 집계로 리소스별/응답 코드별/동작별 요청량을 확인할 수 있습니다.

단계 별로 모니터링 정보를 구체화 하는 실습을 진행했습니다.

# 연습1 : 라벨(label) 과 값(value) 확인
apiserver_request_total  # 전체 API 서버 요청 카운터 메트릭(라벨, 값 확인용)
rate(apiserver_request_total{job="apiserver"}[5m])  # 5분간 초당 요청 수(rate 함수 사용)
irate(apiserver_request_total{job="apiserver"}[5m]) # 5분간 초당 요청 수(irate 함수 사용, 더 민감)

# 연습2
sum by(code) (irate(apiserver_request_total{job="apiserver"}[5m]))   # 응답 코드별 초당 요청 수
sum by(verb) (irate(apiserver_request_total{job="apiserver"}[5m]))   # 동작(verb)별 초당 요청 수
sum by(resource) (irate(apiserver_request_total{job="apiserver"}[5m])) # 리소스별 초당 요청 수
sum by(resource, code, verb) (irate(apiserver_request_total{job="apiserver"}[5m])) # 리소스/코드/동작별 집계

# 연습3 : resource 값 없는 것 제외
topk(3, sum by(resource) (irate(apiserver_request_total{job="apiserver"}[5m]))) # 리소스별 상위 3개 요청량(빈 값 포함)
topk(3, sum by(resource) (irate(apiserver_request_total{resource=~".+"}[5m])))  # 리소스 값이 있는 것만 상위 3개

# 연습3 : 4xx, 5xx 응답 코드만 필터링
sum by(code) (rate(apiserver_request_total{code=~"[45].."}[1m])) # 4xx, 5xx 에러 응답 코드별 초당 요청 수

# 최종
sum by(resource, code, verb) (rate(apiserver_request_total{resource=~".+"}[5m])) # 리소스/코드/동작별 5분간 초당 요청 수
or
sum by(resource, code, verb) (irate(apiserver_request_total{resource=~".+"}[5m])) # irate로 더 민감하게 측정

위 이미지는 Grafana에서 apiserver_request_total 메트릭을 활용하여 Kubernetes API 서버의 요청 현황을 모니터링한 결과입니다.

첫 번째 이미지는 리소스(resource), 응답 코드(code), 동작(verb)별로 집계된 초당 요청 수(QPS)를 보여줍니다.
각 리소스에 대해 어떤 동작(예: GET, POST, DELETE)이 얼마나 발생했고, 그 결과가 어떤 응답 코드(2xx, 4xx, 5xx 등)로 처리되었는지 한눈에 확인할 수 있습니다. 이를 통해 API 서버에 가장 많이 요청되는 리소스와, 에러가 많이 발생하는 동작 등을 파악할 수 있습니다.
두 번째 이미지는 위의 데이터를 좀 더 세부적으로 분류하거나, 특정 조건(예: 에러 응답만 필터링, 상위 3개 리소스만 보기 등)으로 집계한 결과를 보여줍니다.
이를 통해 API 서버의 부하 분포, 비정상 요청의 비율, 특정 리소스에 집중된 트래픽 등을 실시간으로 모니터링할 수 있습니다.

Cilium Performance 측정 실습

실습 환경 구성 (Type1) by kind k8s + Cilium CNI

# Prometheus Target connection refused bind-address 설정 : kube-controller-manager , kube-scheduler , etcd , kube-proxy
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
networking:
  disableDefaultCNI: true
  kubeProxyMode: none
  podSubnet: "10.244.0.0/16"   # cluster-cidr
kubeadmConfigPatches:
- |
  kind: ClusterConfiguration
  controllerManager:
    extraArgs:
      allocate-node-cidrs: "true"
      cluster-cidr: "10.244.0.0/16"
      node-cidr-mask-size: "22"
EOF

# node 별 PodCIDR 확인
❯ kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'
10.244.0.0/22


# cilium cni 설치
cilium install --version 1.18.1 --set ipam.mode=kubernetes --set ipv4NativeRoutingCIDR=172.20.0.0/16 \
--set routingMode=native --set autoDirectNodeRoutes=true --set endpointRoutes.enabled=true --set directRoutingSkipUnreachable=true \
--set kubeProxyReplacement=true --set bpf.masquerade=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set hubble.enabled=true --set hubble.relay.enabled=true --set hubble.ui.enabled=true \
--set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=30003 \
--set prometheus.enabled=true --set operator.prometheus.enabled=true --set envoy.prometheus.enabled=true --set hubble.metrics.enableOpenMetrics=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload\,traffic_direction}" \
--set debug.enabled=true  # --dry-run-helm-values

# hubble ui
open http://127.0.0.1:30003


# metrics-server
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

# 확인
❯ kubectl top node
NAME                  CPU(cores)   CPU(%)   MEMORY(bytes)   MEMORY(%)   
myk8s-control-plane   279m         3%       1099Mi          6%          
❯ kubectl top pod -A --sort-by='cpu'
NAMESPACE            NAME                                          CPU(cores)   MEMORY(bytes)   
kube-system          kube-apiserver-myk8s-control-plane            44m          287Mi           
kube-system          cilium-nd6wz                                  31m          192Mi           
kube-system          etcd-myk8s-control-plane                      18m          50Mi            
kube-system          kube-controller-manager-myk8s-control-plane   14m          62Mi            
kube-system          hubble-ui-655f947f96-9smdl                    6m           21Mi            
kube-system          kube-scheduler-myk8s-control-plane            6m           22Mi            
kube-system          cilium-envoy-h4w45                            5m           20Mi            
kube-system          coredns-674b8bbfcf-2lnpv                      3m           17Mi            
kube-system          coredns-674b8bbfcf-9fplq                      3m           14Mi            
kube-system          cilium-operator-74c8d8bb68-wrh5k              3m           45Mi            
kube-system          metrics-server-5dd7b49d79-jz6kn               2m           17Mi            
kube-system          hubble-relay-fdd49b976-gfpg9                  1m           18Mi            
local-path-storage   local-path-provisioner-7dc846544d-ctzrk       1m           10Mi            
❯ kubectl top pod -A --sort-by='memory'
NAMESPACE            NAME                                          CPU(cores)   MEMORY(bytes)   
kube-system          kube-apiserver-myk8s-control-plane            44m          287Mi           
kube-system          cilium-nd6wz                                  31m          192Mi           
kube-system          kube-controller-manager-myk8s-control-plane   14m          62Mi            
kube-system          etcd-myk8s-control-plane                      18m          50Mi            
kube-system          cilium-operator-74c8d8bb68-wrh5k              3m           45Mi            
kube-system          kube-scheduler-myk8s-control-plane            6m           22Mi            
kube-system          hubble-ui-655f947f96-9smdl                    6m           21Mi            
kube-system          cilium-envoy-h4w45                            5m           20Mi            
kube-system          hubble-relay-fdd49b976-gfpg9                  1m           18Mi            
kube-system          metrics-server-5dd7b49d79-jz6kn               2m           17Mi            
kube-system          coredns-674b8bbfcf-2lnpv                      3m           17Mi            
kube-system          coredns-674b8bbfcf-9fplq                      3m           14Mi            
local-path-storage   local-path-provisioner-7dc846544d-ctzrk       1m           10Mi  
Prometheus & Grafana 설치
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.18.1/examples/kubernetes/addons/prometheus/monitoring-example.yaml

#
❯ kubectl get deploy,pod,svc,ep -n cilium-monitoring
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/grafana      1/1     1            1           26s
deployment.apps/prometheus   1/1     1            1           26s

NAME                              READY   STATUS    RESTARTS   AGE
pod/grafana-5c69859d9-nsgtt       1/1     Running   0          26s
pod/prometheus-6fc896bc5d-mdkwd   1/1     Running   0          26s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/grafana      ClusterIP   10.96.110.99   <none>        3000/TCP   26s
service/prometheus   ClusterIP   10.96.232.10   <none>        9090/TCP   26s

NAME                   ENDPOINTS           AGE
endpoints/grafana      10.244.3.17:3000    26s
endpoints/prometheus   10.244.0.197:9090   26s
❯ kubectl get cm -n cilium-monitoring
NAME                                         DATA   AGE
grafana-cilium-dashboard                     1      31s
grafana-cilium-operator-dashboard            1      31s
grafana-config                               3      31s
grafana-hubble-dashboard                     1      31s
grafana-hubble-l7-http-metrics-by-workload   1      31s
kube-root-ca.crt                             1      31s
prometheus                                   1      31s
kubectl describe cm -n cilium-monitoring prometheus
kubectl describe cm -n cilium-monitoring grafana-config
❯ kubectl get svc -n cilium-monitoring
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
grafana      ClusterIP   10.96.110.99   <none>        3000/TCP   68s
prometheus   ClusterIP   10.96.232.10   <none>        9090/TCP   68s

# NodePort 설정
kubectl patch svc -n cilium-monitoring prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n cilium-monitoring grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'

# 접속 주소 확인
open "http://127.0.0.1:30001"  # prometheus
open "http://127.0.0.1:30002"  # grafana

쿠버네티스 환경에서 속도 측정 테스트

배포 및 확인

# 배포
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: iperf3-server
spec:
  selector:
    matchLabels:
      app: iperf3-server
  replicas: 1
  template:
    metadata:
      labels:
        app: iperf3-server
    spec:
      containers:
      - name: iperf3-server
        image: networkstatic/iperf3
        args: ["-s"]
        ports:
        - containerPort: 5201
---
apiVersion: v1
kind: Service
metadata:
  name: iperf3-server
spec:
  selector:
    app: iperf3-server
  ports:
    - name: tcp-service
      protocol: TCP
      port: 5201
      targetPort: 5201
    - name: udp-service
      protocol: UDP
      port: 5201
      targetPort: 5201
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: iperf3-client
spec:
  selector:
    matchLabels:
      app: iperf3-client
  replicas: 1
  template:
    metadata:
      labels:
        app: iperf3-client
    spec:
      containers:
      - name: iperf3-client
        image: networkstatic/iperf3
        command: ["sleep"]
        args: ["infinity"]
EOF

# 확인 : 서버와 클라이언트가 어떤 노드에 배포되었는지 확인
❯ kubectl get deploy,svc,pod -owide
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS      IMAGES                 SELECTOR
deployment.apps/iperf3-client   1/1     1            1           11s   iperf3-client   networkstatic/iperf3   app=iperf3-client
deployment.apps/iperf3-server   1/1     1            1           11s   iperf3-server   networkstatic/iperf3   app=iperf3-server

NAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE   SELECTOR
service/iperf3-server   ClusterIP   10.96.68.252   <none>        5201/TCP,5201/UDP   11s   app=iperf3-server
service/kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP             34m   <none>

NAME                                 READY   STATUS    RESTARTS   AGE   IP            NODE                  NOMINATED NODE   READINESS GATES
pod/iperf3-client-688ff6565d-gpflq   1/1     Running   0          11s   10.244.3.69   myk8s-control-plane   <none>           <none>
pod/iperf3-server-5d54b669cc-8b7mg   1/1     Running   0          11s   10.244.3.44   myk8s-control-plane   <none>           <none>

TCP 5201, 측정시간 5초

# 클라이언트 파드에서 아래 명령 실행
❯ kubectl exec -it deploy/iperf3-client -- iperf3 -c iperf3-server -t 5
Connecting to host iperf3-server, port 5201
[  5] local 10.244.3.69 port 53534 connected to 10.96.68.252 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  18.0 GBytes   155 Gbits/sec    3   1.62 MBytes       
[  5]   1.00-2.00   sec  18.3 GBytes   157 Gbits/sec    6   1.62 MBytes       
[  5]   2.00-3.00   sec  18.8 GBytes   162 Gbits/sec   10   1.62 MBytes       
[  5]   3.00-4.00   sec  18.6 GBytes   160 Gbits/sec    2   1.81 MBytes       
[  5]   4.00-5.00   sec  17.8 GBytes   153 Gbits/sec    7   1.81 MBytes       
-
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-5.00   sec  91.5 GBytes   157 Gbits/sec   28             sender
[  5]   0.00-5.00   sec  91.5 GBytes   157 Gbits/sec                  receiver

iperf Done.

# 서버 파드 로그 확인 : 기본 5201 포트 Listen
❯ kubectl logs -l app=iperf3-server -f
-
Server listening on 5201 (test #1)
-
Accepted connection from 10.244.3.69, port 53532
[  5] local 10.244.3.44 port 5201 connected to 10.244.3.69 port 53534
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec  18.0 GBytes   155 Gbits/sec                  
[  5]   1.00-2.00   sec  18.3 GBytes   157 Gbits/sec                  
[  5]   2.00-3.00   sec  18.8 GBytes   162 Gbits/sec                  
[  5]   3.00-4.00   sec  18.6 GBytes   160 Gbits/sec                  
[  5]   4.00-5.00   sec  17.8 GBytes   153 Gbits/sec                  
[  5]   5.00-5.00   sec  1.00 MBytes  95.3 Gbits/sec                  
-
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-5.00   sec  91.5 GBytes   157 Gbits/sec                  receiver

**UDP 사용, 역방향모드(-R)

❯ kubectl exec -it deploy/iperf3-client -- iperf3 -c iperf3-server -u -b 20G
Connecting to host iperf3-server, port 5201
[  5] local 10.244.3.69 port 53526 connected to 10.96.68.252 port 5201
[ ID] Interval           Transfer     Bitrate         Total Datagrams
[  5]   0.00-1.00   sec  2.33 GBytes  20.0 Gbits/sec  76269  
[  5]   1.00-2.00   sec  2.33 GBytes  20.0 Gbits/sec  76293  
[  5]   2.00-3.00   sec  2.33 GBytes  20.0 Gbits/sec  76295  
[  5]   3.00-4.00   sec  2.33 GBytes  20.0 Gbits/sec  76288  
[  5]   4.00-5.00   sec  2.33 GBytes  20.0 Gbits/sec  76299  
[  5]   5.00-6.00   sec  2.33 GBytes  20.0 Gbits/sec  76294  
[  5]   6.00-7.00   sec  2.33 GBytes  20.0 Gbits/sec  76292  
[  5]   7.00-8.00   sec  2.33 GBytes  20.0 Gbits/sec  76299  
[  5]   8.00-9.00   sec  2.33 GBytes  20.0 Gbits/sec  76301  
[  5]   9.00-10.00  sec  2.33 GBytes  20.0 Gbits/sec  76309  
-
[ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
[  5]   0.00-10.00  sec  23.3 GBytes  20.0 Gbits/sec  0.000 ms  0/762939 (0%)  sender
[  5]   0.00-10.00  sec  21.7 GBytes  18.6 Gbits/sec  0.002 ms  52404/762939 (6.9%)  receiver

iperf Done.

❯ kubectl logs -l app=iperf3-server -f
-
Server listening on 5201 (test #2)
-
Accepted connection from 10.244.3.69, port 44478
[  5] local 10.244.3.44 port 5201 connected to 10.244.3.69 port 53526
[ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
[  5]   0.00-1.00   sec  2.18 GBytes  18.8 Gbits/sec  0.001 ms  4701/76269 (6.2%)  
[  5]   1.00-2.00   sec  2.20 GBytes  18.9 Gbits/sec  0.001 ms  4126/76293 (5.4%)  
[  5]   2.00-3.00   sec  2.16 GBytes  18.6 Gbits/sec  0.001 ms  5372/76295 (7%)  
[  5]   3.00-4.00   sec  2.16 GBytes  18.5 Gbits/sec  0.001 ms  5609/76288 (7.4%)  
[  5]   4.00-5.00   sec  2.17 GBytes  18.7 Gbits/sec  0.001 ms  5104/76299 (6.7%)  
[  5]   5.00-6.00   sec  2.17 GBytes  18.6 Gbits/sec  0.001 ms  5336/76294 (7%)  
[  5]   6.00-7.00   sec  2.13 GBytes  18.3 Gbits/sec  0.001 ms  6390/76292 (8.4%)  
[  5]   7.00-8.00   sec  2.16 GBytes  18.6 Gbits/sec  0.001 ms  5424/76299 (7.1%)  
[  5]   8.00-9.00   sec  2.15 GBytes  18.5 Gbits/sec  0.001 ms  5822/76301 (7.6%)  
[  5]   9.00-10.00  sec  2.19 GBytes  18.8 Gbits/sec  0.001 ms  4520/76307 (5.9%)  
[  5]  10.00-10.00  sec  64.0 KBytes   950 Mbits/sec  0.002 ms  0/2 (0%)  
-
[ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
[  5]   0.00-10.00  sec  21.7 GBytes  18.6 Gbits/sec  0.002 ms  52404/762939 (6.9%)  receiver

TCP, 쌍방향 모드(-R)

# 클라이언트 파드에서 아래 명령 실행
kubectl exec -it deploy/iperf3-client -- iperf3 -c iperf3-server -t 5 --bidir
❯ kubectl exec -it deploy/iperf3-client -- iperf3 -c iperf3-server -t 5 --bidir
Connecting to host iperf3-server, port 5201
[  5] local 10.244.3.69 port 47046 connected to 10.96.68.252 port 5201
[  7] local 10.244.3.69 port 47060 connected to 10.96.68.252 port 5201
[ ID][Role] Interval           Transfer     Bitrate         Retr  Cwnd
[  5][TX-C]   0.00-1.00   sec  7.21 GBytes  61.9 Gbits/sec    1   3.43 MBytes       
[  7][RX-C]   0.00-1.00   sec  9.18 GBytes  78.9 Gbits/sec                  
[  5][TX-C]   1.00-2.00   sec  13.7 GBytes   118 Gbits/sec    4   3.43 MBytes       
[  7][RX-C]   1.00-2.00   sec  1.58 GBytes  13.6 Gbits/sec                  
[  5][TX-C]   2.00-3.00   sec  3.98 GBytes  34.2 Gbits/sec    3   3.43 MBytes       
[  7][RX-C]   2.00-3.00   sec  11.9 GBytes   103 Gbits/sec                  
[  5][TX-C]   3.00-4.00   sec  2.49 GBytes  21.4 Gbits/sec    0   3.56 MBytes       
[  7][RX-C]   3.00-4.00   sec  13.7 GBytes   117 Gbits/sec                  
[  5][TX-C]   4.00-5.00   sec  10.6 GBytes  91.3 Gbits/sec    4   1.87 MBytes       
[  7][RX-C]   4.00-5.00   sec  5.43 GBytes  46.6 Gbits/sec                  
-
[ ID][Role] Interval           Transfer     Bitrate         Retr
[  5][TX-C]   0.00-5.00   sec  38.0 GBytes  65.3 Gbits/sec   12             sender
[  5][TX-C]   0.00-5.00   sec  38.0 GBytes  65.3 Gbits/sec                  receiver
[  7][RX-C]   0.00-5.00   sec  41.8 GBytes  71.8 Gbits/sec   12             sender
[  7][RX-C]   0.00-5.00   sec  41.8 GBytes  71.8 Gbits/sec                  receiver

iperf Done.
# 서버 파드 로그 확인 : 기본 5201 포트 Listen
❯ kubectl logs -l app=iperf3-server -f
-
Server listening on 5201 (test #3)
-
Accepted connection from 10.244.3.69, port 47036
[  5] local 10.244.3.44 port 5201 connected to 10.244.3.69 port 47046
[  8] local 10.244.3.44 port 5201 connected to 10.244.3.69 port 47060
[ ID][Role] Interval           Transfer     Bitrate         Retr  Cwnd
[  5][RX-S]   0.00-1.00   sec  7.20 GBytes  61.8 Gbits/sec                  
[  8][TX-S]   0.00-1.00   sec  9.19 GBytes  78.9 Gbits/sec    2   2.00 MBytes       
[  5][RX-S]   1.00-2.00   sec  13.7 GBytes   118 Gbits/sec                  
[  8][TX-S]   1.00-2.00   sec  1.59 GBytes  13.6 Gbits/sec    0   2.00 MBytes       
[  5][RX-S]   2.00-3.00   sec  3.97 GBytes  34.1 Gbits/sec                  
[  8][TX-S]   2.00-3.00   sec  11.9 GBytes   103 Gbits/sec    6   2.12 MBytes       
[  5][RX-S]   3.00-4.00   sec  2.49 GBytes  21.4 Gbits/sec                  
[  8][TX-S]   3.00-4.00   sec  13.7 GBytes   117 Gbits/sec    3   2.37 MBytes       
[  5][RX-S]   4.00-5.00   sec  10.6 GBytes  91.4 Gbits/sec                  
[  8][TX-S]   4.00-5.00   sec  5.44 GBytes  46.7 Gbits/sec    1   2.56 MBytes       
[  5][RX-S]   5.00-5.00   sec  1.12 MBytes  80.7 Gbits/sec                  
[  8][TX-S]   5.00-5.00   sec  0.00 Bytes  0.00 bits/sec    0   2.56 MBytes       
-
[ ID][Role] Interval           Transfer     Bitrate         Retr
[  5][RX-S]   0.00-5.00   sec  38.0 GBytes  65.3 Gbits/sec                  receiver
[  8][TX-S]   0.00-5.00   sec  41.8 GBytes  71.8 Gbits/sec   12             sender

TCP 다중 스트림(30개), -P(number of parallel client streams to run)

# 클라이언트 파드에서 아래 명령 실행
❯ kubectl exec -it deploy/iperf3-client -- iperf3 -c iperf3-server -t 10 -P 2
Connecting to host iperf3-server, port 5201
[  5] local 10.244.3.69 port 38404 connected to 10.96.68.252 port 5201
[  7] local 10.244.3.69 port 38410 connected to 10.96.68.252 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  8.14 GBytes  69.9 Gbits/sec   26   1.25 MBytes       
[  7]   0.00-1.00   sec  8.14 GBytes  69.9 Gbits/sec   20    895 KBytes       
[SUM]   0.00-1.00   sec  16.3 GBytes   140 Gbits/sec   46             
-
[  5]   1.00-2.00   sec  8.56 GBytes  73.6 Gbits/sec   17   1.25 MBytes       
[  7]   1.00-2.00   sec  8.56 GBytes  73.6 Gbits/sec   23   1023 KBytes       
[SUM]   1.00-2.00   sec  17.1 GBytes   147 Gbits/sec   40             
-
[  5]   2.00-3.00   sec  8.63 GBytes  74.1 Gbits/sec   16   1.25 MBytes       
[  7]   2.00-3.00   sec  8.63 GBytes  74.1 Gbits/sec   15   1023 KBytes       
[SUM]   2.00-3.00   sec  17.3 GBytes   148 Gbits/sec   31             
-
[  5]   3.00-4.00   sec  8.63 GBytes  74.2 Gbits/sec   14   1.37 MBytes       
[  7]   3.00-4.00   sec  8.63 GBytes  74.2 Gbits/sec   25   1023 KBytes       
[SUM]   3.00-4.00   sec  17.3 GBytes   148 Gbits/sec   39             
-
[  5]   4.00-5.00   sec  8.25 GBytes  70.9 Gbits/sec   18    959 KBytes       
[  7]   4.00-5.00   sec  8.25 GBytes  70.9 Gbits/sec   20   1023 KBytes       
[SUM]   4.00-5.00   sec  16.5 GBytes   142 Gbits/sec   38             
-
[  5]   5.00-6.00   sec  8.53 GBytes  73.3 Gbits/sec   14    767 KBytes       
[  7]   5.00-6.00   sec  8.53 GBytes  73.3 Gbits/sec   19   1023 KBytes       
[SUM]   5.00-6.00   sec  17.1 GBytes   147 Gbits/sec   33             
-
[  5]   6.00-7.00   sec  8.77 GBytes  75.3 Gbits/sec    5    959 KBytes       
[  7]   6.00-7.00   sec  8.77 GBytes  75.3 Gbits/sec   18   1023 KBytes       
[SUM]   6.00-7.00   sec  17.5 GBytes   151 Gbits/sec   23             
-
[  5]   7.00-8.00   sec  7.70 GBytes  66.1 Gbits/sec   18    959 KBytes       
[  7]   7.00-8.00   sec  7.70 GBytes  66.1 Gbits/sec   28   1023 KBytes       
[SUM]   7.00-8.00   sec  15.4 GBytes   132 Gbits/sec   46             
-
[  5]   8.00-9.00   sec  8.42 GBytes  72.4 Gbits/sec   13    959 KBytes       
[  7]   8.00-9.00   sec  8.42 GBytes  72.4 Gbits/sec   29    831 KBytes       
[SUM]   8.00-9.00   sec  16.8 GBytes   145 Gbits/sec   42             
-
[  5]   9.00-10.00  sec  8.45 GBytes  72.6 Gbits/sec   17   1.12 MBytes       
[  7]   9.00-10.00  sec  8.45 GBytes  72.6 Gbits/sec   10   1.06 MBytes       
[SUM]   9.00-10.00  sec  16.9 GBytes   145 Gbits/sec   27             
-
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  84.1 GBytes  72.2 Gbits/sec  158             sender
[  5]   0.00-10.00  sec  84.1 GBytes  72.2 Gbits/sec                  receiver
[  7]   0.00-10.00  sec  84.1 GBytes  72.2 Gbits/sec  207             sender
[  7]   0.00-10.00  sec  84.1 GBytes  72.2 Gbits/sec                  receiver
[SUM]   0.00-10.00  sec   168 GBytes   144 Gbits/sec  365             sender
[SUM]   0.00-10.00  sec   168 GBytes   144 Gbits/sec                  receiver

iperf Done.

# 서버 파드 로그 확인 : 기본 5201 포트 Listen
❯ kubectl logs -l app=iperf3-server -f
-
Server listening on 5201 (test #4)
-
Accepted connection from 10.244.3.69, port 38390
[  5] local 10.244.3.44 port 5201 connected to 10.244.3.69 port 38404
[  8] local 10.244.3.44 port 5201 connected to 10.244.3.69 port 38410
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec  8.14 GBytes  69.9 Gbits/sec                  
[  8]   0.00-1.00   sec  8.14 GBytes  69.9 Gbits/sec                  
[SUM]   0.00-1.00   sec  16.3 GBytes   140 Gbits/sec                  
-
[  5]   1.00-2.00   sec  8.56 GBytes  73.6 Gbits/sec                  
[  8]   1.00-2.00   sec  8.56 GBytes  73.6 Gbits/sec                  
[SUM]   1.00-2.00   sec  17.1 GBytes   147 Gbits/sec                  
-
[  5]   2.00-3.00   sec  8.63 GBytes  74.1 Gbits/sec                  
[  8]   2.00-3.00   sec  8.63 GBytes  74.1 Gbits/sec                  
[SUM]   2.00-3.00   sec  17.3 GBytes   148 Gbits/sec                  
-
[  5]   3.00-4.00   sec  8.63 GBytes  74.2 Gbits/sec                  
[  8]   3.00-4.00   sec  8.63 GBytes  74.2 Gbits/sec                  
[SUM]   3.00-4.00   sec  17.3 GBytes   148 Gbits/sec                  
-
[  5]   4.00-5.00   sec  8.25 GBytes  70.9 Gbits/sec                  
[  8]   4.00-5.00   sec  8.25 GBytes  70.9 Gbits/sec                  
[SUM]   4.00-5.00   sec  16.5 GBytes   142 Gbits/sec                  
-
[  5]   5.00-6.00   sec  8.53 GBytes  73.3 Gbits/sec                  
[  8]   5.00-6.00   sec  8.53 GBytes  73.3 Gbits/sec                  
[SUM]   5.00-6.00   sec  17.1 GBytes   147 Gbits/sec                  
-
[  5]   6.00-7.00   sec  8.77 GBytes  75.3 Gbits/sec                  
[  8]   6.00-7.00   sec  8.77 GBytes  75.3 Gbits/sec                  
[SUM]   6.00-7.00   sec  17.5 GBytes   151 Gbits/sec                  
-
[  5]   7.00-8.00   sec  7.70 GBytes  66.1 Gbits/sec                  
[  8]   7.00-8.00   sec  7.70 GBytes  66.1 Gbits/sec                  
[SUM]   7.00-8.00   sec  15.4 GBytes   132 Gbits/sec                  
-
[  5]   8.00-9.00   sec  8.42 GBytes  72.4 Gbits/sec                  
[  8]   8.00-9.00   sec  8.42 GBytes  72.4 Gbits/sec                  
[SUM]   8.00-9.00   sec  16.8 GBytes   145 Gbits/sec                  
-
[  5]   9.00-10.00  sec  8.45 GBytes  72.6 Gbits/sec                  
[  8]   9.00-10.00  sec  8.45 GBytes  72.6 Gbits/sec                  
[SUM]   9.00-10.00  sec  16.9 GBytes   145 Gbits/sec                  
-
[  5]  10.00-10.00  sec  2.62 MBytes  68.6 Gbits/sec                  
[  8]  10.00-10.00  sec  2.62 MBytes  69.2 Gbits/sec                  
[SUM]  10.00-10.00  sec  5.25 MBytes   137 Gbits/sec                  
-
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  84.1 GBytes  72.2 Gbits/sec                  receiver
[  8]   0.00-10.00  sec  84.1 GBytes  72.2 Gbits/sec                  receiver
[SUM]   0.00-10.00  sec   168 GBytes   144 Gbits/sec                  receiver

삭제

 kubectl delete deploy iperf3-server iperf3-client && kubectl delete svc iperf3-server 

Cilium Performance & Tuning

eBPF Maps 상향 조정 실습

eBPF 맵(Map)은 커널 내부에서 데이터를 저장하는 자료구조로, Cilium에서는 네트워크 트래픽을 추적하거나 정책을 적용할 때 다양한 eBPF 맵을 사용합니다.
이 맵들은 각각 최대 용량(upper capacity limit)이 정해져 있어서, 이 한도를 초과하면 더 이상 데이터를 저장할 수 없거나, 데이터 경로(datapath)의 확장성에 제약이 생길 수 있습니다.
Cilium은 기본적으로 시스템 전체 메모리의 일정 비율(ratio)을 기준으로 각 eBPF 맵의 용량을 자동으로 산정(auto-derived)합니다. 즉, 시스템 메모리가 많을수록 더 큰 맵이 생성됩니다.
하지만 고급 사용자는 Cilium 에이전트의 설정을 통해 이 최대 용량(upper capacity limit)을 직접 오버라이드(override)할 수 있습니다.
자세한 내용과 설정 방법은 공식 문서의 eBPF Maps 가이드를 참고하면 됩니다.

kubectl exec -it -n kube-system ds/cilium -- cilium status --verbose
...
KubeProxyReplacement Details:
  Status:               True
  Socket LB:            Enabled
  Socket LB Tracing:    Enabled
  Socket LB Coverage:   Full
  Devices:              eth0    172.18.0.2 fc00:f853:ccd:e793::2 fe80::42:acff:fe12:2 (Direct Routing)
  Mode:                 SNAT
  Backend Selection:    Random
  Session Affinity:     Enabled
  NAT46/64 Support:     Disabled
  XDP Acceleration:     Disabled
  Services:
  - ClusterIP:      Enabled
  - NodePort:       Enabled (Range: 30000-32767) 
  - LoadBalancer:   Enabled 
  - externalIPs:    Enabled 
  - HostPort:       Enabled
  Annotations:
  - service.cilium.io/node
  - service.cilium.io/node-selector
  - service.cilium.io/proxy-delegation
  - service.cilium.io/src-ranges-policy
  - service.cilium.io/type
BPF Maps:   dynamic sizing: on (ratio: 0.002500)
  Name                          Size
  Auth                          524288
  Non-TCP connection tracking   73459
  TCP connection tracking       146919
  Endpoints                     65535
  IP cache                      512000
  IPv4 masquerading agent       16384
  IPv6 masquerading agent       16384
  IPv4 fragmentation            8192
  IPv4 service                  65536
  IPv6 service                  65536
  IPv4 service backend          65536
  IPv6 service backend          65536
  IPv4 service reverse NAT      65536
  IPv6 service reverse NAT      65536
  Metrics                       1024
  Ratelimit metrics             64
  NAT                           146919
  Neighbor table                146919
  Endpoint policy               16384
  Policy stats                  65536
  Session affinity              65536
  Sock reverse NAT              73459
Encryption:       Disabled   
Cluster health:              Probe disabled

helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
--set bpf.distributedLRU.enabled=true --set bpf.mapDynamicSizeRatio=0.01

kubectl -n kube-system rollout restart ds/cilium

kubectl exec -it -n kube-system ds/cilium -- cilium status --verbose
...
BPF Maps:   dynamic sizing: on (ratio: 0.010000)
  Name                          Size
  Auth                          524288
  Non-TCP connection tracking   293840
  TCP connection tracking       587680
  Endpoints                     65535
  IP cache                      512000
  IPv4 masquerading agent       16384
  IPv6 masquerading agent       16384
  IPv4 fragmentation            8192
  IPv4 service                  65536
  IPv6 service                  65536
  IPv4 service backend          65536
  IPv6 service backend          65536
  IPv4 service reverse NAT      65536
  IPv6 service reverse NAT      65536
  Metrics                       1024
  Ratelimit metrics             64
  NAT                           587680
  Neighbor table                587680
  Endpoint policy               16384
  Policy stats                  65536
  Session affinity              65536
  Sock reverse NAT              293840
Encryption:       Disabled   
Cluster health:              Probe disabled

Cilium의 eBPF 맵(Map) 용량을 조정하여, 네트워크 데이터 경로의 확장성을 높이는 과정을 진행했습니다.

  1. 초기 상태 확인
  • kubectl exec -it -n kube-system ds/cilium -- cilium status --verbose 명령을 통해 Cilium의 현재 eBPF 맵 용량과 동작 상태를 확인했습니다.
  • BPF Maps: dynamic sizing: on (ratio: 0.002500) 부분에서, eBPF 맵의 크기가 시스템 메모리의 0.25% 비율로 자동 산정되고 있음을 알 수 있습니다.
  • 주요 맵(예: TCP connection tracking, NAT, Neighbor table 등)의 크기가 각각 146,919, 146,919, 146,919 등으로 설정되어 있습니다.
  1. 맵 용량 상향 조정
  • helm upgrade 명령을 통해 bpf.mapDynamicSizeRatio 값을 0.01(1%)로 상향 조정했습니다.
  • 이 설정은 Cilium이 eBPF 맵을 생성할 때 시스템 메모리의 1%까지 맵 용량을 할당하도록 변경하는 것입니다.
  • 이후 Cilium 데몬셋을 롤링 재시작하여 변경 사항을 적용했습니다.
  1. 조정 후 상태 확인
  • BPF Maps: dynamic sizing: on (ratio: 0.010000)로 비율이 1%로 증가한 것을 볼 수 있습니다.
  • 주요 맵의 크기가 크게 증가했습니다. 예를 들어, TCP connection tracking, NAT, Neighbor table 등이 587,680으로 약 4배 가까이 커졌습니다.
  • 이로써 더 많은 연결, 세션, 네트워크 엔드포인트를 처리할 수 있게 되어, 대규모 트래픽이나 많은 파드가 존재하는 환경에서 확장성과 안정성을 향상시킬 수 있습니다.

Kubernetes perf-tests

Kubernetes perf-tests는 Kubernetes 클러스터의 성능과 확장성을 평가하기 위한 공식 벤치마킹 및 부하 테스트 도구 모음입니다.
다양한 시나리오(예: 파드 생성/삭제, 서비스 처리량, API 서버 응답 시간 등)에 대해 자동화된 테스트를 수행할 수 있도록 설계되어 있습니다.
주요 특징은 다음과 같습니다.

  • clusterloader2: 대규모 클러스터에서 다양한 워크로드를 시뮬레이션하여 성능을 측정하는 대표적인 도구입니다.
  • network performance, scalability, density 등 다양한 테스트 시나리오를 지원합니다.
  • 테스트 결과를 통해 클러스터의 병목 현상, 리소스 한계, 확장성 문제 등을 진단할 수 있습니다.
  • Kubernetes 프로젝트에서 공식적으로 관리하며, 실제 릴리즈 전 성능 검증에도 사용됩니다.

perf-tests는 GitHub 저장소(kubernetes/perf-tests)에서 소스와 문서를 확인할 수 있습니다.

Cilium Endpoint Slices

Cilium이 Kubernetes 클러스터에서 엔드포인트 정보를 관리하는 방식은 EndpointSlice 리소스를 활용하는 것입니다.
예를 들어, 5,000개의 노드가 있고 각 노드마다 100개의 엔드포인트(파드 등)가 존재한다면, 전체적으로 약 500,000개의 엔드포인트에 대한 업데이트(Watch 이벤트)가 발생할 수 있습니다.
이러한 대규모 환경에서는 Cilium이 각 엔드포인트의 상태 변화를 효율적으로 감지하고 처리해야 하므로, EndpointSlice의 동작 방식과 성능이 클러스터 확장성에 중요한 영향을 미칩니다.
아래 이미지는 대규모 Kubernetes 클러스터에서 Cilium이 엔드포인트 정보를 어떻게 관리하는지 단계별로 시각화한 것입니다.

  • EndpointSlice 리소스: Kubernetes는 많은 엔드포인트(파드 등)를 효율적으로 관리하기 위해 EndpointSlice라는 리소스를 사용합니다. 하나의 EndpointSlice에는 여러 개의 엔드포인트 정보(IP, 포트, 상태 등)가 포함되어 있습니다.
  • Cilium의 동작 방식: Cilium은 각 EndpointSlice 리소스의 변경 사항(생성, 수정, 삭제 등)을 Kubernetes API 서버로부터 watch 방식으로 실시간 감지합니다.
  • 엔드포인트 동기화: 감지된 EndpointSlice의 변경 이벤트를 바탕으로, Cilium은 내부 데이터베이스(eBPF 맵 등)에 엔드포인트 정보를 동기화합니다. 이 과정에서 각 엔드포인트의 네트워크 정책, 라우팅 정보, 서비스 연결 정보 등이 함께 관리됩니다.
  • 확장성 고려: 수천~수십만 개의 엔드포인트가 존재하는 환경에서도, Cilium은 EndpointSlice 단위로 효율적으로 엔드포인트 상태를 추적하고, 불필요한 전체 동기화 없이 변경된 부분만 반영합니다. 이를 통해 대규모 트래픽 환경에서도 빠르고 안정적으로 네트워크 정책을 적용할 수 있습니다.
# 각 파드마다 CiliumEndpoint(CEP) 리소스가 생성되며, 모든 Cilium 에이전트가 전체 CEP를 watch합니다.
# CEP는 파드의 IP를 Identity(정책 적용을 위한 식별자)로 매핑하는 역할을 합니다.
kubectl get ciliumendpoints.cilium.io -A                # 모든 네임스페이스의 CEP 목록 조회
NAMESPACE            NAME                                      SECURITY IDENTITY   ENDPOINT STATE   IPV4           IPV6
cilium-monitoring    grafana-5c69859d9-nsgtt                   53695               ready            10.244.3.17    
cilium-monitoring    prometheus-6fc896bc5d-mdkwd               26808               ready            10.244.0.197   
kube-system          coredns-674b8bbfcf-2lnpv                  62452               ready            10.244.0.229   
kube-system          coredns-674b8bbfcf-9fplq                  62452               ready            10.244.1.96    
kube-system          hubble-relay-fdd49b976-gfpg9              3068                ready            10.244.0.131   
kube-system          hubble-ui-655f947f96-9smdl                24056               ready            10.244.3.203   
kube-system          metrics-server-5dd7b49d79-jz6kn           13086               ready            10.244.2.200   
local-path-storage   local-path-provisioner-7dc846544d-ctzrk   19734               ready            10.244.0.153   

kubectl get ciliumendpoints.cilium.io -A | wc -l        # 전체 CEP 개수 확인

kubectl get crd                                         # 현재 클러스터에 등록된 CRD 목록 확인
NAME                                         CREATED AT
ciliumcidrgroups.cilium.io                   2025-08-30T06:26:06Z
ciliumclusterwidenetworkpolicies.cilium.io   2025-08-30T06:26:05Z
ciliumendpoints.cilium.io                    2025-08-30T06:26:03Z
ciliumidentities.cilium.io                   2025-08-30T06:26:01Z
ciliuml2announcementpolicies.cilium.io       2025-08-30T06:26:08Z
ciliumloadbalancerippools.cilium.io          2025-08-30T06:26:07Z
ciliumnetworkpolicies.cilium.io              2025-08-30T06:26:04Z

# CiliumEndpointSlice 기능 활성화 (CEP를 묶어서 관리)
helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
--set ciliumEndpointSlice.enabled=true                  # Cilium Helm Chart 업그레이드 및 EndpointSlice 활성화

kubectl rollout restart -n kube-system deployment cilium-operator   # cilium-operator 재시작
kubectl rollout restart -n kube-system ds/cilium                    # cilium 데몬셋 재시작

# CEP들을 CiliumEndpointSlice CRD로 묶어서 watch 이벤트 수를 크게 줄임
kubectl get crd                                         # CRD 목록에서 CiliumEndpointSlice 리소스 확인
NAME                                         CREATED AT
ciliumcidrgroups.cilium.io                   2025-08-30T06:26:06Z
ciliumclusterwidenetworkpolicies.cilium.io   2025-08-30T06:26:05Z
ciliumendpoints.cilium.io                    2025-08-30T06:26:03Z
ciliumendpointslices.cilium.io               2025-08-30T07:04:04Z
ciliumidentities.cilium.io                   2025-08-30T06:26:01Z
ciliuml2announcementpolicies.cilium.io       2025-08-30T06:26:08Z
ciliumloadbalancerippools.cilium.io          2025-08-30T06:26:07Z
ciliumnetworkpolicies.cilium.io              2025-08-30T06:26:04Z
ciliumnodeconfigs.cilium.io                  2025-08-30T06:26:09Z
ciliumnodes.cilium.io                        2025-08-30T06:26:00Z
ciliumpodippools.cilium.io                   2025-08-30T06:26:02Z

kubectl get ciliumendpointslices.cilium.io -A | wc -l   # 전체 CiliumEndpointSlice 개수 확인
       4

kubectl get ciliumendpointslices.cilium.io -A           # 모든 네임스페이스의 CiliumEndpointSlice 목록 조회
NAME                  AGE
ces-gylwrfmk6-hzfqc   12s
ces-lvnzjtbql-mk8fm   12s
ces-rnqkk7hv2-cgwf7   12s

기존에는 모든 파드별로 CEP 리소스를 개별적으로 관리하고, 모든 Cilium 에이전트가 전체 CEP를 watch해야 했기 때문에 대규모 환경에서 watch 이벤트가 폭증하는 문제가 있었습니다.
CiliumEndpointSlice 기능을 활성화하면 여러 CEP를 하나의 EndpointSlice로 묶어 관리할 수 있어, watch 이벤트 수가 크게 줄고, 클러스터 확장성 및 성능이 향상됩니다.

eBPF Host Routing, Netkit

eBPF Host Routing
eBPF Host Routing은 Cilium이 노드 내에서 패킷을 라우팅할 때 eBPF 프로그램을 활용하는 기능입니다.
기존에는 노드 간, 노드 내 트래픽이 모두 리눅스 커널의 전통적인 라우팅 테이블을 거쳐 처리되었습니다.
하지만 eBPF Host Routing을 사용하면, Cilium이 직접 eBPF를 통해 패킷의 경로를 제어할 수 있어,
더 빠르고 유연한 네트워크 처리가 가능합니다.
이 기능을 활성화하면, Pod 간 통신이나 노드-노드 간 통신에서 불필요한 커널 네트워크 스택을 우회하여
지연(latency)을 줄이고, 네트워크 성능을 향상시킬 수 있습니다.

eBPF Host Routing을 사용하면, Cilium이 리눅스 커널의 전통적인 라우팅 테이블을 거치지 않고
eBPF 프로그램을 통해 직접 패킷의 경로를 제어합니다.
이로 인해 Pod 간, 노드 간 트래픽이 더 빠르게 전달되고, 네트워크 지연이 줄어드는 효과가 있습니다.

NetKit

Netkit은 네트워크 실습 및 시뮬레이션을 위한 도구로, 다양한 네트워크 토폴로지와 환경을 쉽게 구성할 수 있게 해줍니다.
eBPF Host Routing과 같은 네트워크 기능을 실습하거나 테스트할 때 Netkit을 활용하면,
복잡한 실제 환경을 구축하지 않고도 다양한 시나리오를 실험해볼 수 있습니다.

Netkit을 사용하면 여러 가상 노드와 라우터, 스위치 등을 손쉽게 배치하고, 각 노드 간의 네트워크 연결을 자유롭게 설정할 수 있습니다.
이를 통해 실제 환경과 유사한 네트워크 시나리오를 실습하거나, eBPF Host Routing과 같은 고급 네트워크 기능의 동작을 실험해볼 수 있습니다.

마치며

이번 7주차 실습을 통해 Kubernetes와 Cilium 환경에서의 성능 테스트 및 최적화 방법에 대해 학습했습니다.
이번 실습에서는 kube-burner를 활용한 대용량 워크로드 생성, Prometheus와 Grafana를 통한 상세한 모니터링, 그리고 Cilium의 성능 최적화 기능들을 직접 체험해보았습니다.
 
또한 CiliumEndpointSlice 기능을 통한 watch 이벤트 최적화, eBPF Host Routing을 통한 네트워크 성능 향상, 그리고 대용량 환경에서의 실제 성능 측정을 통해 Cilium이 어떻게 대규모 클러스터에서 효율적으로 동작하는지 직접 확인할 수 있었습니다.
 
실습을 통해 성능 테스트 도구의 활용법과 모니터링 시스템 구축 방법, 그리고 Cilium의 고급 최적화 기능들을 이해할 수 있었습니다. 실제 프로덕션 환경에서 발생할 수 있는 성능 이슈와 해결 방안에 대해 고민해볼 수 있어서 좋았던 것 같습니다.
 
긴 글 읽어주셔서 감사합니다 :)

반응형

'클라우드 컴퓨팅 & NoSQL > [Cilium Study] 실리움 스터디' 카테고리의 다른 글

[8주차 - Cilium 스터디] Cilium Security & Tetragon (25.08.31)  (0) 2025.09.06
[6주차 - Cilium 스터디] Cilium ServiceMesh (25.08.17)  (0) 2025.08.23
[5주차 - Cilium 스터디] BGP Control Plane & ClusterMesh (25.08.10)  (4) 2025.08.16
[4주차 - Cilium 스터디] Networking - 노드에 파드들간 통신 2 & K8S 외부 노출 (25.08.03)  (4) 2025.08.08
[3주차 - Cilium 스터디] Networking (25.07.27)  (0) 2025.08.02
    devlos
    devlos
    안녕하세요, Devlos 입니다. 새로 공부 중인 지식들을 공유하고, 명확히 이해하고자 블로그를 개설했습니다 :) 여러 DEVELOPER 분들과 자유롭게 지식을 공유하고 싶어요! 방문해 주셔서 감사합니다 😀 - DEVLOS -

    티스토리툴바