Ssoon

[5주차] EKS Autoscaling - KARPENTER - MULTI-ARCHITECTURE DEPLOYMENTS 본문

AWS EKS Workshop Study

[5주차] EKS Autoscaling - KARPENTER - MULTI-ARCHITECTURE DEPLOYMENTS

구구달스 2023. 5. 25. 16:23
CloudNet@ 팀의 AWS EKS Workshop Study 5주차 정리입니다.
# Karpenter Workshop 의 내용입니다.

[ DEPLOYING MULTIPLE PROVISIONERS ]

Setting up the Provisioners CRD

  • 프로비저너 CRD(Custom Resource Definition)를 설정합니다.
  • 기본값으로 하나를 설정하고 이전에 생성한 것을 재정의하고 team1이라는 새 프로비저너를 설정합니다.

  • 기본 제공자의 구성을 변경합니다.
cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  consolidation:
    enabled: true
  weight: 100
  labels:
    intent: apps
  requirements:
    - key: karpenter.sh/capacity-type
      operator: In
      values: ["on-demand","spot"]
    - key: kubernetes.io/arch
      operator: In
      values: ["amd64","arm64"]
  limits:
    resources:
      cpu: 1000
      memory: 1000Gi
  ttlSecondsUntilExpired: 2592000
  providerRef:
    name: default
---
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: default
spec:
  subnetSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  securityGroupSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  tags:
    KarpenerProvisionerName: "default"
    NodeType: "karpenter-workshop"
    IntentLabel: "apps"
EOF
  • team1이라는 보조 프로비저너를 배포합니다.
cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: team1
spec:
  labels:
    intent: apps
  requirements:
    - key: karpenter.sh/capacity-type
      operator: In
      values: ["on-demand"]
    - key: kubernetes.io/arch
      operator: In
      values: ["amd64","arm64"]
  limits:
    resources:
      cpu: 1000
      memory: 1000Gi
  ttlSecondsAfterEmpty: 30
  ttlSecondsUntilExpired: 2592000
  taints:
  - effect: NoSchedule
    key: team1
  providerRef:
    name: team1
---
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: team1
spec:
  amiFamily: Bottlerocket
  subnetSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  securityGroupSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  tags:
    KarpenerProvisionerName: "team1"
    NodeType: "karpenter-workshop"
    IntentLabel: "apps"
  userData:  |
    [settings.kubernetes]
    kube-api-qps = 30
    [settings.kubernetes.eviction-hard]
    "memory.available" = "20%"
EOF
  • 두 프로비저너 모두 레이블 intent: apps 을 설정합니다. 이것은 intent: control-apps 를 가진 관리 노드 그룹에 설정된 것과 용량을 구별합니다.
  • 둘 다 아키텍처 amd64(x86_64와 동일) 및 arm64를 허용합니다. 
  • 기본 프로비저너는 이제 spot  on-demand 용량 유형을 모두 지원합니다. 그러나 team1 프로비저너는 on-demand 만 지원합니다.
  • team1 프로비저너는 key team1에 대한 Toleration을 제공하는 Pods 또는 Jobs 만 지원합니다. 이 제공자가 조달한 노드는 key team1 및 효과 NoSchedule 과 함께 Taint를 사용하여 tainted 됩니다.
  • team1 프로비저너는 다른 AWSNodeTemplate 을 정의하고 AMI를 기본 EKS 최적화 AMI에서 bottlerocket으로 변경합니다. 또한 이 특정 공급자에 대한 UserData 부트스트래핑을 조정합니다.
  • 기본 프로비저너는 가중치 100을 설정합니다. 프로비저너 평가는 가중치를 사용할 수 있습니다. 가중치가 높을수록 평가의 우선 순위가 높아집니다. 워크로드와 일치하는 첫 번째 프로비저너가 사용됩니다.
Karpenter가 Pod 에서 허용되지 않는 프로비저너에서 taint 을 발견하면 Karpenter는 해당 프로비저너를 사용하여 포드를 프로비저닝하지 않습니다. 상호 배타적인 프로비저너를 생성하는 것이 좋습니다. 따라서 포드가 여러 프로비저너와 일치해서는 안 됩니다. 여러 프로비저너가 일치하는 경우 Karpenter는 사용할 항목을 무작위로 선택합니다.
  • 현재 프로비저너 구성정보를 확인합니다.
  • 프로비저너 내의 provider 섹션을 확인할 수 있습니다.

[ MULTI-ARCHITECTURE DEPLOYMENTS ]

두 개의 프로비저닝을 정의했는데, 두 프로비저닝 모두 amd64(x86_64) 및 arm64 아키텍처를 지원합니다.

특정 아키텍처가 필요한 애플리케이션을 배포합니다.

Creating Multi-Architecture Deployments

각 아키텍처에 대해 하나씩 두 개의 새 deployments를 생성합니다. 0개의 복제본으로 deployments 를 시작하겠습니다.

 

  • amd64 deployment 를 생성합니다.
cat <<EOF > inflate-amd64.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate-amd64
spec:
  replicas: 0
  selector:
    matchLabels:
      app: inflate-amd64
  template:
    metadata:
      labels:
        app: inflate-amd64
    spec:
      nodeSelector:
        intent: apps
        kubernetes.io/arch: amd64
        karpenter.sh/capacity-type: on-demand
      containers:
      - image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
        name: inflate-amd64
        resources:
          requests:
            cpu: "1"
            memory: 256M
EOF
kubectl apply -f inflate-amd64.yaml
  • arm64 deployment 를 생성합니다.
cat <<EOF > inflate-arm64.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate-arm64
spec:
  replicas: 0
  selector:
    matchLabels:
      app: inflate-arm64
  template:
    metadata:
      labels:
        app: inflate-arm64
    spec:
      nodeSelector:
        intent: apps
        kubernetes.io/arch: arm64
        node.kubernetes.io/instance-type: c6g.xlarge
      containers:
      - image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
        name: inflate-arm64
        resources:
          requests:
            cpu: "1"
            memory: 256M
EOF
kubectl apply -f inflate-arm64.yaml


inflate-amd64 deployment 를 2개의 replicas 로 확장합니다. 카펜터는 어떤 노드를 선택했나요?

kubectl scale deployment inflate-amd64 --replicas 2
  • Node selector 는 사용자가 pod 를 스케줄링할 수 있는 노드를 지정할 수 있는 opt-in 메커니즘이다.
  • Karpenter 는 unschedulable pod 에서 well-known Node selector 를 인식하고 이를 사용하여 프로비저닝하는 노드를 제한한다.
  • kubernetes.io/arch는 카펜터에서 well-known Node selector  중 하나이다. 카펜터가 kubernetes.io/archamd64로 설정된 것을 발견하면 프로비저닝된 노드가 amd64 인스턴스에 따라 제약되도록 보장한다.

controller.provisioner  launching machine with 2 pods requesting {"cpu":"2125m","memory":"512M","pods":"4"} from types m5a.16xlarge, r5ad.8xlarge, m5ad.8xlarge, r5.24xlarge, m5.metal and 159 other(s)   {"commit": "982c35f", "provisioner": "default"}

첫 번째는 인스턴스 선택에 사용된 프로비저너와 관련된 것입니다. 로그는 controller.allocation.provisioner/default 가 선택한 것을 가리킵니다. 

 

로그에는 선택된 인스턴스가 c5a.xlarge 유형의 on-demand 인스턴스이며, 인스턴스 diversified selection (from types m5a.16xlarge, r5ad.8xlarge, m5ad.8xlarge, r5.24xlarge, m5.metal and 159 other(s) 에서 고려되었음을 보여 줍니다. 

목록에 있는 모든 인스턴스는 유형이 amd64 또는 x86_64이며, 모두 최소한 2개의 복제본 배포에 적합한 크기입니다.

 

    spec:
      nodeSelector:
        intent: apps
        kubernetes.io/arch: amd64
        karpenter.sh/capacity-type: on-demand


Node selector 는 사용자가 파드를 스케줄링할 수 있는 노드를 지정할 수 있는 옵트인 메커니즘입니다.

Karpenter는 pending pods 에 정의된 Node selector 를 사용하고 그에 따라 용량을 프로비저닝합니다.

kubernetes.sh/capacity-type 에 대한 Node selector 에 on-demand 로 명시되어 있습니다.

내부적으로 Karpenter는 온디맨드 인스턴스에 대해 최저 가격 할당 전략을 사용합니다. 

CloudTrail을 사용하여 CreateFleet에 대한 최신 호출(EC2 Fleet instant mode call)을 추출해 보겠습니다.

aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=CreateFleet --max-items=1

그러면 이 계정에서 수행된 CreateFleet에 대한 마지막 호출이 표시됩니다. CloudTrailEvent의 출력에는 이스케이프된 JSON 문서가 표시됩니다. Cloud9 콘솔에서 "Control-F" 를 입력하고 lowest-price 를 검색할 수 있습니다. 

"OnDemandOptions\":{\"AllocationStrategy\":\"lowest-price\"

또한 intent:apps 및 kubernetes.io/arch:amd64 를 필터링하는 다음 명령을 실행하여 선택한 인스턴스에 대한 자세한 정보를 얻을 수 있습니다.

kubectl get node --selector=intent=apps -L kubernetes.io/arch -L node.kubernetes.io/instance-type -L karpenter.sh/provisioner-name -L topology.kubernetes.io/zone -L karpenter.sh/capacity-type


inflate-arm64 deployment 를 2개의 replicas 로 확장합니다. 카펜터는 어떤 노드를 선택했나요?

kubectl scale deployment inflate-arm64 --replicas 2

  • node.kubernetes.io/instance-type: c6g.xlarge
    spec:
      nodeSelector:
        intent: apps
        kubernetes.io/arch: arm64
        node.kubernetes.io/instance-type: c6g.xlarge
  • Karpenter 로그를 실행하여 확인할 수 있습니다

  • intent:apps 및 kubernetes.io/arch:arm64를 필터링하여 선택한 인스턴스에 대한 자세한 정보를 얻을 수 있습니다.
kubectl get node --selector=intent=apps,kubernetes.io/arch=arm64 -L kubernetes.io/arch -L node.kubernetes.io/instance-type -L karpenter.sh/provisioner-name -L topology.kubernetes.io/zone -L karpenter.sh/capacity-type


두 deployment 를 replicas 를 0으로 변경합니다.

kubectl scale deployment inflate-amd64 --replicas 0
kubectl scale deployment inflate-arm64 --replicas 0

[ 정리 ]

  • Karpenter 는 NodeSelector pods 에서 well-known labels 을 사용하여 선택한 타입 인스턴스를 오버라이드합니다. 실습에서는 NodeSelector kubernetes.io/arch를 사용하여 amd64 x86_64 및 arm64 타입의 인스턴스를 선택했습니다. 또한 well-known labels 인 node.kubernetes.io/instance-type(예: c6g.xlarge)을 사용하여 특정 인스턴스 유형을 선택할 수 있습니다.

  • NodeSelector 가 지정되지 않은 경우, Karpenter 는 해당 레이블에 대한 default 구성 설정으로 되돌아간다. 이 경우, arm64 디플로이먼트의 경우 kubernetes.sh/capacity-type 속성이 설정되지 않았기 때문에 기본 프로비저너가 spot 과 on-demand 모두를 지원하더라도 spot 인스턴스가 선택되었다는 의미이다.

  • Karpenter는 다양한 선택을 통해 on-demand 인스턴스도 확장합니다. spot 과 마찬가지로, 인스턴스는 pending pods 를 bin-pack well 하는 능력에 따라 선택됩니다. Karpenter는 on-demand 할당 전략인 lowest-price 을 사용하여 사용 가능한 용량이 있는 인스턴스 중에서 어떤 인스턴스를 선택할지 선택합니다.

 

 

 

 

 
Comments