| EKS 환경에서 활용할 수 있는 다양한 오토스케일링 방법에 대해 포스팅합니다.
0. 실습환경 세팅
EKS Node Viewer 설치
노드 할당 가능 용량과 요청 request 리소스 보여줍니다.(실제 파드 리소스 사용량 X)
# go 설치
wget https://go.dev/dl/go1.22.1.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.22.1.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version
go version go1.22.1 linux/amd64
# EKS Node Viewer 설치 : 약 2분 이상 소요
go install github.com/awslabs/eks-node-viewer/cmd/eks-node-viewer@latest
# [신규 터미널] EKS Node Viewer 접속
cd ~/go/bin && ./eks-node-viewer
혹은
cd ~/go/bin && ./eks-node-viewer --resources cpu,memory
명령 샘플
# Standard usage
./eks-node-viewer
# Display both CPU and Memory Usage
./eks-node-viewer --resources cpu,memory
# Karenter nodes only
./eks-node-viewer --node-selector "karpenter.sh/provisioner-name"
# Display extra labels, i.e. AZ
./eks-node-viewer --extra-labels topology.kubernetes.io/zone
# Specify a particular AWS profile and region
AWS_PROFILE=myprofile AWS_REGION=us-west-2
기본 옵션
# select only Karpenter managed nodes
node-selector=karpenter.sh/provisioner-name
# display both CPU and memory
resources=cpu,memory
Prometheus-stack 설치
스케일링 모니터링 실습을 위해 필요한 설정을 추가하여 설치합니다.
verticalPodAutoscaler.enabled: true
kube-state-metrics.customResourceState
# 사용 리전의 인증서 ARN 확인
CERT_ARN=`aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text`
echo $CERT_ARN
# repo 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# 파라미터 파일 생성 : PV/PVC(AWS EBS) 삭제에 불편하니, 4주차 실습과 다르게 PV/PVC 미사용
cat <<EOT > monitor-values.yaml
prometheus:
prometheusSpec:
podMonitorSelectorNilUsesHelmValues: false
serviceMonitorSelectorNilUsesHelmValues: false
retention: 5d
retentionSize: "10GiB"
verticalPodAutoscaler:
enabled: true
ingress:
enabled: true
ingressClassName: alb
hosts:
- prometheus.$MyDomain
paths:
- /*
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/ssl-redirect: '443'
grafana:
defaultDashboardsTimezone: Asia/Seoul
adminPassword: prom-operator
defaultDashboardsEnabled: false
ingress:
enabled: true
ingressClassName: alb
hosts:
- grafana.$MyDomain
paths:
- /*
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/ssl-redirect: '443'
kube-state-metrics:
rbac:
extraRules:
- apiGroups: ["autoscaling.k8s.io"]
resources: ["verticalpodautoscalers"]
verbs: ["list", "watch"]
prometheus:
monitor:
enabled: true
customResourceState:
enabled: true
config:
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: autoscaling.k8s.io
kind: "VerticalPodAutoscaler"
version: "v1"
labelsFromPath:
verticalpodautoscaler: [metadata, name]
namespace: [metadata, namespace]
target_api_version: [apiVersion]
target_kind: [spec, targetRef, kind]
target_name: [spec, targetRef, name]
metrics:
- name: "vpa_containerrecommendations_target"
help: "VPA container recommendations for memory."
each:
type: Gauge
gauge:
path: [status, recommendation, containerRecommendations]
valueFrom: [target, memory]
labelsFromPath:
container: [containerName]
commonLabels:
resource: "memory"
unit: "byte"
- name: "vpa_containerrecommendations_target"
help: "VPA container recommendations for cpu."
each:
type: Gauge
gauge:
path: [status, recommendation, containerRecommendations]
valueFrom: [target, cpu]
labelsFromPath:
container: [containerName]
commonLabels:
resource: "cpu"
unit: "core"
selfMonitor:
enabled: true
alertmanager:
enabled: false
EOT
cat monitor-values.yaml | yh
# 배포
kubectl create ns monitoring
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 57.2.0 \
--set prometheus.prometheusSpec.scrapeInterval='15s' --set prometheus.prometheusSpec.evaluationInterval='15s' \
-f monitor-values.yaml --namespace monitoring
# Metrics-server 배포
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 프로메테우스 ingress 도메인으로 웹 접속
echo -e "Prometheus Web URL = https://prometheus.$MyDomain"
# 그라파나 웹 접속 : 기본 계정 - admin / prom-operator
echo -e "Grafana Web URL = https://grafana.$MyDomain"
1. HPA - Horizontal Pod Autoscaler
Kubernetes
에서 제공하는 자동 스케일링 기능 중 하나입니다.- 애플리케이션 부하에 따라 Pod인스턴스의 수를 동적으로 조정합니다.
- 리소스의 효율 적 사용
- 응답시간 유지
HPA 실습
| php 웹 서버를 배포하여 HPA를 적용하고 파드가 과부하될 때, 자동으로 오토스케일링 되는지 확인해 봅니다.
php 웹 서버를 디플로이먼트를 배포합니다. 부하 테스트를 위해 단순 계산식을 반복하는 웹 서버입니다.
cat << EOT > php-apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
EOT
kubectl apply -f php-apache.yaml
# 확인
kubectl exec -it deploy/php-apache -- cat /var/www/html/index.php
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK!";
?>
모니터링을 위해 그라파나 HPA 대시보드를 사용합니다.
HPA 생성하고 및 부하 발생 후 오토 스케일링 테스트합니다.
- 파드 기본 대기 시(필요에 따라 조정이 가능합니다.)
- 증가 시, 30초
- 감소 시, 5분
# Create the HorizontalPodAutoscaler : requests.cpu=200m - 알고리즘
# Since each pod requests 200 milli-cores by kubectl run, this means an average CPU usage of 100 milli-cores.
kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
kubectl describe hpa
...
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): 0% (1m) / 50%
Min replicas: 1
Max replicas: 10
Deployment pods: 1 current / 1 desired
...
# HPA 설정 확인
kubectl get hpa php-apache -o yaml | kubectl neat | yh
spec:
minReplicas: 1 # [4] 또는 최소 1개까지 줄어들 수도 있습니다
maxReplicas: 10 # [3] 포드를 최대 5개까지 늘립니다
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache # [1] php-apache 의 자원 사용량에서
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # [2] CPU 활용률이 50% 이상인 경우
# 반복 접속 1 (파드1 IP로 접속) >> 증가 확인 후 중지
while true;do curl -s $PODIP; sleep 0.5; done
# 반복 접속 2 (서비스명 도메인으로 접속) >> 증가 확인(몇개까지 증가되는가? 그 이유는?) 후 중지 >> 중지 5분 후 파드 갯수 감소 확인
# Run this in a separate terminal
# so that the load generation continues and you can carry on with the rest of the steps
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
파드의 요청된 사용 cpu가 50% 이상 넘어가면 파드가 HPA의 해 오토스케일링 됩니다.
그라파나 HPA 대시보드에서도 반영됨을 확인할 수 있습니다.
다음 실습을 위해 사용 리소스를 삭제합니다.kubectl delete deploy, svc, hpa, pod --all
2. KEDA - Kubernetes based Event Driven Autoscaler
HPA의 문제점
기존의 HPA(Horizontal Pod Autoscaler)는 리소스(CPU, Memory) 메트릭을 기반으로 스케일 여부를 결정하게 됩니다
반면에 KEDA는 특정 이벤트를 기반으로 스케일 여부를 결정할 수 있습니다.
특정 이벤트를 기반을 예로 들면, Kafka 메시지를 수신할 때, Postgres의 부하가 늘어날 때라던지, ** 다양한 Scaler의
이벤트 기반**으로 오토스케일링할 수 있습니다.
Keda 설치
helm chart로 keda를 설치합니다.
# KEDA 설치
cat <<EOT > keda-values.yaml
metricsServer:
useHostNetwork: true
prometheus:
metricServer:
enabled: true
port: 9022
portName: metrics
path: /metrics
serviceMonitor:
# Enables ServiceMonitor creation for the Prometheus Operator
enabled: true
podMonitor:
# Enables PodMonitor creation for the Prometheus Operator
enabled: true
operator:
enabled: true
port: 8080
serviceMonitor:
# Enables ServiceMonitor creation for the Prometheus Operator
enabled: true
podMonitor:
# Enables PodMonitor creation for the Prometheus Operator
enabled: true
webhooks:
enabled: true
port: 8080
serviceMonitor:
# Enables ServiceMonitor creation for the Prometheus webhooks
enabled: true
EOT
kubectl create namespace keda
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --version 2.13.0 --namespace keda -f keda-values.yaml
# KEDA 설치 확인
kubectl get all -n keda
kubectl get validatingwebhookconfigurations keda-admission
kubectl get validatingwebhookconfigurations keda-admission | kubectl neat | yh
kubectl get crd | grep keda
Keda 실습
| ScaledObject
를 생성하고, keda를 통해 디플로이먼트를 스케일링합니다.
스케일링 대상으로 사용할 php-apache 디플로이먼트를 생성합니다.
cat << EOF > php-apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
EOF
kubectl apply -f php-apache.yaml -n keda
ScaledObject 정책 생성
KEDA를 사용하여 자동으로 스케일링할 대상을 정의합니다. 간단한 실습을 위해 트리거는 Cron으로 설정하여 매시, 00,15,30,45분마다 디플로이먼트가 스케일링하도록 합니다.
# ScaledObject 정책 생성 : cron
cat <<EOT > keda-cron.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: php-apache-cron-scaled
spec:
minReplicaCount: 0
maxReplicaCount: 2
pollingInterval: 30
cooldownPeriod: 300
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
triggers:
- type: cron
metadata:
timezone: Asia/Seoul
start: 00,15,30,45 * * * *
end: 05,20,35,50 * * * *
desiredReplicas: "1"
EOT
kubectl apply -f keda-cron.yaml -n keda
스케일링 모니터링
약간의 딜레이 시간이 있지만, 매시, 15분에 디플로이먼트가 스케일링되는 것을 볼 수 있습니다.
3. VPA - Vertical Pod Autoscaler
- HPA와는 반대로 파드의 수가 아닌, 요청 스펙을 스케일링합니다.
- Pod의 리소스 요청과 제한 (
resource.requests, limits
)을 최대한 동적으로 조정하여 최적의 성능을 유지합니다.
- Pod의 리소스 요청과 제한 (
- 요청 리소스가 변하게 되면 파드는 재실행됩니다(immutable)
- HPA와는 동시에 사용할 수 없습니다.
VPA 실습
| VPA를 통해, 요청 사용량에 따라 파드의 요청 스펙이 스케일링되는지 확인합니다.
VPA 예제 실습 코드
# 코드 다운로드
git clone https://github.com/kubernetes/autoscaler.git
cd ~/autoscaler/vertical-pod-autoscaler/
tree hack
# openssl 버전 확인
openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
# openssl 1.1.1 이상 버전 확인
yum install openssl11 -y
openssl11 version
OpenSSL 1.1.1g FIPS 21 Apr 2020
# 스크립트파일내에 openssl11 수정
sed -i 's/openssl/openssl11/g' ~/autoscaler/vertical-pod-autoscaler/pkg/admission-controller/gencerts.sh
# Deploy the Vertical Pod Autoscaler to your cluster with the following command.
watch -d kubectl get pod -n kube-system
cat hack/vpa-up.sh
./hack/vpa-up.sh
kubectl get crd | grep autoscaling
kubectl get mutatingwebhookconfigurations vpa-webhook-config
kubectl get mutatingwebhookconfigurations vpa-webhook-config -o json | jq
VPA 실습 모니터링
사용량에 따라 파드가 재기동되며 요청 리소스가 변경됨을 볼 수 있습니다.
vpa 커스텀리소스
실습환경설정에서 추가 설정한 프로메테우스의 customresource를 통해서 메트릭을 수집하기 때문에, VPA 그라파나 대시보드를 통해서도 확인할 수 있습니다.
kube_customresource_vpa_containerrecommendations_target{resource="cpu"}
kube_customresource_vpa_containerrecommendations_target{resource="memory"}
그라파나 대시보드
4. CA - Cluster Autoscaler
- 파드가 아닌 노드가 스케일링 대상의 기준으로, 노드의 수를 동적으로 조절하여 클러스터의 리소스 사용량에 맞게 확장하거나 축소하는 기능을 제공하는 컴포넌트입니다.
- 파드(Pod)가 스케줄링될 수 있는 노드의 여유 공간을 모니터링하고, 리소스 부족 시 새로운 노드를 자동으로 추가하거나 더 이상 필요하지 않은 노드를 자동으로 제거하여 클러스터의 효율성과 가용성을 최적화합니다.
- 이를 통해 클러스터의 관리를 단순화하고 리소스를 효율적으로 활용할 수 있습니다
CA 설치
Cluster Autoscaler(CA)의 스케일링 노드 대상에는 사전설정 필요합니다.
EKS의 경우에는, 아래 태그의 키 값이 설정되어야 합니다.
CA 디플로이먼트를 배포합니다.
curl -s -O https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
sed -i "s/<YOUR CLUSTER NAME>/$CLUSTER_NAME/g" cluster-autoscaler-autodiscover.yaml
kubectl apply -f cluster-autoscaler-autodiscover.yaml
# 확인
kubectl get pod -n kube-system | grep cluster-autoscaler
kubectl describe deployments.apps -n kube-system cluster-autoscaler
kubectl describe deployments.apps -n kube-system cluster-autoscaler | grep node-group-auto-discovery
--node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/myeks
# (옵션) cluster-autoscaler 파드가 동작하는 워커 노드가 퇴출(evict) 되지 않게 설정
kubectl -n kube-system annotate deployment.apps/cluster-autoscaler cluster-autoscaler.kubernetes.io/safe-to-evict="false"
CA 실습
| CA를 통해 , 노드의 리소스 사용량에 따라, 노드가 스케일링되는지 확인합니다.
요청 리소스를 정의한 디플로이먼트를 배포합니다.
- cpu : 500m
- memory: 512Mi
# Deploy a Sample App
# We will deploy an sample nginx application as a ReplicaSet of 1 Pod
cat <<EoF> nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-to-scaleout
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
service: nginx
app: nginx
spec:
containers:
- image: nginx
name: nginx-to-scaleout
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 500m
memory: 512Mi
EoF
kubectl apply -f nginx.yaml kubectl get deployment/nginx-to-scaleout
스케일링 테스트
디플로이먼트의 레플리카 수를 15개로 늘려서 노드가 자동으로 증가되는지(scale out)를 확인합니다.
5. CPA - Cluster Proportional Autoscaler
- 노드 수 증가에 비례하여 성능 처리가 필요한 애플리케이션(컨테이너/파드)을 수평으로 자동 확장합니다.
CPA 설치
- CPA 규칙을 설정합니다.
nodesToReplicas
는 노드 수에 대한 파드의 수입니다.- coredns와 같이 노드 수의 비례하여 성능이 필요한 애플리케이션에 적합합니다.
coresToReplicas
(CPU/Memory 기반 정책)도 지원합니다.
cat <<EOT > cpa-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
cpu: "100m"
memory: "64Mi"
requests:
cpu: "100m"
memory: "64Mi"
ports:
- containerPort: 80
EOT
kubectl apply -f cpa-nginx.yam
CPA 실습
CPA를 통해, 노드의 수의 비례하여 대상 디플로이먼트가 증가하는지 확인합니다.
먼저, 대상 디플로이먼트를 배포합니다.
cat <<EOT > cpa-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
cpu: "100m"
memory: "64Mi"
requests:
cpu: "100m"
memory: "64Mi"
ports:
- containerPort: 80
EOT
kubectl apply -f cpa-nginx.yam
CPA 규칙 설정에 따라, 노드가 5개일 경우에, 파드가 5개로 증가되는 것을 볼 수 있습니다.
6. Karpenter : K8S Native AutoScaler
- 클러스터 내에서 노드에 대한 라이프사이클을 관리하는 서비스 이는 클러스터의 리소스
- 몇 초 만에 컴퓨팅 리소스 제공
- CA(Cluster Autoscaler)의 단점을 보완
Karpenter 설치
Karpenter의 버전이 올라가면서 api가 변경되었습니다.
- v1 alpha5/Provisioner → v1 beta1/NodePool
- v1 alpha1/AWSNodeTemplate → v1 beta1/EC2 NodeClass
- v1 alpha5/Machine → v1 beta1/NodeClaim
# Karpenter 설치를 위한 변수 설정 및 확인
export CLUSTER_ENDPOINT="$(aws eks describe-cluster --name "${CLUSTER_NAME}" --query "cluster.endpoint" --output text)"
export KARPENTER_IAM_ROLE_ARN="arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:role/${CLUSTER_NAME}-karpenter"
echo "${CLUSTER_ENDPOINT} ${KARPENTER_IAM_ROLE_ARN}"
# EC2 Spot Fleet의 service-linked-role 생성 확인 : 만들어있는것을 확인하는 거라 아래 에러 출력이 정상!
# If the role has already been successfully created, you will see:
# An error occurred (InvalidInput) when calling the CreateServiceLinkedRole operation: Service role name AWSServiceRoleForEC2Spot has been taken in this account, please try a different suffix.
aws iam create-service-linked-role --aws-service-name spot.amazonaws.com || true
# docker logout : Logout of docker to perform an unauthenticated pull against the public ECR
docker logout public.ecr.aws
# helm registry logout
helm registry logout public.ecr.aws
# karpenter 설치
helm install karpenter oci://public.ecr.aws/karpenter/karpenter --version "${KARPENTER_VERSION}" --namespace "${KARPENTER_NAMESPACE}" --create-namespace \
--set "serviceAccount.annotations.eks\.amazonaws\.com/role-arn=${KARPENTER_IAM_ROLE_ARN}" \
--set "settings.clusterName=${CLUSTER_NAME}" \
--set "settings.interruptionQueue=${CLUSTER_NAME}" \
--set controller.resources.requests.cpu=1 \
--set controller.resources.requests.memory=1Gi \
--set controller.resources.limits.cpu=1 \
--set controller.resources.limits.memory=1Gi \
--wait
# 확인
kubectl get-all -n $KARPENTER_NAMESPACE
kubectl get all -n $KARPENTER_NAMESPACE
kubectl get crd | grep karpenter
nodepool과
ec2 nodeclass를
생성합니다. 스케일링할 노드에 대한 템플릿을 내용을 정의합니다.
cat <<EOF | envsubst | kubectl apply -f -
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: kubernetes.io/os
operator: In
values: ["linux"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["2"]
nodeClassRef:
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
name: default
limits:
cpu: 1000
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720h # 30 * 24h = 720h
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2 # Amazon Linux 2
role: "KarpenterNodeRole-${CLUSTER_NAME}" # replace with your cluster name
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "${CLUSTER_NAME}" # replace with your cluster name
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "${CLUSTER_NAME}" # replace with your cluster name
amiSelectorTerms:
- id: "${ARM_AMI_ID}"
- id: "${AMD_AMI_ID}"
# - id: "${GPU_AMI_ID}" # <- GPU Optimized AMD AMI
# - name: "amazon-eks-node-${K8S_VERSION}-*" # <- automatically upgrade when a new AL2 EKS Optimized AMI is released. This is unsafe for production workloads. Validate AMIs in lower environments before deploying them to production.
EOF
# 확인
kubectl get nodepool,ec2nodeclass
Karpenter 실습
카펜터를 통해 리소스 사용량에 따라, 노드가 빠르게 스케줄링되는지를 실습합니다.
먼저, 실습을 위해요청 리소스 사용량이 높은 deployment을 배포합니다.
# pause 파드 1개에 CPU 1개 최소 보장 할당
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 0
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
terminationGracePeriodSeconds: 0
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
resources:
requests:
cpu: 1
EOF
Karpenter 실습 모니터링
디플로이먼트의 레플리카 수가 5개로 증가하면서 노드가 스케일 아웃되는 것을 확인할 수 있습니다. 파드의 pending 상태가 약 40초가 정도 되지 않아, 스케일링됨으로 빠른 스케줄링 기능을 확인 할 수 있습니다.
Disruption - spot to spot consolidation
- 카펜터에서 최적화를 제공하는 기능입니다.(구 Consolidation)
- Disruption의 종류
- Expiration
- 기본 720시간(30일) 후 인스턴스를 자동으로 만료하여 강제로 노드를 최신 상태로 유지
- drift
- 구성 변경 사항(NodePool, EC2 NodeClass)을 감지하여 필요한 변경 사항을 적용
- Consolidation
- 비용 효율적인 컴퓨팅 최적화
- Expiration
spot to spot consolidation란?
- 리소스 사용량을 계산하여 자동으로 적절한 스펙의 노드를 스케일링
- 최신 버전부터 on-demand 외에 추가적으로 spot instance를 지원
- 카펜터를 통해 EC2 API 직접 통신하여, 빠르게 스케일링
spot to spot consolidation 실습
spot to spot consolidation 사용을 위해 nodepool을 재구성합니다.
# 기존 nodepool 삭제
kubectl delete nodepool,ec2nodeclass default
# v0.34.0 부터 featureGates 에 spotToSpotConsolidation 활성화로 사용 가능
helm upgrade karpenter -n kube-system oci://public.ecr.aws/karpenter/karpenter --reuse-values --set settings.featureGates.spotToSpotConsolidation=true
# Create a Karpenter NodePool and EC2NodeClass
cat <<EOF > nodepool.yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
metadata:
labels:
intent: apps
spec:
nodeClassRef:
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c","m","r"]
- key: karpenter.k8s.aws/instance-size
operator: NotIn
values: ["nano","micro","small","medium"]
- key: karpenter.k8s.aws/instance-hypervisor
operator: In
values: ["nitro"]
limits:
cpu: 100
memory: 100Gi
disruption:
consolidationPolicy: WhenUnderutilized
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: Bottlerocket
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "${CLUSTER_NAME}" # replace with your cluster name
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "${CLUSTER_NAME}" # replace with your cluster name
role: "KarpenterNodeRole-${CLUSTER_NAME}" # replace with your cluster name
tags:
Name: karpenter.sh/nodepool/default
IntentLabel: "apps"
EOF
kubectl apply -f nodepool.yaml
부하 테스트를 위한 디플로이먼트를 생성합니다.
# Deploy a sample workload
cat <<EOF > inflate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 1
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
nodeSelector:
intent: apps
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
resources:
requests:
cpu: 1
memory: 1.5Gi
EOF
kubectl get nodes -L karpenter.sh/nodepool -L node.kubernetes.io/instance-type -L topology.kubernetes.io/zone -L karpenter.sh/capacity-type
# Scale in a sample workload to observe consolidation
# To invoke a Karpenter consolidation event scale, inflate the deployment to 1. Run the following command:
kubectl scale --replicas=1 deployment/inflate
kubectl -n kube-system logs -l app.kubernetes.io/name=karpenter --all-containers=true -f --tail=20
kubectl get nodes -L karpenter.sh/nodepool -L node.kubernetes.io/instance-type -L topology.kubernetes.io/zone -L karpenter.sh/capacity-type
kubectl get node --label-columns=eks.amazonaws.com/capacityType,karpenter.sh/capacity-type
kubectl get node --label-columns=node.kubernetes.io/instance-type,topology.kubernetes.io/zone
# Use kubectl get nodeclaims to list all objects of type NodeClaim and then describe the NodeClaim Kubernetes resource
# using kubectl get nodeclaim/<claim-name> -o yaml.
# In the NodeClaim .spec.requirements, you can also see the 15 instance types passed to the Amazon EC2 Fleet API:
kubectl get nodeclaims
NAME TYPE ZONE NODE READY AGE
default-w52c4 c6g.large ap-northeast-2d ip-192-168-77-172.ap-northeast-2.compute.internal True 3m8s
kubectl get nodeclaims -o yaml | kubectl neat | yh
....
spec:
nodeClassRef:
name: default
requirements:
- key: karpenter.sh/nodepool
operator: In
values:
- default
- key: node.kubernetes.io/instance-type
operator: In
values:
- c6g.large
- c6gd.large
- c6gn.large
- c6id.large
- c6in.large
- c7g.large
- c7i.large
- m6g.large
- m6gd.large
- m6i.large
- m7g.large
- m7i-flex.large
- m7i.large
- r6g.large
- r7g.large
spot 인스턴스 노드가 최적화된 인스턴스 타입의 스펙으로 스케일링됨을 확인할 수 있습니다.
리소스 삭제
# 삭제
kubectl delete deployment inflate
kubectl delete nodepool,ec2nodeclass default
'AWS > EKS' 카테고리의 다른 글
EKS CI/CD - AEWS 7주차 (1) | 2024.04.20 |
---|---|
EKS 보안(Security) - AEWS 6주차 (1) | 2024.04.14 |
EKS 옵저버빌리티(Obsivability) - AEWS 4주차 (0) | 2024.03.31 |
EKS 노드그룹(Nodegroup) - AEWS 3주차 2 (0) | 2024.03.23 |
EKS 스토리지(Storage) - AEWS 3주차 1 (0) | 2024.03.23 |