들어가며
Kubernetes로 구성된 환경에서 AutoScaling은 필수적인 기능이지만, 이를 간단히 테스트하기는 쉽지 않습니다. Minikube 나 Kind 같은 경량화 솔루션들이 등장했지만, 이들 역시 가상 머신이나 Docker와 같은 컨테이너를 사용하므로 리소스 소비가 적지 않습니다.
그렇기 때문에 KWOK(Kubernetes WithOut Kubelet) 가 등장하게 되었는데요. KWOK은 Kubelet 없이도 Kubernetes API와 상호작용하는 가상 노드를 구성할 수 있어, 보다 가볍고 빠르게 AutoScaling을 실험할 수 있는 환경을 구성할 수 있습니다.
KWOK
KWOK이란?
KWOK(Kubernetes WithOut Kubelet)는 Kubernetes의 다양한 기능을 테스트하고 실험할 수 있는 경량 시뮬레이션 도구로, Kubelet 없이 클러스터를 실행할 수 있도록 합니다.
주요 기능
실제 노드 없이도 Kubernetes 환경을 구성할 수 있기 때문에 빠르고 가볍게 테스트 환경을 구성할 수 있습니다. 또한, Kubernetes API 요청을 가로채고, 가상의 Node와 Pod를 생성하여 마치 실제 클러스터처럼 동작하도록 합니다.
또한, KWOK를 사용하면 Node와 Pod에 대해 다양한 시뮬레이션 동작을 구성할 수도 있습니다. 예를 들어, "NotReady"와 같은 특정 조건에서 Node를 생성하여 장애 시나리오를 테스트할 수 있게 구성하거나, CPU 및 메모리 제한을 설정하여 클러스터의 부하 테스트 수행할 수 있고, Pod가 특정 조건에서 어떻게 배치되고 동작하는지 테스트 할 수 있습니다.
구성 요소
KWOK
Kubernetes 노드와 포드를 시뮬레이션하는 핵심 도구로 kwok 명령어를 통해 가상의 Kubernetes 클러스터를 실행할 수 있습니다.
KWOKCTL
KWOK 기반의 로컬 Kubernetes 클러스터를 관리하는 도구로 kind 또는 minikube와 비슷한 방식으로 작동하지만, 훨씬 가볍고 빠르게 클러스터를 배포할 수 있습니다.
# 사용 예시
kwokctl create cluster --name=example
kwokctl delete cluster --name=example
Kind와의 차이점
그렇다면 흔히 kubernetes를 로컬에 테스트 환경으로 구축할 때에 많이 사용하는 Kind와는 무엇이 다른 걸까요?
KIND는 Docker 컨테이너 안에서 Kubernetes 클러스터를 실행하는 도구이기에 실제 Kubernetes 환경과 거의 동일한 환경을 로컬에서 구성할 수 있습니다. 이때, KIND의 Node들은 실제 Kubelet을 실행하고, CRI를 사용하여 컨테이너를 실행할 수 있습니다. 하지만 KWOK는 Kubernetes의 가짜(Fake) Node와 Pod를 시뮬레이션하는 도구입니다. 그렇기에 실제 Kubelet을 실행하지 않으며, 컨테이너도 실행되지 않습니다.
KIND | KWOK | |
구동 방식 | Docker Container에서 Kubernetes 실행 | Kubernetes API 상태만 시뮬레이션 |
Node 실행 방식 | 실제 Kubernete의 Node 실행 | 가짜 Node 및 Pod의 상태만 유지 |
Container 실행 | 가능 | 불가능 |
속도 | 느림 | 빠름 |
리소스 사용량 | 높음 | 낮음 |
목적 | 실제 Kubernetes 환경과 비슷한 개발 및 테스트 | 대규모 Kubernetes 클러스터 시뮬레이션 및 빠른 테스트 |
예시 | 앱 개발, CI/CD, Pod 실행 테스트 | Kubernetes Scheduler, Controller, API 동작 테스트 |
즉, KIND는 실제 Kubernetes 환경을 로컬에서 실행하려는 경우에 적합하기 때문에 실제 애플리케이션을 배포하고 실행하는 것이 필요하다면 KIND를 사용하고, Kubernetes의 API와 리소스를 가볍게 시뮬레이션하거나 빠른 테스트 및 CI/CD을 구성하고 싶다면 KWOK을 선택하는 것이 좋습니다
KWOK의 한계
KWOK는 기존 Kubernetes 환경을 완전히 대체하는 것이 아니라 특정 용도로 사용하기 위한 도구이기 때문에 완전히 Kubernetes의 기능을 구현하지는 않습니다. 특히 실제 Kubelet이 아니므로 Pod 라이프사이클 관리, 볼륨 마운트, 디바이스 플러그인 등의 동작이 다를 수 있습니다. 그리고 단순한 공식을 이용해 일부 동작을 구현해 놓았기 때문에 Kubernetes의 실제 동작과 차이가 있을 수 있습니다. 마지막으로 보안 정책이나 메커니즘을 적용하지 않으며, kube-apiserver에서 오는 모든 요청이 유효하다고 가정하기 때문에 보안 테스트용으로는 적절하지 않습니다.
KWOK 실습
KWOK 설치
변수 설정
KWOK_REPO=kubernetes-sigs/kwok
KWOK_LATEST_RELEASE=$(curl "https://api.github.com/repos/${KWOK_REPO}/releases/latest" | jq -r '.tag_name')
kwokctl 설치
wget -O kwokctl -c "https://github.com/${KWOK_REPO}/releases/download/${KWOK_LATEST_RELEASE}/kwokctl-$(go env GOOS)-$(go env GOARCH)"
chmod +x kwokctl
sudo mv kwokctl /usr/local/bin/kwokctl
kwok 설치
wget -O kwok -c "https://github.com/${KWOK_REPO}/releases/download/${KWOK_LATEST_RELEASE}/kwok-$(go env GOOS)-$(go env GOARCH)"
chmod +x kwok
sudo mv kwok /usr/local/bin/kwok
kwokctl 및 kwok 설치 확인
kwokctl --version && kwok --version
설치를 완료했으니 kwokctl과 kwok의 버전을 확인해보겠습니다.
KWOK Cluster 생성
kubeconfig 생성 및 환경 변수 설정
touch ~/.kube/config-kwok
export KUBECONFIG=~/.kube/config-kwok
실제로 업무에 사용하고 있는 config 파일과 충돌되지 않게 새롭게 config-kwok 파일을 생성하여 해당 파일에서 kwok cluster를 구성하도록 하겠습니다. (물론 context가 추가될 뿐이지만 혹시나 모를 상황에 대비해 config 파일을 따로 생성하겠습니다.)
kwok cluster 생성
kwokctl create cluster --name=kwok
처음 kwok cluster를 생성할 때는 etcd, kube-apiserver, kube-controller-manager 등 필요한 바이너리를 다운로드해야 하기 때문에 시간이 좀 걸릴 수 있습니다.(한 번 다운로드하면 이후 캐싱되어 클러스터 생성 속도는 훨씬 빨라집니다.)
kwok cluster 확인
kubectl cluster-info
kwokctl get clusters
KWOK로 Node 및 Pod 생성
node 생성
KWOK를 통해 생성된 cluster에 Node를 생성해 보겠습니다.
kubectl apply -f - <<EOF
apiVersion: v1
kind: Node
metadata:
annotations:
node.alpha.kubernetes.io/ttl: "0"
kwok.x-k8s.io/node: fake # 이 노드가 KWOK을 이용한 가짜(Fake) 노드임을 명시
labels:
beta.kubernetes.io/arch: amd64
beta.kubernetes.io/os: linux
kubernetes.io/arch: amd64
kubernetes.io/hostname: kwok-node-0 # 호스트 이름을 kwok-node-0으로 설정
kubernetes.io/os: linux
kubernetes.io/role: agent # 이 노드가 에이전트 역할을 수행하도록 지정
node-role.kubernetes.io/agent: ""
type: kwok # KWOK에서 생성된 노드임을 명시
name: kwok-node-0
spec:
taints: # 이 노드는 실제 애플리케이션을 실행하지 않고, 오직 시뮬레이션 용도로만 사용
- effect: NoSchedule
key: kwok.x-k8s.io/node
value: fake
status:
# 실제로는 KWOK을 이용한 가짜 노드이므로, 실제 CPU나 메모리는 사용되지 않음
allocatable:
cpu: 32
memory: 256Gi
pods: 110
capacity:
cpu: 32
memory: 256Gi
pods: 110
nodeInfo:
architecture: amd64
bootID: ""
containerRuntimeVersion: ""
kernelVersion: ""
kubeProxyVersion: fake
kubeletVersion: fake
machineID: ""
operatingSystem: linux
osImage: ""
systemUUID: ""
phase: Running
EOF
주석으로 설명을 달아 놓긴 했았기 때문에 간략하게 살펴보겠습니다.
- annotations.kwok.x-k8s.io/node: fake 설정 -> 이 노드가 KWOK을 이용한 가짜(Fake) 노드임을 명시합니다.
- labels.kubernetes.io/hostname: kwok-node-0 -> 호스트 이름을 kwok-node-0으로 설정하였습니다.
- labels.kubernetes.io/role: agent → 이 노드가 에이전트 역할을 수행하도록 지정합니다.
- spec.taints ->실제 애플리케이션을 실행하지 않고, 오직 시뮬레이션 용도로만 사용합니다.
- status : 메모리 및 리소스 할당 -> 실제로는 KWOK을 이용한 가짜 노드이므로, 실제 CPU나 메모리는 사용되지 않습니다.
node 생성 확인
kubectl get node -o wide
노드를 생성한 후, kubectl을 사용하여 생성된 노드의 상태를 확인합니다.
Pod 생성
노드가 생성되었으니 기본 네임스페이스(default)에 fake-pod라는 Deployment를 생성해 보겠습니다.
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: fake-pod
namespace: default
spec:
replicas: 10 # 총 10개의 Pod 복제본(레플리카)을 생성
selector:
matchLabels:
app: fake-pod # 라벨 지정
template:
metadata:
labels:
app: fake-pod
spec:
affinity:
nodeAffinity: # KWOK으로 생성된 노드에서만 Pod가 스케줄링됨
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- kwok
tolerations: # 설정된 가짜 노드에서 Pod가 실행
- key: "kwok.x-k8s.io/node"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: fake-container
image: fake-image
EOF
총 10개의 Pod가 app: fake-pod라는 label이 붙어 띄어지며, nodeAffinity 설정으로 인해 KWOK로 생성된 node에서만 Pod가 스케줄링되고 tolerations를 통해 fake node에서만 Pod가 실행됩니다.
Pod 확인
kubectl get pod -o wide
모든 Pod가 kwok-node-0 노드에 생성된 것을 확인하실 수 있습니다.
kwok로 생성한 cluster 삭제
kwokctl delete cluster --name kwok
다음 실습을 위해 kwok라는 이름으로 생성한 cluster를 삭제하도록 하겠습니다.
Horizontal pod autoscaling 실습
KWOK를 사용하면 Metric Server를 배포하여 Horizontal Pod Autoscaler를 관찰하고 트리거할 수 있습니다.
KWOK Cluster 생성
metrics-usage 파일 다운로드
wget https://github.com/kubernetes-sigs/kwok/releases/download/v0.6.0/metrics-usage.yaml
위 파일은 Pod 및 Node의 리소스 사용량과 Metric을 시뮬레이션하는 설정 파일인데, 클러스터 리소스 사용량을 정의해놓은 부분과 클러스터 메트릭 데이터 제공하는 부분으로 나뉘어 있습니다.
ClusterResourceUsage
apiVersion: kwok.x-k8s.io/v1alpha1
kind: ClusterResourceUsage
metadata:
name: usage-from-annotation
spec:
usages:
- usage:
cpu:
expression: |
"kwok.x-k8s.io/usage-cpu" in pod.metadata.annotations
? Quantity(pod.metadata.annotations["kwok.x-k8s.io/usage-cpu"])
: Quantity("1m")
memory:
expression: |
"kwok.x-k8s.io/usage-memory" in pod.metadata.annotations
? Quantity(pod.metadata.annotations["kwok.x-k8s.io/usage-memory"])
: Quantity("1Mi")
Pod의 annotation에 설정된 값이 kwok.x-k8s.io/usage-cpu 이거나 kwok.x-k8s.io/usage-memory 일 경우 각각 명시된 리소스 사용량을 설정합니다.
Metric
apiVersion: kwok.x-k8s.io/v1alpha1
kind: Metric
metadata:
name: metrics-resource
spec:
metrics:
- dimension: node
name: scrape_error
kind: gauge
value: "0"
Kubernetes의 Node, Pod, Container 수준에서 리소스 사용량을 시뮬레이션하는 메트릭을 정의하는 부분으로 Prometheus와 같은 Metric 수집기로 수집할 수 있게 /metrics/nodes/{nodeName}/metrics/resource 엔드포인트 생성합니다.
#노드에서 소비된 CPU 시간(누적)
- dimension: node
name: node_cpu_usage_seconds_total
value: node.CumulativeUsage("cpu")
# 노드에서 현재 사용 중인 메모리량
- dimension: node
name: node_memory_working_set_bytes
value: node.Usage("memory")
# Pod에서 소비된 CPU 시간(누적)
- dimension: pod
name: pod_cpu_usage_seconds_total
value: pod.CumulativeUsage("cpu")
# Pod에서 현재 사용 중인 메모리량
- dimension: pod
name: pod_memory_working_set_bytes
value: pod.Usage("memory")
# 특정 컨테이너의 CPU 사용량
- dimension: container
name: container_cpu_usage_seconds_total
value: pod.CumulativeUsage("cpu", container.name)
# 특정 컨테이너의 메모리 사용량
- dimension: container
name: container_memory_working_set_bytes
value: pod.Usage("memory", container.name)
Cluster 생성
kwokctl create cluster --name=metric-kwok --enable-metrics-server --config ./metrics-usage.yaml
위에서 다운로드한 metric-usage.yaml 파일을 --config 옵션으로 지정하여 KWOK 클러스터의 설정 파일로 지정합니다. 또한 --enable-metrics-server 옵션을 추가하여, KWOK 클러스터 내부에서 Metrics Server가 활성화되도록 합니다.
이때 Metrics Server는 Docker 컨테이너로 실행되며, Kubernetes 클러스터 내에서 CPU 및 메모리 사용량을 확인할 수 있는
kubectl top nodes이나 kubectl top pods 명령어를 사용할 수 있게 됩니다.
Cluster 생성 확인
kwokctl get clusters
Node 생성
kwokctl scale node --replica 1 --name=metric-kwok
Node 생성 확인
kubectl get node
Pod 생성
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: fake-app
spec:
replicas: 1
selector:
matchLabels:
app: fake-app
template:
metadata:
labels:
app: fake-app
annotations:
kwok.x-k8s.io/usage-cpu: 200m
spec:
containers:
- name: fake-container
image: fake
ports:
- containerPort: 80
resources:
requests:
cpu: 1000m
limits:
cpu: 1200m
EOF
fake-app이라는 Deployment를 생성합니다. 이 Deploy의 Pod는 CPU 사용량이 200m이고, request.cpu는 1000m(1 Core), limit.cpu는 1200m 정도입니다.
# HPA 사용률 백분율 = (현재 CPU 사용률 / CPU 요청) * 100)
(200/1000) * 100 ≈ 20%
즉, HPA를 구성하기 위해 HPA 사용률을 구하면 현재 20%의 사용률인 상황입니다.
Metric 수집
sleep 50
위의 명령어를 실행하여 Metric Server가 Pod의 Metric을 수집할 시간을 기다립니다.
Pod의 Metric 확인
kubectl top pod
top 명령여를 통해 수집된 Pod의 metric을 확인해 보겠습니다.
설정한 대로 CPU가 200m을 사용하고 있는 것을 확인하실 수 있습니다. (위의 Pod 명세 파일에서 kwok.x-k8s.io/usage-cpu 만 설정해 두었기 때문에 CPU 사용률만 체크)
HPA 배포
kubectl apply -f - << EOF
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: pod-auto-scaler
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: fake-app
minReplicas: 1
maxReplicas: 2
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 1
scaleDown:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 1
EOF
위 yaml 파일은 Pod의 CPU 사용량을 기준으로 자동으로 replicas를 조정하는 HPA 설정 파일입니다.
설정 파일의 내용을 자세히 살펴보겠습니다.
...
spec:
minReplicas: 1
maxReplicas: 2
...
CPU 부하에 따라 Pod 개수를 1~2개 사이에서 조절합니다.
...
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
...
평균 CPU 사용률(averageUtilization)이 70%를 넘으면 스케일 아웃하고, 70% 미만이면 스케일 다운하게끔 설정합니다.
...
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 1
scaleDown:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 1
...
scaleUp일 때는 위의 HPA 조건인 CPU 사용량을 1초마다 검토( periodSeconds: 1 )하면서 해당된다면 즉시 반응( stabilizationWindowSeconds:0 ) 하여 현재 레플리카 개수의 100%만큼 증가(1->2)하며, scaleDown일 때 마찬가지로 HPA 조건을 1초마다 검토하면서 HPA 조건에 즉시 반응하여 현재 레플리카 개수의 100%만큼 감소(2->1)합니다.
Metric 수집
sleep 5
HPA가 Metric 수집하기 위해 5초 정도 sleep 합니다.
HPA 확인
kubectl get hpa
scaleUp 전에 HPA를 확인해 보겠습니다.
pod-auto-scaler라는 HPA는 fake-app이라는 Deployment에 설정되어 있으며, cpu 사용량이 70%가 되면 동작하고 현재 Replicas는 1인 것을 확인하실 수 있습니다.
Pod의 Metric 임의로 수정 (CPU 사용률 증가)
POD_NAME=$(kubectl top pods | awk 'NR>1 {print $1}')
위 명령어를 통해 POD_NAME 환경 변수에 kubectl top pods 로 첫 번째 실행 중인 Pod의 이름을 지정합니다.
kubectl patch pod $POD_NAME --type=json -p='[{"op":"add","path":"/metadata/annotations","value":{"kwok.x-k8s.io/usage-cpu":"800m"}}]'
그 후 kubectl patch를 사용하여 해당 Pod의 kwok.x-k8s.io/usage-cpu 값을 800m로 설정합니다.
Metric 수집
sleep 30
Metric Server가 Pod의 Metric을 수집할 시간을 기다립니다.
HPA 이벤트 확인
kubectl get hpa
hpa 정보를 확인해 보겠습니다.
설정한 CPU 사용률에 의해 현재 replicas가 2로 된 것을 확인하실 수 있습니다.
kubectl describe hpa
hpa의 상세 정보를 확인해 보겠습니다.
kubectl describe hpa | awk '/Events:/ {found=1} found {print}' | tail -n 1
hpa의 상세 정보 중 Events란의 내용을 확인해 보도록 하겠습니다.
정상적으로 HPA가 동작하여 Pod의 개수를 조정했으며, CPU 사용률이 target보다 높아서 HPA가 Pod을 자동으로 확장(Scale Up) 한 것을 알 수 있습니다.
Pod의 Metric 임의로 수정 (CPU 사용률 감소)
kubectl patch pod $POD_NAME --type=json -p='[{"op":"add","path":"/metadata/annotations","value":{"kwok.x-k8s.io/usage-cpu":"200m"}}]'
kubectl patch를 사용하여 Pod의 kwok.x-k8s.io/usage-cpu 값을 200m로 설정합니다.
Metric 수집
sleep 30
HPA 이벤트 확인
kubectl get hpa
hpa 정보를 확인해 보겠습니다.
target으로 현재 cpu 사용량이 20%로 줄었으며 Replicas도 1로 조정된 것을 확인하실 수 있습니다.
kubectl describe hpa
hpa의 상세 정보를 확인해 보겠습니다.
hpa 상세정보를 보면 hpa가 동작한 것을 확인하실 수 있는데, 이 중 Events 탭을 자세히 보도록 하겠습니다.
kubectl describe hpa | awk '/Events:/ {found=1} found {print}' | tail -n 1
HPA가 정상적으로 작동하고 있으며, CPU 사용률이 낮아져서 Pod 개수를 줄인 것을 확인하실 수 있습니다.
참고
https://kubernetes.io/blog/2023/03/01/introducing-kwok/
Introducing KWOK: Kubernetes WithOut Kubelet
Have you ever wondered how to set up a cluster of thousands of nodes just in seconds, how to simulate real nodes with a low resource footprint, and how to test your Kubernetes controller at scale without spending much on infrastructure? If you answered "ye
kubernetes.io
Home
KWOK (Kubernetes WithOut Kubelet) # KWOK is pronounced as /kwɔk/. KWOK is a toolkit that enables setting up a cluster of thousands of Nodes in seconds. Under the scene, all Nodes are simulated to behave like real ones, so the overall approach employs a pr
kwok.sigs.k8s.io
https://kwok.sigs.k8s.io/docs/technical-outcomes/scalability/scale-using-hpa/
Horizontal Pod Autoscaling
Horizontal pod autoscaling # Using KWOK, we can deploy a metric server to help us observe and trigger our HorizontalPodAutoscaler. This image shows you what you should expect when testing this scenario. You can follow the step-by-step guide after seeing th
kwok.sigs.k8s.io
'스터디 이야기 > 25' AWS EKS' 카테고리의 다른 글
AWS EKS의 AutoMode (0) | 2025.03.21 |
---|---|
EKS에서 ConfigMap 없이 API로 접근 관리하기(Cluster Access Management) (2) | 2025.03.14 |
OpenTelemetry를 활용한 이슈 분석 및 해결 (feat. OTel Demo) (0) | 2025.03.01 |
모니터링 vs 관측가능성, 그리고 SLI·SLO·SLA (0) | 2025.02.28 |