Вступление

Если вы когда-либо пытались запустить рабочую нагрузку графического процессора в кластере Kubernetes, вы знаете, что эта задача требует нетривиальной конфигурации и имеет высокую стоимость (экземпляры графического процессора довольно дороги).

В этом посте показано, как экономично запустить рабочую нагрузку графического процессора в кластере Kubernetes, используя кластер Amazon EKS, AWS Auto Scaling, Спотовые инстансы Amazon EC2, а также некоторые ресурсы и конфигурации Kubernetes.

Кластерный план EKS

Во-первых, нам нужно создать кластер Kubernetes, состоящий из смешанных узлов: узлов без графического процессора для управления и общей рабочей нагрузки Kubernetes и более дорогих узлов на базе графического процессора для выполнения задач с интенсивным использованием графического процессора, таких как машинное обучение, медицинский анализ, сейсмические исследования и т. Д. перекодирование видео и другие.

Эти группы узлов должны иметь возможность масштабирования по запросу (масштабирование и масштабирование) для общих узлов и от 0 до необходимого числа и обратно до 0 для дорогих экземпляров графического процессора. Более того, чтобы сделать это экономически эффективным способом, мы собираемся использовать спотовые инстансы Amazon EC2 как для общих узлов, так и для узлов GPU.

Спотовые инстансы AWS EC2

С инстансами Спотовые инстансы Amazon EC2 вы можете сэкономить до 90% по сравнению с ценой по запросу. Ранее спотовые инстансы завершались в порядке возрастания ставок. Из-за этого рыночные цены часто колебались. В текущей модели спотовые цены более предсказуемы, обновляются реже и определяются резервными мощностями Amazon EC2, а не ценами заявок. Сервис AWS EC2 может восстанавливать спотовые инстансы, если для конкретного инстанса в определенной зоне доступности недостаточно ресурсов. Спотовые инстансы получают двухминутное предупреждение, когда они собираются быть восстановлены службой Amazon EC2, и могут использовать это время для постепенного завершения работы и изменения состояния.

Рабочий процесс

1. Создайте кластер EKS.

Кластер Amazon EKS можно создать, используя Amazon EKS CLI, CloudFormation или Terraform, AWS CDK или eksctl.

инструмент командной строки eksctl

В этом посте используется eksctl (инструмент CLI для создания кластеров на EKS). Можно передать все параметры инструменту в виде флагов интерфейса командной строки или файла конфигурации. Использование файла конфигурации делает процесс более повторяемым и удобным для автоматизации.

eksctl может создавать или обновлять кластер EKS и дополнительные необходимые ресурсы AWS, используя стеки CloudFormation.

Настройте свой кластер с помощью файла конфигурации. Просто беги

eksctl create cluster -f cluster.yaml

чтобы применить cluster.yaml файл:

apiVersion: eksctl.io/v1alpha5 
kind: ClusterConfig
metadata: 
  name: test-cluster
  region: us-west-2
nodeGroups: 
  - name: ng
    instanceType: t3.micro
    desiredCapacity: 10

Будет создан новый кластер EKS с 10 t3.micro рабочими узлами EC2 по требованию, а учетные данные кластера будут добавлены в ~/.kube/config файл.

2. Создание групп узлов

Как и планировалось, мы собираемся создать две группы узлов для рабочих узлов Kubernetes:

  1. Общая группа узлов - группа автомасштабирования со спотовыми экземплярами для запуска системной рабочей нагрузки Kubernetes и рабочей нагрузки, не связанной с графическим процессором.
  2. Группы узлов GPU - группа автомасштабирования со спотовыми инстансами на GPU, которые могут масштабироваться от 0 до необходимого количества экземпляров и обратно до 0.

К счастью, eksctl поддерживает добавление групп узлов Kubernetes в кластер EKS, и эти группы могут состоять из спотовых инстансов или смеси спотовых инстансов и инстансов по требованию.

2.1 Общая группа узлов

Файл конфигурации eksctl содержит кластер EKS в us-west-2 в 3 зонах доступности и первую группу узлов с автомасштабированием General (от 2 до 20 узлов), работающую на диверсифицированных спотовых экземплярах.

---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: gaia-kube
  region: us-west-2
availabilityZones: ["us-west-2a", "us-west-2b", "us-west-2c"]
nodeGroups:
  # spot workers NG - multi AZ, scale from 3
  - name: spot-ng
    ami: auto
    instanceType: mixed
    desiredCapacity: 2
    minSize: 2
    maxSize: 20
    volumeSize: 100
    volumeType: gp2
    volumeEncrypted: true
    iam:
      attachPolicyARNs:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
        - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
        - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      withAddonPolicies:
        autoScaler: true
        ebs: true
        albIngress: true
        cloudWatch: true
    instancesDistribution:
      onDemandPercentageAboveBaseCapacity: 0
      instanceTypes:
        - m4.2xlarge
        - m4.4xlarge
        - m5.2xlarge
        - m5.4xlarge
        - m5a.2xlarge
        - m5a.4xlarge
        - c4.2xlarge
        - c4.4xlarge
        - c5.2xlarge
        - c5.4xlarge
      spotInstancePools: 15
    tags:
      k8s.io/cluster-autoscaler/enabled: 'true'
    labels:
      lifecycle: Ec2Spot
    privateNetworking: true
    availabilityZones: ["us-west-2a", "us-west-2b", "us-west-2c"]
# next: GPU node groups ...

Теперь пришло время объяснить некоторые параметры, используемые в приведенном выше файле конфигурации.

  • ami: auto - eksctl автоматически обнаруживает последний оптимизированный для EKS образ AMI для рабочих узлов на основе указанного региона AWS, версии EKS и типа инстанса. См. Главу AMI, оптимизированный для Amazon EKS в Руководстве пользователя.
  • instanceType: mixed - укажите, что фактический тип экземпляра будет одним из типов экземпляров, определенных в разделе instancesDistribution
  • iam содержит список предопределенных и действующих политик IAM; eksctl создает новую Роль IAM с указанными политиками и прикрепляет эту роль к каждому рабочему узлу EKS. Существует несколько политик IAM, которые необходимо прикрепить к каждому рабочему узлу EKS, см. Раздел Роль IAM рабочего узла Amazon EKS в Руководстве пользователя и документацию eksctl Политики IAM.
  • instancesDistribution - укажите политику смешанного экземпляра для групп автоматического масштабирования EC2, прочтите документацию AWS MixedInstancesPolicy
  • spotInstancePools - указывает количество используемых пулов спотовых инстансов, подробнее
  • tags - теги AWS добавлены в рабочие узлы EKS
  • k8s.io/cluster-autoscaler/enabled будет использовать этот тег для автоматического обнаружения Kubernetes Cluster Autoscaler.
  • privateNetworking: true - все рабочие узлы EKS будут размещены в частных подсетях

Пулы спотовых инстансов

Когда вы используете спотовые инстансы в качестве рабочих узлов, вам необходимо диверсифицировать использование до как можно большего числа пулов спотовых инстансов. Пул спотовых инстансов - это набор неиспользуемых инстансов EC2 с одинаковым типом инстанса (например, m5.large), операционной системой, зоной доступности и сетевыми платформами.

eksctl в настоящее время поддерживает единую спотовую модель выделения ресурсов: lowestPrice стратегию распределения. Эта стратегия позволяет создать парк спотовых инстансов, который будет дешевым и разнообразным. ASG автоматически развертывает самую дешевую комбинацию типов инстансов и зон доступности на основе текущей спотовой цены для указанного вами количества спотовых пулов. Эта комбинация позволяет избежать использования самых дорогих спотовых инстансов.

Диверсификация спотовых инстансов также увеличивает доступность рабочих узлов, обычно не все пулы спотовых инстансов будут прерваны одновременно, поэтому только небольшая часть вашей рабочей нагрузки будет прервана, а группа автоматического масштабирования EC2 заменит прерванные экземпляры из других пулов спотовых инстансов.

Пожалуйста, также подумайте о том, чтобы использовать специальный том для наборов данных, прогресса обучения (контрольных точек) и журналов. Этот том должен быть постоянным, и на него не должно влиять завершение работы экземпляра.

2.2 Группа узлов с питанием от GPU

Следующая часть нашего eksctl файла конфигурации содержит первую группу узлов автомасштабирования GPU (от 0 до 10 узлов), работающую на различных спотовых инстансах с GPU.

При использовании спотовых инстансов на базе GPU рекомендуется создать группу узлов GPU для каждой зоны доступности и настроить Kubernetes Cluster Autoscaler, чтобы избежать автоматической ребалансировки ASG.

Почему это важно? Некоторые спотовые инстансы EC2 на базе графического процессора имеют относительно высокую частоту прерывания (>20% для некоторых типов инстансов графического процессора; отметьте Советчик по спотовым инстансам), а использование нескольких зон доступности и отключение автоматической балансировки кластерного автомасштабирования может помочь свести к минимуму перерывы в работе графического процессора.

# ... EKS cluster and General node group ...
# spot GPU NG - west-2a AZ, scale from 0
  - name: gpu-spot-ng-a
    ami: auto
    instanceType: mixed
    desiredCapacity: 0
    minSize: 0
    maxSize: 10
    volumeSize: 100
    volumeType: gp2
    volumeEncrypted: true
    iam:
      attachPolicyARNs:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
        - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
        - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      withAddonPolicies:
        autoScaler: true
        ebs: true
        fsx: true
        efs: true
        albIngress: true
        cloudWatch: true
    instancesDistribution:
      onDemandPercentageAboveBaseCapacity: 0
      instanceTypes:
        - p3.2xlarge
        - p3.8xlarge
        - p3.16xlarge
        - p2.xlarge
        - p2.8xlarge
        - p2.16xlarge
      spotInstancePools: 5
    tags:
      k8s.io/cluster-autoscaler/node-template/taint/dedicated: nvidia.com/gpu=true
      k8s.io/cluster-autoscaler/node-template/label/nvidia.com/gpu: 'true'
      k8s.io/cluster-autoscaler/enabled: 'true'
    labels:
      lifecycle: Ec2Spot
      nvidia.com/gpu: 'true'
      k8s.amazonaws.com/accelerator: nvidia-tesla
    taints:
      nvidia.com/gpu: "true:NoSchedule"
    privateNetworking: true
    availabilityZones: ["us-west-2a"]
# create additional node groups for `us-west-2b` and `us-west-2c` availability zones ...

Теперь пришло время объяснить некоторые параметры, используемые для настройки группы узлов на базе графического процессора.

  • ami: auto - eksctl автоматически обнаруживает последний оптимизированный для EKS образ AMI с поддержкой графического процессора для рабочих узлов в зависимости от указанного региона AWS, версии EKS и типа инстанса. См. Руководство пользователя AMI, оптимизированный для Amazon EKS с поддержкой графического процессора.
  • iam: withAddonPolicies - если запланированная рабочая нагрузка требует доступа к сервисам хранения AWS, важно включить дополнительные политики IAM (автоматически создаются eksctl)
  • tags - теги AWS добавлены в рабочие узлы EKS
  • k8s.io/cluster-autoscaler/node-template/taint/dedicated: nvidia.com/gpu=true - заражение узла Kubernetes
  • k8s.io/cluster-autoscaler/node-template/label/nvidia.com/gpu: 'true' - Метка узла Kubernetes, используемая Cluster Autoscaler для масштабирования ASG от / до 0
  • nvidia.com/gpu: “true:NoSchedule” - повреждение узла GPU Kubernetes; помогает избежать размещения рабочей нагрузки, не связанной с GPU, на дорогих узлах GPU

Оптимизированное изображение AMI для EKS с поддержкой графического процессора

Помимо стандартной конфигурации AMI, оптимизированной для Amazon EKS, AMI графического процессора включает в себя следующее:

  • Драйверы NVIDIA
  • Пакет nvidia-docker2
  • nvidia-container-runtime (как среда выполнения по умолчанию)

Масштабирование группы узлов до / от 0

Из Kubernetes Cluster Autoscaler 0.6.1 - можно масштабировать группу узлов до / от 0, предполагая, что все условия увеличения и уменьшения выполняются.

Если вы используете nodeSelector, вам нужно пометить ASG ключом шаблона узла k8s.io/cluster-autoscaler/node-template/label/ и k8s.io/cluster-autoscaler/node-template/taint/, если вы используете taints.

3. Планирование рабочей нагрузки графического процессора.

3.1 Расписание на основе ресурсов GPU

Плагин NVIDIA для устройств Kubernetes показывает количество графических процессоров на каждом узле вашего кластера. После установки плагина можно использовать nvidia/gpu ресурс Kubernetes на узлах GPU и для рабочих нагрузок Kubernetes.

Выполните эту команду, чтобы применить подключаемый модуль устройства Nvidia Kubernetes как daemonset, работающий только на рабочих узлах AWS с GPU, используя tolerations и nodeAffinity

kubectl create -f kubernetes/nvidia-device-plugin.yaml
kubectl get daemonset -nkube-system

с использованием nvidia-device-plugin.yaml файла ресурсов Kubernetes

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset-1.12
  namespace: kube-system
spec:
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      containers:
      - image: nvidia/k8s-device-plugin:1.11
        name: nvidia-device-plugin-ctr
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: beta.kubernetes.io/instance-type
                operator: In
                values:
                - p3.2xlarge
                - p3.8xlarge
                - p3.16xlarge
                - p3dn.24xlarge
                - p2.xlarge
                - p2.8xlarge
                - p2.16xlarge

3.2 Пороки и терпимость

Kubernetes портит позволяет узлу отражать набор подов. Ошибки и допуски работают вместе, чтобы гарантировать, что поды не будут запланированы на несоответствующие узлы. На узел наносится один или несколько порчи; это означает, что узел не должен принимать никакие стручки, не терпящие порчи. Допуски применяются к модулям и позволяют (но не требуют) планировать модули на узлах с соответствующими загрязнениями.

См. Документацию Kubernetes Taints and Tolerations для более подробной информации.

Чтобы запустить рабочую нагрузку GPU на узлах спотовых инстансов с питанием от GPU, с nvidia.com/gpu: "true:NoSchedule" taint, рабочая нагрузка должна включать в себя обе совпадающие конфигурации tolerations и nodeSelector.

Развертывание Kubernetes с 10 репликами pod с nvidia/gpu: 1 лимитом:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cuda-vector-add
  labels:
    app: cuda-vector-add
spec:
  replicas: 10
  selector:
    matchLabels:
      app: cuda-vector-add
  template:
    metadata:
      name: cuda-vector-add
      labels:
        app: cuda-vector-add
    spec:
      nodeSelector:
        nvidia.com/gpu: "true"
      tolerations:
      - key: "nvidia.com/gpu"
        operator: "Exists"
        effect: "NoSchedule"
      containers:
        - name: cuda-vector-add
          image: "k8s.gcr.io/cuda-vector-add:v0.1"
          resources:
            limits:
              nvidia.com/gpu: 1 # requesting 1 GPU

Разверните cuda-vector-add развертывание и посмотрите, как новые узлы на базе графического процессора добавляются в кластер EKS.

# list Kubernetes nodes before running GPU workload
kubectl get nodes --output="custom-
columns=NAME:.metadata.name,TYPE:.metadata.labels.beta\.kubernetes\.io\/instance-type"
NAME                                            TYPE
ip-192-168-151-104.us-west-2.compute.internal   c4.4xlarge
ip-192-168-171-140.us-west-2.compute.internal   c4.4xlarge
# deploy GPU workload on EKS cluster with tolerations for nvidia/gpu=true
kubectl create -f kubernetes/examples/vector/vector-add-dpl.yaml
# list Kubernetes nodes after several minutes to see new GPU nodes added to the cluster
kubectl get nodes --output="custom-columns=NAME:.metadata.name,TYPE:.metadata.labels.beta\.kubernetes\.io\/instance-type"
NAME                                            TYPE
ip-192-168-101-60.us-west-2.compute.internal    p2.16xlarge
ip-192-168-139-227.us-west-2.compute.internal   p2.16xlarge
ip-192-168-151-104.us-west-2.compute.internal   c4.4xlarge
ip-192-168-171-140.us-west-2.compute.internal   c4.4xlarge
ip-192-168-179-248.us-west-2.compute.internal   p2.16xlarge

Как видите, в кластер были добавлены 3 новых узла с графическим процессором (p2.16xlarge) в 3 зонах доступности. Когда вы удаляете рабочую нагрузку GPU, кластер уменьшит группу узлов GPU до 0 через 10 минут.

Резюме

Следуйте этому руководству, чтобы создать кластер EKS (Kubernetes) с группой узлов на базе графического процессора, работающий на спотовых экземплярах и масштабируемый от / до 0 узлов.

использованная литература

- Репозиторий EKS Spot Cluster на GitHub с кодом для этого блога
- Полное руководство по запуску спотовых инстансов EC2 в качестве рабочих узлов Kubernetes от Рана Шейнберга
- Kubernetes Cluster Autoscaler
- Пороки и терпимости Документация Kubernetes

Отказ от ответственности

Неважно, где я работаю, все мои мнения - мои собственные.

Черновик опубликован на https://alexei-led.github.io.