[EKS] 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'
// 환경 변수 설정
export KARPENTER_VERSION=v0.30.0
export TEMPOUT=$(mktemp)
echo $KARPENTER_VERSION; echo $CLUSTER_NAME; echo $AWS_DEFAULT_REGION; echo $AWS_ACCOUNT_ID $TEMPOUT
Warning: CloudFormation 스택이 생성되고 환경 변수가 선언되기 전에 너무 빨리 접속하면 다시 접속합니다.
Karpenter 관련 IAM, EC2 Instance Profile 생성
// CloudFormation 스택으로 IAM Policy, Role, EC2 Instance Profile 생성
// 약 3분 정도 소요
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}"
Amazon EKS 클러스터 생성
// EKS 클러스터 생성 : myeks2 생성
// 약 19분 정도 소요
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
1.3. EKS 클러스터 확인 및 추가 설정
Default Namespace로 적용
// Default Namespace로 위치 변경
kubectl ns default
EKS 클러스터 확인
// EKS 클러스터 배포 확인
eksctl get cluster
eksctl get nodegroup --cluster $CLUSTER_NAME
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl describe cm -n kube-system aws-auth
신규 터미널 - EKS Node Viewer 설치
// EKS Node Viewer 설치 : 약 2분 이상 소요
// EKS 클러스터 생성 완료 후 작업
go install github.com/awslabs/eks-node-viewer/cmd/eks-node-viewer@v0.5.0
// EKS Node Viewer 접속
cd ~/go/bin && ./eks-node-viewer
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 -
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"
2. Karpenter 환경 구성
2.1. Karpenter 설치 및 확인
환경 변수 설정
// 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
EC2 Spot fleet의 server-linked-role 확인
// EC2 Spot Fleet 사용을 위한 service-linked-role 생성 확인 (이미 생성됐다는 에러가 나와야 정상)
// An error occurred (InvalidInput) when calling the CreateServiceLinkedRole operation...
aws iam create-service-linked-role --aws-service-name spot.amazonaws.com || true
Warning: 만약 에러 메시지가 아닌 새롭게 생성하는 메시지가 나온다면 현재 어카운트에 해당 서비스 연결 역할(AWSServiceRoleForEC2Spot)이 존재하지 않는 것 입니다. 서비스 연결 역할 생성 후 다음 단계로 넘어가면 됩니다. 처음부터 다시 진행할 필요는 없습니다.
public.ecr.aws logout
// docker logout
docker logout public.ecr.aws
// helm registry logout
helm registry logout public.ecr.aws
Karpenter 설치
// 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
Karpenter 설치 확인
// 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
2.2. Provisioner 생성 및 확인
Provisioner와 AWSNodeTemplate 생성
// 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
Provisioner와 AWSNodeTemplate 확인
kubectl get 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
// 디플로이먼트 확인
kubectl get deploy
3.2. Karpenter의 스케일링 확인
Scale-Out 확인
// 테스트용 디플로이먼트 생성
// replicas 수정 및 로그 확인 (replicas 0 -> 5)
kubectl scale deployment inflate --replicas 5
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep provisioner
// 스팟 인스턴스 확인
kubectl get node --label-columns=eks.amazonaws.com/capacityType,karpenter.sh/capacity-type,node.kubernetes.io/instance-type
Scale-In 확인
// 디플로이먼트 삭제 및 로그 확인 (ttlSecondsAfterEmpty 30초)
kubectl delete deployment inflate; date
date
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep deprovisioning
3.3. Karpenter의 Consolidation 확인
Provisioner 삭제
// 기존 provisioner를 삭제
kubectl delete provisioners default
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
디플로이먼트 배포
// 디플로이먼트 배포
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
// 디플로이먼트 확인
kubectl get deploy
Scale-Out 확인
// 테스트용 디플로이먼트 생성
// replicas 수정 및 로그 확인 (replicas 0 -> 12)
kubectl scale deployment inflate --replicas 12
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep provisioner
// karpenter로 생성한 노드 확인
kubectl get node -l type=karpenter
kubectl get node --label-columns=eks.amazonaws.com/capacityType,karpenter.sh/capacity-type
Consolidation 확인
// replicas 수정 및 로그 확인 (replicas 12 -> 7)
kubectl scale deployment inflate --replicas 7
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller | grep consolidation -A 3
디플로이먼트 삭제
// 디플로이먼트 삭제
kubectl delete deployment inflate
4. 실습 환경 삭제
5장 Karpenter 실습이 종료되어 모든 실습 환경을 삭제합니다.
실습 종료 후 자원 삭제
// helm chart 삭제
helm uninstall -n kube-system kube-ops-view
helm uninstall karpenter --namespace karpenter
// ec2 launch template 삭제
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 {}
// eks 클러스터 삭제
eksctl delete cluster --name "${CLUSTER_NAME}"
// karpenter 관련 cloudformation 스택 삭제
aws cloudformation delete-stack --stack-name "Karpenter-${CLUSTER_NAME}"
// 기본 cloudformation 스택 삭제
aws cloudformation delete-stack --stack-name ${CLUSTER_NAME}
Warning: 실습 환경 삭제는 반드시 순차적으로 진행하여 삭제합니다.
Amazon Route 53 레코드 및 호스팅 영역 삭제
1) 서비스 > Route 53 > 호스팅 영역 > 도메인 선택
- 대상 레코드 선택 > ‘레코드 삭제’ 버튼 > ‘삭제’ 버튼
2) 더 이상 도메인을 사용 계획이 없을 경우 호스팅 영역 삭제
- NS 레코드와 SOA 레코드만 존재하는지 확인
- ‘영역 삭제’ 버튼 > ‘삭제’ 버튼
Warning: 호스팅 영역을 재사용할 경우 ‘호스팅 영역 생성’ 버튼을 클릭하고 자신의 도메인을 입력합니다. 이때 네임 서버 주소를 맞추는 작업이 필요한데 링크를 참조바랍니다.
여기까지 5장 Karpenter 구성 하기 실습을 마칩니다.
수고하셨습니다 :)