Home
home

5장 실습 - Karpenter 구성하기

1. 실습 기본 환경 구성

이번 실습은 5장의 Karpenter 구성하기 실습을 위해 기본 인프라 환경을 CloudFormation 스택으로 생성하고 eksctl로 Amazon EKS 클러스터 배포합니다.

1.1. Karpenter Preconfig 배포

해당 링크를 클릭하면 AWS CloudFormation 페이지로 연결되며, 파라미터를 입력 후 스택을 생성합니다.
Note: AWS 관리 콘솔에 로그인 할때 IAM 사용자 계정으로 진행합니다.
[관리 콘솔] CloudFormation 파라미터 설정
스택 생성 페이지에서 다음 버튼을 클릭합니다.
스택 이름은 [myeks2]로 입력합니다.
KeyName은 [각자의 키페어]를 선택합니다.
MyIAMUserAccessKeyID는 [각자의 액세스 키 ID 값]을 입력합니다.
MyIAMUserSecretAccessKey는 [각자의 시크릿 액세스 키 값]을 입력합니다.
SgIngressSshCidr는 [각자의 PC의 퍼블릭 IP 주소/32]로 입력합니다.
나머지 파라미터는 기본 값을 유지하고 다음 버튼을 클릭합니다.
Warning: 설정을 마치고 약 5분 정도 대기 시간이 흐른 뒤 기본 인프라 환경 생성이 완료됩니다. 반드시 해당 대기 시간이 지난 후 다음 작업을 수행합니다.

1.2. EKS 클러스터 생성

AWS CloudFormation 스택의 출력 탭에서 eksctlhost의 퍼블릭 IP를 확인합니다.
해당 IP로 EKS 관리용 인스턴스(myeks-bastion-EC2)에 SSH로 접속하고 아래 명령어를 통해 정보를 확인합니다.
환경 변수
export | egrep 'ACCOUNT|AWS_|CLUSTER' | egrep -v 'SECRET|KEY'
Bash
복사
# 환경 변수 정보 확인
export KARPENTER_VERSION=v0.30.0 export TEMPOUT=$(mktemp) echo $KARPENTER_VERSION; echo $CLUSTER_NAME; echo $AWS_DEFAULT_REGION; echo $AWS_ACCOUNT_ID $TEMPOUT
Bash
복사
# 환경 변수 설정 및 확인
Warning: CloudFormation 스택이 생성되고 환경 변수가 선언되기 전에 너무 빨리 접속하면 다시 접속합니다.
Karpenter 관련 IAM, EC2 Instance Profile 생성
curl -fsSL https://raw.githubusercontent.com/aws/karpenter/"${KARPENTER_VERSION}"/website/content/en/preview/getting-started/getting-started-with-karpenter/cloudformation.yaml > $TEMPOUT \ && aws cloudformation deploy \ --stack-name "Karpenter-${CLUSTER_NAME}" \ --template-file "${TEMPOUT}" \ --capabilities CAPABILITY_NAMED_IAM \ --parameter-overrides "ClusterName=${CLUSTER_NAME}"
Bash
복사
# CloudFormation 스택으로 IAM Policy, Role, EC2 Instance Profile 생성 (약 3분 소요)
Amazon EKS 클러스터 생성
eksctl create cluster -f - <<EOF --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ${CLUSTER_NAME} region: ${AWS_DEFAULT_REGION} version: "1.26" tags: karpenter.sh/discovery: ${CLUSTER_NAME} iam: withOIDC: true serviceAccounts: - metadata: name: karpenter namespace: karpenter roleName: ${CLUSTER_NAME}-karpenter attachPolicyARNs: - arn:aws:iam::${AWS_ACCOUNT_ID}:policy/KarpenterControllerPolicy-${CLUSTER_NAME} roleOnly: true iamIdentityMappings: - arn: "arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME}" username: system:node:{{EC2PrivateDNSName}} groups: - system:bootstrappers - system:nodes managedNodeGroups: - instanceType: m5.large amiFamily: AmazonLinux2 name: ${CLUSTER_NAME}-ng desiredCapacity: 2 minSize: 1 maxSize: 10 iam: withAddonPolicies: externalDNS: true EOF
Bash
복사
# EKS 클러스터 생성 : myeks2 생성 (약 19분 소요)

1.3. EKS 클러스터 확인 및 추가 설정

Default Namespace로 적용
kubectl ns default
Bash
복사
# Default Namespace로 위치 변경
EKS 클러스터 확인
eksctl get cluster
Bash
복사
# EKS 클러스터 정보 확인
eksctl get nodegroup --cluster $CLUSTER_NAME
Bash
복사
# EKS 클러스터 노드 그룹 확인
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
Bash
복사
# EKS 클러스터 iamidentitymapping 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
Bash
복사
# EKS 클러스터 irsa 확인
kubectl describe cm -n kube-system aws-auth
Bash
복사
# aws-auth의 Config Map 확인 (상세)
신규 터미널 - EKS Node Viewer 설치
go install github.com/awslabs/eks-node-viewer/cmd/eks-node-viewer@v0.5.0
Bash
복사
# EKS Node Viewer 설치 (약 2분 소요)
cd ~/go/bin && ./eks-node-viewer
Bash
복사
# EKS Node Viewer 접속
Warning: EKS Node Viewer 설치는 EKS 클러스터 생성을 완료한 후 작업합니다.
ExternalDNS 설치
MyDomain=<자신의 도메인> MyDnsHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text) echo $MyDomain, $MyDnsHostedZoneId curl -s -O https://raw.githubusercontent.com/cloudneta/cnaeblab/master/_data/externaldns.yaml MyDomain=$MyDomain MyDnsHostedZoneId=$MyDnsHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -
Bash
복사
# ExternalDNS 설치 (종합)
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 env.TZ="Asia/Seoul" --namespace kube-system kubectl patch svc -n kube-system kube-ops-view -p '{"spec":{"type":"LoadBalancer"}}' kubectl annotate service kube-ops-view -n kube-system "external-dns.alpha.kubernetes.io/hostname=kubeopsview.$MyDomain" echo -e "Kube Ops View URL = http://kubeopsview.$MyDomain:8080/#scale=1.5"
Bash
복사
# kube-ops-view 설치 (종합)

2. Karpenter 환경 구성

2.1. Karpenter 설치 및 확인

환경 변수 설정
export CLUSTER_ENDPOINT="$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output text)" export KARPENTER_IAM_ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT_ID}:role/${CLUSTER_NAME}-karpenter" echo $CLUSTER_ENDPOINT; echo $KARPENTER_IAM_ROLE_ARN
Bash
복사
# Karpenter 설치를 위한 환경 변수 설정 및 확인
EC2 Spot fleet의 server-linked-role 확인
aws iam create-service-linked-role --aws-service-name spot.amazonaws.com || true
Bash
복사
# EC2 Spot Fleet 사용을 위한 service-linked-role 생성 확인 (이미 생성됐다는 에러가 나와야 정상)
Note: 아래와 같은 문구가 나오면 정상입니다. An error occurred (InvalidInput) when calling the CreateServiceLinkedRole operation...
Warning: 만약 에러 메시지가 아닌 새롭게 생성하는 메시지가 나온다면 현재 어카운트에 해당 서비스 연결 역할(AWSServiceRoleForEC2Spot)이 존재하지 않는 것 입니다. 서비스 연결 역할 생성 후 다음 단계로 넘어가면 됩니다. 처음부터 다시 진행할 필요는 없습니다.
docker & public.ecr.aws - logout
docker logout public.ecr.aws
Bash
복사
# docker logout
helm registry logout public.ecr.aws
Bash
복사
# public ecr logout
Karpenter 설치
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter --version ${KARPENTER_VERSION} --namespace karpenter --create-namespace \ --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \ --set settings.aws.clusterName=${CLUSTER_NAME} \ --set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${CLUSTER_NAME} \ --set settings.aws.interruptionQueueName=${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
Bash
복사
# karpenter 설치 (helm)
Karpenter 설치 확인
kubectl get-all -n karpenter kubectl get all -n karpenter kubectl get cm -n karpenter karpenter-global-settings -o jsonpath={.data} | jq kubectl get crd | grep karpenter
Bash
복사
# karpenter 설치 확인

2.2. Provisioner 생성 및 확인

Provisioner와 AWSNodeTemplate 생성
cat <<EOF | kubectl apply -f - apiVersion: karpenter.sh/v1alpha5 kind: Provisioner metadata: name: default spec: requirements: - key: karpenter.sh/capacity-type operator: In values: ["spot"] limits: resources: cpu: 1000 providerRef: name: default ttlSecondsAfterEmpty: 30 --- apiVersion: karpenter.k8s.aws/v1alpha1 kind: AWSNodeTemplate metadata: name: default spec: subnetSelector: karpenter.sh/discovery: ${CLUSTER_NAME} securityGroupSelector: karpenter.sh/discovery: ${CLUSTER_NAME} EOF
Bash
복사
# Provisioner와 AWSNodeTemplate 정책을 정의하고 생성
Provisioner와 AWSNodeTemplate 확인
kubectl get awsnodetemplates,provisioners
Bash
복사
# awsnodetemplates, provisioners 확인

3. Karpenter 동작 확인

3.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
Bash
복사
# 테스트용 디플로이먼트 배포
kubectl get deploy
Bash
복사
# 테스트용 디플로이먼트 확인

3.2. Karpenter의 스케일링 확인

Scale-Out 확인
kubectl scale deployment inflate --replicas 5
Bash
복사
# replicas 수정 (replicas 0 -> 5)
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep provisioner
Bash
복사
# 로그 확인
kubectl get node --label-columns=eks.amazonaws.com/capacityType,karpenter.sh/capacity-type,node.kubernetes.io/instance-type
Bash
복사
# 스팟 인스턴스 확인
Scale-In 확인
kubectl delete deployment inflate; date date
Bash
복사
// 디플로이먼트 삭제 (ttlSecondsAfterEmpty 30초)
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep deprovisioning
Bash
복사
# 로그 확인

3.3. Karpenter의 Consolidation 확인

Provisioner 삭제
kubectl delete provisioners default
Bash
복사
# 기존 provisioner를 삭제
Provisioner 생성
cat <<EOF | kubectl apply -f - apiVersion: karpenter.sh/v1alpha5 kind: Provisioner metadata: name: default spec: consolidation: enabled: true labels: type: karpenter limits: resources: cpu: 1000 memory: 1000Gi providerRef: name: default requirements: - key: karpenter.sh/capacity-type operator: In values: - on-demand - key: node.kubernetes.io/instance-type operator: In values: - c5.large - m5.large - m5.xlarge EOF
Bash
복사
# 신규 provisioner 생성
디플로이먼트 배포
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
Bash
복사
# 테스트용 디플로이먼트 배포
kubectl get deploy
Bash
복사
# 테스트용 디플로이먼트 확인
Scale-Out 확인
kubectl scale deployment inflate --replicas 12
Bash
복사
# replicas 수정 (replicas 0 -> 12)
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep provisioner
Bash
복사
# 로그 확인
kubectl get node -l type=karpenter
Bash
복사
# karpenter로 생성한 노드 확인
kubectl get node --label-columns=eks.amazonaws.com/capacityType,karpenter.sh/capacity-type
Bash
복사
# karpenter로 생성한 노드 확인
Consolidation 확인
kubectl scale deployment inflate --replicas 7
Bash
복사
# replicas 수정 (replicas 12 -> 7)
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep consolidation -A 3
Bash
복사
# 로그 확인
디플로이먼트 삭제
kubectl delete deployment inflate
Bash
복사
# 테스트용 디플로이먼트 삭제

4. 실습 환경 삭제

5장 Karpenter 실습이 종료되어 모든 실습 환경을 삭제합니다.
실습 종료 후 자원 삭제
helm uninstall -n kube-system kube-ops-view helm uninstall karpenter --namespace karpenter
Bash
복사
# helm chart 삭제
aws ec2 describe-launch-templates --filters Name=tag:karpenter.k8s.aws/cluster,Values=${CLUSTER_NAME} | jq -r ".LaunchTemplates[].LaunchTemplateName" | xargs -I{} aws ec2 delete-launch-template --launch-template-name {}
Bash
복사
# ec2 launch template 삭제
eksctl delete cluster --name "${CLUSTER_NAME}"
Bash
복사
# eks 클러스터 삭제
aws cloudformation delete-stack --stack-name "Karpenter-${CLUSTER_NAME}"
Bash
복사
# karpenter 관련 cloudformation 스택 삭제
aws cloudformation delete-stack --stack-name ${CLUSTER_NAME}
Bash
복사
# 기본 cloudformation 스택 삭제
Warning: 실습 환경 삭제는 반드시 순차적으로 진행하여 삭제합니다.
Amazon Route 53 레코드 및 호스팅 영역 삭제
1) 서비스 > Route 53 > 호스팅 영역 > 도메인 선택
대상 레코드 선택 > ‘레코드 삭제’ 버튼 > ‘삭제’ 버튼
2) 더 이상 도메인을 사용 계획이 없을 경우 호스팅 영역 삭제
NS 레코드와 SOA 레코드만 존재하는지 확인
‘영역 삭제’ 버튼 > ‘삭제’ 버튼
Warning: 호스팅 영역을 재사용할 경우 ‘호스팅 영역 생성’ 버튼을 클릭하고 자신의 도메인을 입력합니다. 이때 네임 서버 주소를 맞추는 작업이 필요한데 링크를 참조바랍니다.
여기까지 5장 Karpenter 구성 하기 실습을 마칩니다.
수고하셨습니다 :)