DevOps/Study

Cilium Study [1기] 7주차 Cilium Performance & Tunning

juyeon22 2025. 8. 31. 04:13

Cilium Study [1기] 7주차 Cilium Performance & Tunning

안녕하세요 이번 게시물에서는 Cilium Performance & Tunning 라는 주제에 대한 정보를 전달 드리고자 합니다.

1. 실습 환경 구성

실습 환경 구성은 호스트 환경에서 가장 높은 퍼모먼스를 사용하기 위해 wsl를 이용하여 환경을 구성합니다.

제 환경은 vCPU 8, Mem 12GB로 Kind를 구성 했습니다.

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

# 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


# 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

# Install Prometheus & Grafana
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.18.1/examples/kubernetes/addons/prometheus/monitoring-example.yaml

# 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}]}}'

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

at <<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 exec -it deploy/iperf3-client -- iperf3 -c iperf3-server -t 5
# Connecting to host iperf3-server, port 5201
# [  5] local 10.244.0.230 port 48116 connected to 10.96.119.81 port 5201
# [ ID] Interval           Transfer     Bitrate         Retr  Cwnd
# [  5]   0.00-1.00   sec  1.46 GBytes  12.5 Gbits/sec    0   1.96 MBytes
# [  5]   1.00-2.00   sec  1.72 GBytes  14.8 Gbits/sec    0   2.06 MBytes
# [  5]   2.00-3.00   sec  1.73 GBytes  14.9 Gbits/sec  137   2.06 MBytes
# [  5]   3.00-4.00   sec  1.84 GBytes  15.8 Gbits/sec   93   2.06 MBytes
# [  5]   4.00-5.00   sec  1.64 GBytes  14.1 Gbits/sec    0   2.06 MBytes
# - - - - - - - - - - - - - - - - - - - - - - - - -
# [ ID] Interval           Transfer     Bitrate         Retr
# [  5]   0.00-5.00   sec  8.40 GBytes  14.4 Gbits/sec  230             sender
# [  5]   0.00-5.00   sec  8.40 GBytes  14.4 Gbits/sec                  receiver

# UDP 사용
kubectl exec -it deploy/iperf3-client -- iperf3 -c iperf3-server -u -b 20G
# Connecting to host iperf3-server, port 5201
# [  5] local 10.244.0.230 port 54832 connected to 10.96.119.81 port 5201
# [ ID] Interval           Transfer     Bitrate         Total Datagrams
# [  5]   0.00-1.00   sec   121 MBytes  1.02 Gbits/sec  87888
# [  5]   1.00-2.00   sec   101 MBytes   849 Mbits/sec  73299
# [  5]   2.00-3.00   sec   120 MBytes  1.01 Gbits/sec  87117
# [  5]   3.00-4.00   sec   115 MBytes   967 Mbits/sec  83496
# [  5]   4.00-5.00   sec   122 MBytes  1.02 Gbits/sec  88014
# [  5]   5.00-6.00   sec   105 MBytes   881 Mbits/sec  76044
# [  5]   6.00-7.00   sec   128 MBytes  1.07 Gbits/sec  92765
# [  5]   7.00-8.00   sec   114 MBytes   960 Mbits/sec  82841
# [  5]   8.00-9.00   sec   118 MBytes   988 Mbits/sec  85263
# [  5]   9.00-10.00  sec   118 MBytes   987 Mbits/sec  85195
# - - - - - - - - - - - - - - - - - - - - - - - - -
# [ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total Datagrams
# [  5]   0.00-10.00  sec  1.14 GBytes   975 Mbits/sec  0.000 ms  0/841922 (0%)  sender
# [  5]   0.00-10.00  sec  1.12 GBytes   963 Mbits/sec  0.038 ms  10252/841922 (1.2%)  receiver

cilium connectivity를 사용한 cilium 성능 및 기능 테스트

cilium connectivity test를 사용하면 cilium에서 제공하는 기능들에 대해서 테스트를 할 수 있습니다.

cilium connectivity test --debug  
# 🐛 Detected features:
# 🐛   bpf-lb-external-clusterip: Disabled


# 실습 리소스 삭제
kubectl delete ns cilium-test-1

cilium connectivity perf를 사용하면 cilum에서 성능 측정을 할 수 있습니다.

2. Cilium Tuning 사례

Deep Dive Into Cilium Resilient Architecture 튜닝 사례

Grafana 에서 패킷이 Drop이 되면서, Service Backend not found Error 발생

몇몇 clium-agent 상태가 좋지 않으며, BPF map pressure 가 144%인 것을 확인

lb4_service_v2 Map 업데이트 담당하는 조정자가 failed 과 Error: map is full 확인

영상에서는 service들을 삭제하여 정상 상태 확인

eBPF Map Size 크기 늘리기

eBPF의 Map Size는 기본적으로 Node의 총 메모리 비율로 사이즈가 정해집니다.

kubectl exec -it -n kube-system ds/cilium -- cilium status --verbose

# BPF Maps:   dynamic sizing: on (ratio: 0.002500)
#   Name                          Size
#   Auth                          524288
#   Non-TCP connection tracking   65536
#   TCP connection tracking       131072

helm에서 bpf.mapDynamicSizeRatio값을 증가 시켜 Map Size를 증가시킬 수 있습니다.

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   220068
#   TCP connection tracking       440136

Helm Values를 사용하여 mapDynamicSizeRatio를 증가시키는 것이 아닌 필요한 Map Size를 증가시킬 수 있습니다.

Figure 2.1 MapSize 정보

3. Cilium Tuning Guide

Cilium Endpoint Slices

Cilium에서 Node가 5000대가 있고 100개의 EndPoint가 있는 경우 Watch Update를 하는 경우 500,000번을 수행하게 됩니다.

이때 Cilium Endpoint Slices를 사용하게되면, EndPoint로 관리하는 것이 아닌 EndPoint Slice로 관리를 하게되어 조회를 하게되는경우 성능이 향상됩니다.

Figure 3.1 CES 설명

ciliumEndpointSlice.enabled 옵션이 true로 되어있어야하며, Egress Gateway와 같이 사용할 수는 없습니다.

kubectl get ciliumendpoints.cilium.io -A | wc -l
# 11

helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
--set ciliumEndpointSlice.enabled=true

kubectl rollout restart -n kube-system deployment cilium-operator
kubectl rollout restart -n kube-system ds/cilium 


kubectl get ciliumendpointslices.cilium.io -A | wc -l
# 5

eBPF Host Routing , Netkit

eBPF Host Routing을 사용하면 network stack을 경유하지않고 바로 eBPF Program으로 Container의 veth로 도착하게됩니다.

또한 CPU의 Queuing 과정을 생략하게됩니다.

하지만 Egress 는 호스트 네트워크 스택(per-CPU backlog queue)을 통과해야합니다.

Figure 3.2 eBPF Host Routing 설명

# eBPF Host Routing 적용 확인
kubectl exec -it -n kube-system ds/cilium -- cilium status | grep Routing
# KubeProxyReplacement:    True   [eth0    172.18.0.2 fc00:f853:ccd:e793::2 fe80::1c6a:f7ff:fe3c:2164 (Direct Routing)]
# Routing:                 Network: Native   Host: BPF

NetKit + eBPF Host Routing을 사용하게되면, ngress + egress 큐(CPU) 대기 없이 모두 빠르게 전달하게됩니다.

커널 6.8이상을 기본적으로 필요하기 때문에 간단하게 설정하는 방법만 알아보겠습니다.

helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
--set bpf.datapathMode=netkit

kubectl rollout restart -n kube-system deployment cilium-operator
kubectl rollout restart -n kube-system ds/cilium 

#
kubectl logs -n kube-system cilium-k84hl
time=2025-08-24T09:33:36.486143842Z level=fatal source=/go/src/github.com/cilium/cilium/pkg/logging/slog.go:159 
.. msg="netkit devices need kernel 6.7.0 or newer and CONFIG_NETKIT"

#
helm upgrade cilium cilium/cilium --version 1.18.1 --namespace kube-system --reuse-values \
--set bpf.datapathMode=veth