Kubernetes 데이터 영역 - Amazon EKS

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

Kubernetes 데이터 영역

EC2 인스턴스 유형을 선택하는 것은 워크로드가 여러 개인 클러스터에서 발생하기 때문에 고객이 직면하는 가장 어려운 결정 중 하나일 수 있습니다. 모든 솔루션에 one-size-fits 솔루션은 없습니다. 다음은 컴퓨팅 크기 조정과 관련된 일반적인 위험을 방지하는 데 도움이 되는 몇 가지 팁입니다.

자동 노드 Autoscaling

토일을 줄이고 Kubernetes와 깊이 통합되는 노드 Auto Scaling을 사용하는 것이 좋습니다. 대규모 클러스터에는 관리형 노드 그룹Karpenter를 사용하는 것이 좋습니다.

관리형 노드 그룹은 관리형 업그레이드 및 구성에 대한 추가 이점과 함께 Amazon EC2 Auto Scaling 그룹의 유연성을 제공합니다. Kubernetes Cluster Autoscaler로 확장할 수 있으며 다양한 컴퓨팅 요구 사항이 있는 클러스터의 일반적인 옵션입니다.

Karpenter는 AWS에서 생성한 오픈 소스 워크로드 네이티브 노드 오토스케일러입니다. 노드 그룹을 관리하지 않고 리소스(예: GPU) 및 테인트 및 허용 오차(예: 영역 분산)에 대한 워크로드 요구 사항에 따라 클러스터의 노드를 확장합니다. 노드는 그룹당 450개의 노드라는 기본 노드 그룹 할당량을 피하고 운영 오버헤드를 줄이면서 인스턴스 선택 유연성을 제공하는 EC2에서 직접 생성됩니다. 가능하면 Karpenter를 사용하는 것이 좋습니다.

다양한 EC2 인스턴스 유형 사용

각 AWS 리전에는 인스턴스 유형당 사용 가능한 인스턴스 수가 제한됩니다. 하나의 인스턴스 유형만 사용하는 클러스터를 생성하고 리전의 용량을 초과하여 노드 수를 조정하면 사용 가능한 인스턴스가 없다는 오류가 발생합니다. 이 문제를 방지하려면 클러스터에서 사용할 수 있는 인스턴스 유형을 임의로 제한해서는 안 됩니다.

Karpenter는 기본적으로 광범위한 호환 인스턴스 유형을 사용하며 보류 중인 워크로드 요구 사항, 가용성 및 비용에 따라 프로비저닝 시간에 인스턴스를 선택합니다. NodePools의 karpenter.k8s.aws/instance-category 키에 사용되는 인스턴스 유형 목록을 확장할 수 있습니다. NodePools

Kubernetes Cluster Autoscaler를 사용하려면 노드 그룹을 비슷한 크기로 조정하여 일관되게 확장할 수 있어야 합니다. CPU 및 메모리 크기에 따라 여러 그룹을 생성하고 독립적으로 확장해야 합니다. ec2-instance-selector를 사용하여 노드 그룹에 맞게 비슷한 크기의 인스턴스를 식별합니다.

ec2-instance-selector --service eks --vcpus-min 8 --memory-min 16
a1.2xlarge
a1.4xlarge
a1.metal
c4.4xlarge
c4.8xlarge
c5.12xlarge
c5.18xlarge
c5.24xlarge
c5.2xlarge
c5.4xlarge
c5.9xlarge
c5.metal

API 서버 로드를 줄이기 위해 더 큰 노드 선호

사용할 인스턴스 유형을 결정할 때 실행 중인 kubelet 및 DaemonSets가 적기 때문에 더 적은 수의 대형 노드가 Kubernetes 제어 플레인에 대한 부하를 줄입니다. 그러나 큰 노드는 작은 노드처럼 완전히 활용되지 않을 수 있습니다. 노드 크기는 워크로드 가용성 및 규모 요구 사항에 따라 평가해야 합니다.

3개의 u-24tb1.metal 인스턴스(24TB 메모리 및 448 코어)가 있는 클러스터에는 3개의 kubelet이 있으며 기본적으로 노드당 110개의 포드로 제한됩니다. 포드가 각각 4개의 코어를 사용하는 경우 이는 예상될 수 있습니다(4개의 코어 x 110 = 440개의 코어/노드). 3 노드 클러스터의 경우 인스턴스 중단 1개가 클러스터의 1/3에 영향을 미칠 수 있으므로 인스턴스 인시던트를 처리하는 기능이 낮아집니다. Kubernetes 스케줄러가 워크로드를 올바르게 배치할 수 있도록 워크로드에 노드 요구 사항과 포드 분산을 지정해야 합니다.

워크로드는 테인트, 허용 오차 및 PodTopologySpread를 통해 필요한 리소스와 필요한 가용성을 정의해야 합니다. 제어 플레인 로드를 줄이고, 운영을 줄이고, 비용을 절감하려면 최대한 활용할 수 있는 가장 큰 노드를 선호하고 가용성 목표를 충족해야 합니다.

Kubernetes 스케줄러는 리소스를 사용할 수 있는 경우 가용 영역 및 호스트에 워크로드를 자동으로 분산하려고 시도합니다. 사용 가능한 용량이 없는 경우 Kubernetes Cluster Autoscaler는 각 가용 영역에 노드를 균등하게 추가하려고 시도합니다. Karpenter는 워크로드가 다른 요구 사항을 지정하지 않는 한 노드를 최대한 빠르고 저렴하게 추가하려고 시도합니다.

워크로드가 스케줄러 및 새 노드와 함께 분산되도록 하려면 topologySpreadConstraints를 사용해야 합니다.

spec:
  topologySpreadConstraints:
    - maxSkew: 3
      topologyKey: "topology.kubernetes.io/zone"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment
    - maxSkew: 2
      topologyKey: "kubernetes.io/hostname"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment

일관된 워크로드 성능을 위해 유사한 노드 크기 사용

워크로드는 일관된 성능과 예측 가능한 규모 조정을 위해 실행해야 하는 노드 크기를 정의해야 합니다. 500m CPU를 요청하는 워크로드는 코어가 4개인 인스턴스와 코어가 16개인 인스턴스에서 다르게 작동합니다. T 시리즈 인스턴스와 같이 버스트 가능한 CPUs.

워크로드의 일관된 성능을 보장하기 위해 워크로드는 지원되는 Karpenter 레이블을 사용하여 특정 인스턴스 크기를 대상으로 지정할 수 있습니다.

kind: deployment
...
spec:
  template:
    spec:
    containers:
    nodeSelector:
      karpenter.k8s.aws/instance-size: 8xlarge

Kubernetes Cluster Autoscaler를 사용하여 클러스터에서 예약되는 워크로드는 레이블 일치를 기반으로 노드 선택기와 노드 그룹과 일치해야 합니다.

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/nodegroup
            operator: In
            values:
            - 8-core-node-group    # match your node group name

컴퓨팅 리소스를 효율적으로 사용

컴퓨팅 리소스에는 EC2 인스턴스 및 가용 영역이 포함됩니다. 컴퓨팅 리소스를 효과적으로 사용하면 확장성, 가용성, 성능이 향상되고 총 비용이 절감됩니다. 여러 애플리케이션이 있는 Auto Scaling 환경에서는 효율적인 리소스 사용량을 예측하기가 매우 어렵습니다. Karpenter는 사용률과 유연성을 극대화하기 위해 워크로드 요구 사항에 따라 온디맨드로 인스턴스를 프로비저닝하도록 생성되었습니다.

Karpenter를 사용하면 워크로드가 먼저 노드 그룹을 생성하거나 특정 노드에 대한 레이블 테인트를 구성하지 않고도 필요한 컴퓨팅 리소스 유형을 선언할 수 있습니다. 자세한 내용은 Karpenter 모범 사례를 참조하세요. Karpenter 프로비저너에서 통합을 활성화하여 사용 중인 노드를 대체하는 것이 좋습니다.

Amazon Machine Image(AMI) 업데이트 자동화

작업자 노드 구성 요소를 최신 상태로 유지하면 최신 보안 패치와 Kubernetes API와 호환되는 기능이 있는지 확인할 수 있습니다. kubelet을 업데이트하는 것은 Kubernetes 기능에 가장 중요한 구성 요소이지만 OS, 커널 및 로컬에 설치된 애플리케이션 패치를 자동화하면 확장 시 유지 관리를 줄일 수 있습니다.

노드 이미지에 최신 Amazon EKS 최적화 Amazon Linux 2 또는 Amazon EKS 최적화 Bottlerocket AMI를 사용하는 것이 좋습니다. Karpenter는 사용 가능한 최신 AMI를 자동으로 사용하여 클러스터에 새 노드를 프로비저닝합니다. 관리형 노드 그룹은 노드 그룹 업데이트 중에 AMI를 업데이트하지만 노드 프로비저닝 시간에는 AMI ID를 업데이트하지 않습니다.

관리형 노드 그룹의 경우 패치 릴리스에 사용할 수 있는 경우 새 AMI IDs로 Auto Scaling 그룹(ASG) 시작 템플릿을 업데이트해야 합니다. AMI 마이너 버전(예: 1.23.5~1.24.3)은 EKS 콘솔 및 API에서 노드 그룹에 대한 업그레이드로 사용할 수 있습니다. 패치 릴리스 버전(예: 1.23.5~1.23.6)은 노드 그룹에 대한 업그레이드로 제공되지 않습니다. AMI 패치 릴리스로 노드 그룹을 최신 상태로 유지하려면 새 시작 템플릿 버전을 생성하고 노드 그룹이 인스턴스를 새 AMI 릴리스로 교체하도록 해야 합니다.

이 페이지에서 사용 가능한 최신 AMI를 찾거나 AWS CLI를 사용할 수 있습니다.

aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.24/amazon-linux-2/recommended/image_id \
  --query "Parameter.Value" \
  --output text

컨테이너에 여러 EBS 볼륨 사용

EBS 볼륨에는 볼륨 유형(예: gp3) 및 디스크 크기에 따라 입출력(I/O) 할당량이 있습니다. 애플리케이션이 호스트와 단일 EBS 루트 볼륨을 공유하는 경우 전체 호스트의 디스크 할당량이 소진되어 다른 애플리케이션이 사용 가능한 용량을 기다릴 수 있습니다. 애플리케이션은 오버레이 파티션에 파일을 쓰고, 호스트에서 로컬 볼륨을 탑재하고, 사용된 로깅 에이전트에 따라 표준 출력(STDOUT)에 로그인할 때 디스크에 씁니다.

디스크 I/O 소진을 방지하려면 컨테이너 상태 폴더(예: /run/containerd)에 두 번째 볼륨을 탑재하고 워크로드 스토리지에 별도의 EBS 볼륨을 사용하고 불필요한 로컬 로깅을 비활성화해야 합니다.

eksctl을 사용하여 EC2 인스턴스에 두 번째 볼륨을 탑재하려면 다음 구성과 함께 노드 그룹을 사용할 수 있습니다.

managedNodeGroups:
  - name: al2-workers
    amiFamily: AmazonLinux2
    desiredCapacity: 2
    volumeSize: 80
    additionalVolumes:
      - volumeName: '/dev/sdz'
        volumeSize: 100
    preBootstrapCommands:
    - |
      "systemctl stop containerd"
      "mkfs -t ext4 /dev/nvme1n1"
      "rm -rf /var/lib/containerd/*"
      "mount /dev/nvme1n1 /var/lib/containerd/"
      "systemctl start containerd"

terraform을 사용하여 노드 그룹을 프로비저닝하는 경우 EKS Blueprints for terraform의 예제를 참조하세요. Karpenter를 사용하여 노드를 프로비저닝하는 경우 노드 사용자 데이터와 blockDeviceMappings 함께를 사용하여 볼륨을 추가할 수 있습니다.

EBS 볼륨을 포드에 직접 탑재하려면 AWS EBS CSI 드라이버를 사용하고 스토리지 클래스와 함께 볼륨을 사용해야 합니다.

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 4Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: public.ecr.aws/docker/library/nginx
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim

워크로드가 EBS 볼륨을 사용하는 경우 EBS 연결 제한이 낮은 인스턴스 방지

EBS는 워크로드가 영구 스토리지를 보유하는 가장 쉬운 방법 중 하나이지만 확장성 제한도 함께 제공합니다. 각 인스턴스 유형에는 연결할 수 있는 최대 EBS 볼륨 수가 있습니다. 워크로드는 실행해야 하는 인스턴스 유형을 선언하고 Kubernetes 테인트가 있는 단일 인스턴스의 복제본 수를 제한해야 합니다.

디스크에 대한 불필요한 로깅 비활성화

프로덕션 환경에서 디버그 로깅으로 애플리케이션을 실행하지 않고 디스크에 자주 읽고 쓰는 로깅을 비활성화하여 불필요한 로컬 로깅을 방지합니다. 저널링은 로그 버퍼를 메모리에 유지하고 주기적으로 디스크로 플러시하는 로컬 로깅 서비스입니다. 모든 줄을 디스크에 즉시 로깅하는 syslog보다 저널링이 선호됩니다. 또한 syslog를 비활성화하면 필요한 총 스토리지 양이 줄어들고 복잡한 로그 교체 규칙이 필요하지 않습니다. syslog를 비활성화하려면 cloud-init 구성에 다음 코드 조각을 추가할 수 있습니다.

runcmd:
  - [ systemctl, disable, --now, syslog.service ]

OS 업데이트 속도가 필요한 경우 패치 인스턴스 적용

중요

패치 적용 인스턴스는 필요한 경우에만 수행해야 합니다. Amazon은 인프라를 애플리케이션과 동일한 방식으로 하위 환경을 통해 승격되는 변경 불가능하고 철저한 테스트 업데이트로 취급할 것을 권장합니다. 이 섹션은 불가능할 때 적용됩니다.

컨테이너화된 워크로드를 중단하지 않고 기존 Linux 호스트에 패키지를 설치하는 데 몇 초가 걸립니다. 인스턴스를 연결, 드레이닝 또는 교체하지 않고도 패키지를 설치하고 검증할 수 있습니다.

인스턴스를 교체하려면 먼저 새 AMIs. 인스턴스는 교체를 생성해야 하며 이전 인스턴스는 연결 및 드레이닝해야 합니다. 그런 다음 새 인스턴스에서 워크로드를 생성하고 패치를 적용해야 하는 모든 인스턴스에 대해 확인 및 반복해야 합니다. 워크로드를 중단하지 않고 인스턴스를 안전하게 교체하는 데 몇 시간, 며칠 또는 몇 주가 걸립니다.

Amazon은 자동화된 선언적 시스템에서 구축, 테스트 및 승격된 변경 불가능한 인프라를 사용할 것을 권장하지만, 시스템을 신속하게 패치해야 하는 경우 새 AMIs 사용할 수 있게 되면 시스템을 패치하고 교체해야 합니다. 패치 적용과 시스템 교체 간의 시간 차이가 크기 때문에 필요한 경우 AWS Systems Manager 패치 관리자를 사용하여 패치 적용 노드를 자동화하는 것이 좋습니다.

패치 노드를 사용하면 AMI가 업데이트된 후 정기적으로 보안 업데이트를 신속하게 롤아웃하고 인스턴스를 교체할 수 있습니다. Flatcar Container Linux 또는 Bottlerocket OS와 같은 읽기 전용 루트 파일 시스템이 있는 운영 체제를 사용하는 경우 해당 운영 체제에서 작동하는 업데이트 연산자를 사용하는 것이 좋습니다. Flatcar Linux 업데이트 운영자Bottlerocket 업데이트 운영자는 노드를 자동으로 최신 상태로 유지하기 위해 인스턴스를 재부팅합니다.