목차
1. 실습 기본 환경 구성
    1.1. Karpenter Preconfig 배포
    1.2. EKS 클러스터 생성
    1.3. EKS 클러스터 확인 및 추가 설정
2. Karpenter 환경 구성
    2.1. Karpenter 설치 및 확인
    2.2. Provisioner 생성 및 확인
3. Karpenter 동작 확인
    3.1. 테스트용 디플로이먼트 생성
    3.2. Karpenter의 스케일링 확인
    3.3. Karpenter의 Consolidation 확인
4. 실습 환경 삭제


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로 접속하고 아래 명령어를 통해 정보를 확인합니다.


환경 변수

1
2
3
4
5
6
7
8
// 환경 변수 정보 확인
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 생성

1
2
3
4
5
6
7
8
// 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 클러스터 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 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로 적용

1
2
// Default Namespace로 위치 변경
kubectl ns default


EKS 클러스터 확인

1
2
3
4
5
6
7
8
9
10
// 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 설치

1
2
3
4
5
6
// 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 설치

1
2
3
4
5
6
7
8
9
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 설치

1
2
3
4
5
6
7
8
9
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 설치 및 확인


환경 변수 설정

1
2
3
4
5
6
// 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 확인

1
2
3
4
// 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

1
2
3
4
5
// docker logout
docker logout public.ecr.aws

// helm registry logout
helm registry logout public.ecr.aws


Karpenter 설치

1
2
3
4
5
6
7
8
9
10
11
// 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 설치 확인

1
2
3
4
5
6
7
8
// 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 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 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 확인

1
kubectl get awsnodetemplates,provisioners




3. Karpenter 동작 확인


3.1. 테스트용 디플로이먼트 생성


디플로이먼트 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 디플로이먼트 배포
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 확인

1
2
3
4
5
6
7
8
9
// 테스트용 디플로이먼트 생성
// 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 확인

1
2
3
4
5
6
// 디플로이먼트 삭제 및 로그 확인 (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 삭제

1
2
// 기존 provisioner를 삭제
kubectl delete provisioners default


Provisioner 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 신규 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


디플로이먼트 배포

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 디플로이먼트 배포
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 확인

1
2
3
4
5
6
7
8
9
10
11
// 테스트용 디플로이먼트 생성
// 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 확인

1
2
3
4
// 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


디플로이먼트 삭제

1
2
// 디플로이먼트 삭제
kubectl delete deployment inflate




4. 실습 환경 삭제


5장 Karpenter 실습이 종료되어 모든 실습 환경을 삭제합니다.


실습 종료 후 자원 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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 구성 하기 실습을 마칩니다.
수고하셨습니다 :)