AWS 기술 블로그

Karpenter Drift를 사용하여 Amazon EKS 워커 노드를 업그레이드하기

이 글은 AWS Container Blog에 게시된 ‘How to upgrade Amazon EKS worker nodes with Karpenter Drift‘을 Karpenter v1beta1 API 변경 사항을 반영하여 업데이트되었습니다.

소개

Karpenter는 집계된 CPU, 메모리, 볼륨 요청 및 기타 쿠버네티스 스케줄링 제약 조건 (예: 어피니티 및 파드 topology spread constraints) 을 기반으로 스케줄링할 수 없는 파드에 대응하여 적절한 크기의 노드를 프로비저닝하여 인프라 관리를 간소화하는 오픈 소스 클러스터 오토스케일러입니다. 클러스터 오토스케일러를 대체 오토스케일러로 사용하는 경우, 오토스케일링이 효과적으로 작동하려면 노드 그룹의 모든 쿠버네티스 노드가 동일한 용량 (vCPU 및 메모리) 을 가져야 합니다.따라서 고객은 워크로드 요구 사항을 충족하기 위해 각각 Amazon EC2 Auto Scaling 그룹이 지원하는 다양한 인스턴스 크기의 노드 그룹을 다수 보유하게 됩니다.워크로드는 시간이 지남에 따라 계속 진화하므로 리소스 요구 사항의 변화로 인해 적절한 규모의 Amazon Elastic Compute Cloud (Amazon EC2) 인스턴스를 선택하는 것이 어려울 수 있습니다.또한 Karpenter는 노드 그룹 및 Amazon EC2 Auto Scaling 그룹과 같은 외부 인프라를 사용하여 용량 관리를 조정하지 않으므로 워커 노드 구성 요소 및 운영 체제를 최신 보안 패치 및 기능으로 최신 상태로 유지하기 위해 운영 프로세스에 다른 관점을 도입합니다.

이 게시물에서는 Drift라는 Karpenter 기능을 통해 Karpenter로 프로비저닝된 쿠버네티스 워커 노드를 패치하는 메커니즘을 설명하겠습니다. 여러 Amazon EKS 클러스터에 워커 노드가 여러 개 있는 경우 이 메커니즘을 사용하면 대규모로 지속적으로 패치를 적용할 수 있습니다.

솔루션 개요

Karpenter 노드 패치 메커니즘

Amazon EKS가 새 쿠버네티스 버전을 지원하는 경우, 단일 API 호출을 통해 Amazon Elastic Kubernetes Service (Amazon EKS) 클러스터 컨트롤 플레인을 다음 버전으로 업그레이드할 수 있습니다. 쿠버네티스 데이터 플레인을 업그레이드하려면 쿠버네티스 워커 노드에 대한 Amazon Machine Image(AMI)를 업데이트해야 합니다. AWS는 패치 및 CVE(Common Vulnerabilities and Exposures)뿐만 아니라 신규 쿠버네티스 버전용 AMI를 출시합니다. 다양한 Amazon EKS에 최적화된 AMI를 선택할 수 있습니다. 또는 자체 사용자 지정 AMI를 사용할 수도 있습니다. 현재 Karpenter EC2NodeClass 리소스에서 AL2, AL2023, bottlerocket, Ubuntu, Windows 2019, Windows 2022 및 사용자 정의인 amiFamily 값을 지원합니다. 사용자 지정 AMI 패밀리를 선택한 경우, 어떤 사용자 지정 AMI를 사용해야 하는지 Karpenter에 알려주는 amiSelectorTerms를 지정해야 합니다.

Karpenter는 롤링 배포 이후 Drift를 사용하여 쿠버네티스 노드를 업그레이드합니다. 노드가 디프로비저닝되면 새 파드 스케줄링을 방지하기 위해 노드가 cordon 상태가 되고 쿠버네티스 Eviction API를 사용하여 파드가 제거됩니다. Drift 메커니즘은 다음과 같습니다.

Drift

Karpenter로 프로비저닝된 쿠버네티스 노드가 원하는 spec에서 벗어난 경우, Karpenter는 신규 노드를 먼저 프로비저닝하고 이전 노드에서 파드를 제거한 다음 종료합니다. 이 글을 작성하는 시점에는 Drift 간격이 5분으로 설정되어 있습니다. 하지만 NodePool 또는EC2NodeClass가 업데이트되면 Drift 체크가 즉시 트리거됩니다. EC2NodeClass에서는 amiFamily가 필수 필드이므로 자체 AMI 값 또는 EKS 최적화 AMI를 사용할 수 있습니다. AMI용 Drift에는 이 두 가지 경우에 두 가지 동작 방식이 있으며, 이에 대한 자세한 내용은 아래에 설명하도록 하겠습니다.

특정 AMI 값을 사용한 Drift

일관성을 위해 애플리케이션 환경을 통한 AMI 업그레이드을 제어하기 위해 이 접근 방식을 고려할 수 있습니다. NodePool와 연결된 EC2NodeClass에서 AMI를 변경하거나 다른 EC2NodeClass를 NodePool과 연결하면 Karpenter는 기존 워커 노드가 원하는 설정에서 벗어났음을 감지합니다.

업그레이드를 트리거하기 위해서는 신규 AMI를 EC2NodeClass에 연결하면 Karpenter가 롤링 배포를 통해 워커 노드를 업그레이드합니다. AMI는 AMI ID, AMI 이름 또는 특정 태그로 지정할 수 있습니다. 만약 여러 AMI가 기준을 충족하는 경우 최신 AMI가 선택됩니다. 고객은 EC2NodeClass의 status 필드에 있는 AMI 값에서 EC2NodeClass가 어떤 AMI를 검색했는지 추적할 수 있습니다. 상태를 확인하는 한 가지 방법은 EC2NodeClass에서 kubectl describe 명령을 실행하는 것입니다. 특정 시나리오에서 EC2NodeClass에서 이전 AMI와 신규 AMI가 모두 검색되면 이전 AMI를 사용하는 실행 중인 노드가 Drift 되고, 디프로비저닝 된 뒤 신규 AMI의 워커 노드로 교체됩니다. 신규 노드는 신규 AMI를 사용하여 프로비저닝됩니다. EC2NodeClass에서 AMI를 선택하는 방식에 대해 자세히 알아보려면 여기를 참조합니다.

예시 1 – ID별 AMI 선택

amiSelectorTerms:
- id: "ami-123"
- id: "ami-456"

예 2 — 애플리케이션 계정 0123456789에서 이름 태그의 값이 appA-AMI인 AMI를 선택

amiSelectorTerms: 
- name: appA-ami
  owner: 0123456789

Amazon EKS 최적화 AMI를 사용한 Drift

EC2NodeClass에 지정된 amiSelectorTerms가 없는 경우, Karpenter는 Amazon EKS 최적화 AMI에 대해 게시된 SSM 파라미터를 모니터링합니다. amiFamily 필드에 AL2, AL2023, bottlerocket, Ubuntu, Windows 2019 또는 Windows 2022의 값을 지정하여 Karpenter에게 어떤 Amazon EKS 최적화 AMI를 사용해야 하는지 알려줄 수 있습니다. Karpenter는 실행 중인 EKS 클러스터의 버전에 대해 지정된 amiFamily에 맞는 최신 Amazon EKS 최적화 AMI로 노드를 프로비저닝합니다. Karpenter는 해당 쿠버네티스 클러스터 버전을 위한 신규 AMI가 출시되면 이를 감지하고 기존 노드를 Drift합니다. status 필드 아래의 EC2NodeClass AMI 값은 신규 검색된 AMI를 반영합니다. 해당 노드는 디프로비저닝되고 최신 AMI가 설치된 워커 노드로 대체됩니다. 이 접근 방식을 사용하면 이전 AMI가 있는 노드가 자동으로 교체됩니다 (예: 신규 AMI를 사용할 수 있게 되거나 쿠버네티스 컨트롤 플레인이 업그레이드된 후의 경우). amiSelectorTerms를 사용하는 이전 접근 방식에서는 노드 업그레이드 시 더 많은 제어를 할 수 있습니다. 이 두 가지 접근 방법의 차이점을 고려하여 애플리케이션에 적합한 접근 방식을 선택합니다. Karpenter는 현재 사용자 지정 SSM 파라미터를 지원하지 않습니다.

Walkthrough

다음 시나리오를 살펴보도록 하겠습니다.

  1. Karpenter Drift feature gate 활성화
  2. Drift를 통한 노드 업그레이드 자동화
  3. AMI 업그레이드 제어를 통한 노드 업그레이드

사전 요구 사항

이 포스팅에서의 작업들을 완료하려면 다음의 사전 작업들이 필요합니다.

  1. 기존 Amazon EKS 클러스터. 클러스터가 없는 경우 여기에 설명된 방법 중 하나를 따라 클러스터를 생성합니다.
  2. 최신 Karpenter deployement. 여기에 나와 있는 Karpenter 시작하기 가이드를 따라 Karpenter를 설치합니다.

먼저 Amazon EKS 클러스터의 이름을 환경변수로 설정합니다.

export CLUSTER_NAME=<your EKS cluster name>

1 단계. Karpenter Drift feature gate 활성화

Karpenter 0.33 버전부터 Drift가 기본적으로 활성화됩니다. Karpenter의 CLI argument에서 —feature-gates Drift=false를 지정하여 Drift 기능을 비활성화할 수 있습니다.

2 단계. Drift를 사용하여 워커 노드 업그레이드를 자동화

이 예시에서는 AL2 EKS 최적화 AMI를 지정하기 위해 amiFamily 필드에 AL2 값을 설정했습니다.

mkdir -p ~/environment/karpenter
cd ~/environment/karpenter

cat <<EoF> basic.yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: default
spec:
  disruption:
    consolidationPolicy: WhenUnderutilized
    expireAfter: 720h # 30 * 24h = 720h
  limits:
    cpu: "1000"
  template:
    metadata:
        labels:
          team: my-team
    spec:
      nodeClassRef:
        name: default
      requirements:
      - key: karpenter.k8s.aws/instance-category
        operator: In
        values: ["c", "m", "r"]
      - key: "karpenter.k8s.aws/instance-generation"
        operator: Gt
        values: ["2"]
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: AL2
  role: karpenterNodeRole-$CLUSTER_NAME
  securityGroupSelectorTerms:
  - tags:
      alpha.eksctl.io/cluster-name: $CLUSTER_NAME
  subnetSelectorTerms:
  - tags:
      alpha.eksctl.io/cluster-name: $CLUSTER_NAME
  tags:
    intent: apps
    managed-by: karpenter
EoF

kubectl apply -f basic.yaml

참고: eksctl에서 Amazon EKS 클러스터를 프로비저닝하지 않는 경우 자체 서브넷과 보안 그룹을 선택합니다. Karpenter EC2NodeClass를 사용하여 서브넷 및 보안 그룹을 검색하는 방법에 대한 자세한 내용은 이 페이지를 참조하십시오.

워커 노드를 확장하기 위해 inflate라는 이름의 샘플 Deployment를 배포해 보겠습니다.

cd ~/environment/karpenter

cat <<EoF> sample-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 2
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
          resources:
            requests:
              cpu: 1
              memory: 128Mi
            limits:
              memory: 128Mi
      nodeSelector:
        team: my-team
EoF

kubectl apply -f sample-deploy.yaml

Karpenter 로그를 확인하여 Karpenter가 스케줄링할 수 없는(즉, 프로비저닝 가능한) 파드를 발견하고 보류 중인 파드를 수용하기 위해 새 노드를 생성한 것을 확인할 수 있습니다.

$ kubectl -n karpenter logs -l app.kubernetes.io/name=karpenter

{"level":"INFO","time":"2024-01-28T16:01:38.547Z","logger":"controller.provisioner","message":"found provisionable pod(s)","commit":"a70b39e","pods":"default/inflate-67b454659d-xdsml, default/inflate-67b454659d-258ms","duration":"63.969954ms"}
{"level":"INFO","time":"2024-01-28T16:01:38.547Z","logger":"controller.provisioner","message":"computed new nodeclaim(s) to fit pod(s)","commit":"a70b39e","nodeclaims":1,"pods":2}
{"level":"INFO","time":"2024-01-28T16:01:38.568Z","logger":"controller.provisioner","message":"created nodeclaim","commit":"a70b39e","nodepool":"default","nodeclaim":"default-w6fg6","requests":{"cpu":"2150m","memory":"256Mi","pods":"4"},"instance-types":"c6a.2xlarge, c6a.4xlarge, c6a.xlarge, c6g.2xlarge, c6g.4xlarge and 95 other(s)"}
{"level":"INFO","time":"2024-01-28T16:01:41.860Z","logger":"controller.nodeclaim.lifecycle","message":"launched nodeclaim","commit":"a70b39e","nodeclaim":"default-w6fg6","provider-id":"aws:///us-east-1b/i-0caeae25f3db6f37c","instance-type":"m6g.xlarge","zone":"us-east-1b","capacity-type":"spot","allocatable":{"cpu":"3920m","ephemeral-storage":"17Gi","memory":"14103Mi","pods":"58","vpc.amazonaws.com/pod-eni":"18"}}

다음으로 새로 배포된 노드의 AMI 버전을 확인합니다. 이 데모 환경에서 AMI 버전은 v1.28입니다.

$ kubectl get nodes -l team=my-team 

NAME                            STATUS   ROLES    AGE   VERSION 
ip-192-168-40-30.ec2.internal   Ready    <none>   25s   v1.28.5-eks-5e0fdde 

이제 Amazon EKS 컨트롤 플레인 버전을 확인해 보겠습니다. 컨트롤 플레인 버전이 노드 버전과 동일하다고 가정하겠습니다.

$ kubectl version --short 
Server Version: v1.28.5-eks-5e0fdde

이제 Amazon EKS 컨트롤 플레인을 업그레이드하고 워커 노드가 컨트롤 플레인 버전과 자동으로 일치하도록 업데이트되는지 확인해 보겠습니다. 여기서는 AWS 명령줄 인터페이스(AWS CLI)를 예시로 사용하지만, 선호하는 방법을 사용할 수도 있습니다. <region-code> 부분은 사용자의 리전 코드로 대체하고, 1.29는 업그레이드 하고자 하는 Amazon EKS 버전으로 변경하세요. Amazon EKS 클러스터 업그레이드 모범 사례에 대해서는 Amazon EKS 모범 사례 가이드의 클러스터 업그레이드 섹션을 참조합니다.

$ aws eks update-cluster-version —region <region-code> —name $CLUSTER_NAME —kubernetes-version 1.29

다음 명령을 실행하여 클러스터 업데이트 상태를 모니터링 합니다. 이전 명령 결과에서 반환한 update ID를 사용하여 <update-id>를 해당 값으로 바꿉니다. Successful 상태가 표시되면 업그레이드가 완료된 것입니다.

$ aws eks describe-update —region <region-code> —name $CLUSTER_NAME —update-id <update-id>

상태가 Active로 바뀐 후에 Karpenter 로그를 확인해봅시다. Karpenter가 Drift를 감지했고 Drift를 통해 기존 노드의 프로비저닝을 해제하고 새로운 노드로 교체하기 시작했는지 확인할 수 있습니다.

kubectl -n karpenter logs -l app.kubernetes.io/name=karpenter | grep -i drift
 
{"level":"INFO","time":"2024-01-28T16:24:15.675Z","logger":"controller.disruption","message":"disrupting via drift replace, terminating 1 candidates ip-192-168-40-30.ec2.internal/m6g.xlarge/spot and replacing with node from types m7i.metal-24xl, r6in.24xlarge, c6i.32xlarge, m6gd.4xlarge, r6a.2xlarge and 290 other(s)","commit":"a70b39e"}

노드의 AMI 버전을 확인해 보겠습니다. v1.28 노드 상태는 준비, 스케줄링 비활성화로 표시되고 새로 배포된 v1.29 노드는 아직 준비되지 않은 것으로 표시됩니다.

$ kubectl get nodes -l team=my-team 

NAME                                          STATUS                      ROLES    AGE   VERSION 
ip-192-168-27-17.us-west-2.compute.internal   Ready,SchedulingDisabled    <none>   55m   v1.24.15-eks-a5565ad 
ip-192-168-41-50.us-west-2.compute.internal   NotReady                    <none>   13s   v1.25.11-eks-a5565ad 

몇 초 후 $ kubectl get nodes -l team=my-team 명령을 다시 실행하면 새 v.1.29 노드가 준비되고 이전 v1.28 노드가 종료된 것을 확인할 수 있습니다.

$ kubectl get nodes -l team=my-team 
NAME                            STATUS   ROLES    AGE     VERSION 
ip-192-168-153-8.ec2.internal   Ready    <none>   2m51s   v1.29.0-eks-5e0fdde 

참고: 노드 업그레이드에 소요되는 실제 시간은 환경에 따라 다릅니다.

3단계. AMI의 승격 제어를 통한 노드 업그레이드

방금 살펴본 바와 같이, Amazon EKS 제어 플레인이 Amazon EKS에 최적화된 Amazon Linux AMI로 업그레이드되면 Karpenter Drift는 노드 AMI 버전을 자동으로 업그레이드합니다. 그러나 사용 사례(예: 환경을 통해 AMI를 프롬프트하는 경우)에 따라 특정 AMI로 AMI 업데이트를 시작할 시기를 더 자세히 제어하고 싶은 경우가 있습니다. 이를 위해 amiSelectorTerms(EC2NodeClass 아래)에서 AMI를 지정하면 컨트롤 플레인 업데이트를 따르지 않고 AMI를 명시적으로 변경할 때만 노드가 업데이트됩니다.

이 예제에서는 컨테이너를 실행하기 위해 Bottlerocket OS를 사용하고 있습니다. Bottlerocket은 컨테이너를 실행하기 위해 Amazon Web Services에서 특별히 제작한 Linux 기반 오픈 소스 운영 체제입니다. Bottlerocket OS 사용의 이점에 대한 자세한 내용은 https://aws.amazon.com/bottlerocket/ 을 참조하세요.

참고 — 아래 예제에서는 Bottlerocket AMI를 사용하고 있습니다. Karpenter는 AWS Systems Manager(SSM)를 통해 적절한 EKS에 최적화된 AMI를 자동으로 쿼리합니다. 다만, 사용자 정의 amiFamily의 경우 기본 AMI가 정의되어 있지 않습니다. 따라서 어떤 사용자 정의 AMI를 사용할지 Karpenter에 알려주려면 amiSelectorTerms를 지정해야 합니다.

cd ~/environment/karpenter

cat << EOF > bottlerocket.yaml
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: bottlerocket
spec:
  amiFamily: Bottlerocket
  role: karpenterNodeRole-$CLUSTER_NAME
  securityGroupSelectorTerms:
  - tags:
      alpha.eksctl.io/cluster-name: $CLUSTER_NAME
  subnetSelectorTerms:
  - tags:
      alpha.eksctl.io/cluster-name: $CLUSTER_NAME
  tags:
    managed-by: "karpenter"
    intent: "apps"
EOF

kubectl -f bottlerocket.yaml create

참고: eksctl에서 Amazon EKS 클러스터를 프로비저닝하지 않는 경우 자체 서브넷과 보안 그룹을 선택하십시오. Karpenter EC2NodeClass를 사용하여 서브넷 및 보안 그룹을 검색하는 방법에 대한 자세한 내용은 이 페이지를 참조하십시오.

이제 새로 생성된 EC2NodeClass인 bottlerocket을 사용하도록 기본 NodePool을 편집해 보겠습니다.

kubectl edit nodepools.karpenter.sh default

spec:에서 nodeClassRef:를 검색하고 name 값을 기본값에서 bottlerocket으로 변경하십시오.

....
spec:
  disruption:
    consolidateAfter: 60s
    consolidationPolicy: WhenEmpty
    expireAfter: Never
  limits:
    cpu: "1000"
  template:
    metadata:
      labels:
        team: my-team
    spec:
      nodeClassRef:
        name: bottlerocket

Karpenter 로그를 확인해 보겠습니다. Karpenter가 drift 교체를 통해 새 노드로 인한 drift 및 deprovisioning된 노드를 감지한 것을 확인할 수 있습니다.

kubectl -n karpenter logs -l app.kubernetes.io/name=karpenter | grep -i drift

{"level":"INFO","time":"2024-01-31T18:53:52.084Z","logger":"controller.disruption","message":"disrupting via drift replace, terminating 1 candidates ip-192-168-37-223.ec2.internal/c6i.xlarge/spot and replacing with node from types r7iz.16xlarge, c6a.24xlarge, c6a.16xlarge, c7gn.16xlarge, r7a.xlarge and 290 other(s)","commit":"a70b39e"}
{"level":"INFO","time":"2024-01-31T18:53:52.153Z","logger":"controller.disruption","message":"created nodeclaim","commit":"a70b39e","nodepool":"default","nodeclaim":"default-wq2lm","requests":{"cpu":"2150m","memory":"256Mi","pods":"4"},"instance-types":"c6a.2xlarge, c6a.4xlarge, c6a.xlarge, c6g.2xlarge, c6g.4xlarge and 95 other(s)"}
{"level":"INFO","time":"2024-01-31T18:53:55.622Z","logger":"controller.nodeclaim.lifecycle","message":"launched nodeclaim","commit":"a70b39e","nodeclaim":"default-wq2lm","provider-id":"aws:///us-east-1b/i-0f49d524524fbf2a8","instance-type":"m6g.xlarge","zone":"us-east-1b","capacity-type":"spot","allocatable":{"cpu":"3920m","ephemeral-storage":"17Gi","memory":"14103Mi","pods":"58","vpc.amazonaws.com/pod-eni":"18"}}
{"level":"INFO","time":"2024-01-31T18:54:25.979Z","logger":"controller.nodeclaim.lifecycle","message":"initialized nodeclaim","commit":"a70b39e","nodeclaim":"default-wq2lm","provider-id":"aws:///us-east-1b/i-0f49d524524fbf2a8","node":"ip-192-168-150-253.ec2.internal"}
{"level":"INFO","time":"2024-01-31T18:54:27.932Z","logger":"controller.node.termination","message":"tainted node","commit":"a70b39e","node":"ip-192-168-37-223.ec2.internal"}
{"level":"INFO","time":"2024-01-31T18:54:29.620Z","logger":"controller.node.termination","message":"deleted node","commit":"a70b39e","node":"ip-192-168-37-223.ec2.internal"}
{"level":"INFO","time":"2024-01-31T18:54:29.978Z","logger":"controller.nodeclaim.termination","message":"deleted nodeclaim","commit":"a70b39e","nodeclaim":"default-mjxrt","node":"ip-192-168-37-223.ec2.internal","provider-id":"aws:///us-east-1b/i-0d4eed64ea7d3e090"}

노드의 AMI 버전을 확인해 보겠습니다. 기존 Amazon EKS에 최적화된 Linux v1.29 AMI (v1.29.0-eks-5e0fdde) 상태는 Ready, SchedulingDisabled으로 표시되고 새로 배포된 bottlerocket v.1.28 노드 (v1.28.2) 는 NotReady 상태입니다.

$ kubectl get nodes -l team=my-team 

NAME                               STATUS                       ROLES    AGE   VERSION 
ip-192-168-153-8.ec2.internal      Ready,SchedulingDisabled     <none>   65m   v1.29.0-eks-5e0fdde 
ip-192-168-150-253.ec2.internal    NotReady                     <none>   14s   v1.28.2

몇 초 후, 이제 새로운 Bottlerocket v1.29 노드가 준비되고 이전 Amazon EKS에 최적화된 Linux AMI v1.29 노드가 종료되는 것을 확인할 수 있습니다.

$ kubectl get nodes -l team=my-team 

NAME                              STATUS    ROLES     AGE    VERSION
1p-192-168-150-253.ec2.internal   Ready     <none>    30s    v1.29.0-eks-a5ec690

새 노드의 AMI를 확인하려면 아래 명령을 실행합니다.

$ kubectl describe node <NAME from previous command output> | grep -i "OS Image"

OS Image:                   Bottlerocket OS 1.18.0 (aws-k8s-1.29)

Karpenter를 사용할 때 지속적인 운영을 달성하는 데 도움이 될 수 있는 몇 가지 추가 설계 고려 사항이 있습니다.

  • 고가용성을 위해 Pod Topology Spread Constraints를 사용하여 장애 도메인 전반에 워크로드를 분산하세요 — pod anti-affinity 규칙과 마찬가지로 Pod topology spread constraints을 사용하면 호스트 또는 가용 영역과 같은 다양한 장애(또는 토폴로지) 도메인에서 애플리케이션을 사용할 수 있습니다.
  • Pod Readiness Gates 사용을 고려하세요 — Elastic Load Balancer(ELB)를 통해 들어오는 워크로드의 경우, 워크로드가 대상 그룹에 성공적으로 등록되었는지 확인하기 위해 Pod readiness gates 사용을 고려하세요. 자세한 내용은 Amazon EKS 모범 사례 가이드를 참조하세요.
  • Pod Disruptions Budgets 사용을 고려하세요 — 자발적 중단 시 Pod disruption budgets을 사용하여 파드 종료를 제어하세요. Karpenter는 backoff retry eviction 전략을 사용하여 Pod disruption budgets(PDB) 을 존중합니다.
  • 자동 AMI 선택이 올바른 접근 방식인지 고려하세요 — 가장 최신의 Amazon EKS에 최적화된 AMI를 고려하는 것이 좋지만, 여러 환경에서 AMI의 롤아웃을 제어하려면 Karpenter가 최신 AMI를 선택하게 할 것인지 아니면 직접 AMI를 지정할 것인지 고려해야 합니다. 자체 AMI를 지정하면 애플리케이션 환경을 통해 AMI의 프로모션을 제어할 수 있습니다.
  • karpenter.sh/do-not-disrupt: “true”로 설정하는 것을 고려해 보세요 — 중단할 수 없는 워크로드(예: 체크포인트 없이 오래 실행되는 배치 작업)의 경우, karpenter.sh/do-not-disrupt 어노테이션을 파드에 추가하는 것을 고려하세요. 중단되지 않도록 파드를 선택하면 이 파드가 포함된 노드를 자발적으로 제거해서는 안 된다는 것을 Karpenter에 알릴 수 있습니다. 또는 노드에서 중단 작업을 방지하도록 karpenter.sh/do-not-disrupt 어노테이션을 노드에 설정할 수도 있습니다.

리소스 정리

생성된 리소스를 정리하려면 다음 단계를 실행할 수 있습니다.

  1. Karpenter NodePool을 삭제하여 노드를 제거하고, EC2NodeClass 및 샘플 애플리케이션을 정리합니다.
    1. kubectl delete -f basic.yml
    2. kubectl delete -f bottlerocket.yaml
    3. kubectl delete -f sample-deploy.yaml
  2. 실습을 위해 새 Amazon EKS 클러스터를 생성한 경우, 리소스를 정리하는 것을 잊지 마세요. 그렇지 않으면 비용이 발생합니다.

결론

다수의 쿠버네티스 클러스터와 노드 그룹을 보유한 고객의 경우, Karpenter를 도입하면 인프라 관리가 간소화됩니다. 이 게시물에서는 Drift라는 Karpenter 기능을 사용할 때 쿠버네티스 노드를 업그레이드하고 패치하는 방법에 대한 접근 방식을 설명했습니다. 이러한 패치 전략을 사용하면 복잡하고 힘든 작업을 줄일 수 있으며, 이를 통해 point-in-time 전략에서 지속적인 메커니즘으로 전환하여 워커 노드를 대규모로 패치할 수 있습니다. Karpenter Drift 기능은 계속 발전 중이며 최신 정보는 Karpenter 문서를 참조하세요.

더 자세히 알아보고 싶으시면 쿠버네티스 슬랙#karpenter 채널에서 Karpenter에 대해 토론하거나 Karpenter working group에 참여하세요.

실습 정보를 얻으려면 Karpenter 워크샵을 확인하세요.

Jini Park

Jini Park

박진이 솔루션즈 아키텍트는 엔터프라이즈 고객을 대상으로 고객이 최적의 솔루션을 선택하여 비즈니스를 개선할 수 있도록 고객과 함께 효율적인 아키텍처를 구성하는 역할을 수행하고 있습니다.

Shinchul Bang

Shinchul Bang

방신철 솔루션즈 아키텍트는 AWS를 처음 사용하시는 다양한 산업의 고객들이 성공적으로 클라우드 서비스를 도입하시는 것을 돕고 있습니다. 고객이 클라우드를 통해 비즈니스를 더욱 가속화 하고 확장할 수 있도록 안정적이고 효율적인 아키텍처를 제안드리고 있습니다.