Подробное руководство по созданию и настройке кластера Kubernetes производственного уровня на AWS с помощью Terraform, Helm и других инструментов с открытым исходным кодом.

Согласно Отчету Flexera о состоянии облака за 2021 год, AWS лидирует по доле рынка оркестрации контейнеров: 51 % респондентов используют Amazon EKS и ECS по сравнению с 43 % для AKS и 31 % для GKE.

Flexera не раскрывает точную разбивку между использованием ECS и EKS, но, согласно последнему отчету Datadog Container Report, использование EKS является самым низким с точки зрения управляемых сервисов Kubernetes, предлагаемых основными облачными платформами.

Хотя результаты этого опроса могут быть искажены из-за размера выборки, как ни странно, они совпадают с моим опытом работы с EKS. AWS объединяет ECS, ECR, Fargate и EKS в одно предложение Containers и, как правило, отстает от AKS и GKE с точки зрения специфичных для Kubernetes функций, таких как поддержка последней версии Kubernetes, бета-функции ( например, вертикальное автомасштабирование pod, настраиваемые аргументы kubelet) и управляемые параметры (например, автоматическое восстановление узла, автоматические обновления, панель инструментов).

Несмотря на эти недостатки, учитывая доминирование AWS на более широком рынке облачных вычислений, многие организации выберут EKS в качестве удобного управляемого поставщика Kubernetes. Если вы хотите спроектировать и подготовить кластер EKS производственного уровня, вот некоторые распространенные проблемы, с которыми я столкнулся, и обходные пути для навигации по сложной экосистеме EKS.

Примечание. Более подробное сравнение управляемых предложений Kubernetes см. в статье Состояние управляемого Kubernetes в 2021 году.

Отправная точка

Есть два популярных способа развертывания EKS: eksctl и Terraform. eksctl — это инструмент с открытым исходным кодом, управляемый Weaveworks, который использует CloudFormation для загрузки и настройки EKS. Если ваш рабочий процесс уже вращается вокруг CloudFormation, eksctl может подойти для начала, поскольку у AWS есть хорошие воркшопы, задокументированные для этого случая. Однако, если вы ищете более традиционный подход IaC, лучше использовать Terraform.

Для Terraform и AWS, и Gruntwork предоставляют базовую архитектуру и шаблоны для начала работы:

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

Остерегайтесь исчерпания IP-адресов EKS

Первое, что нужно учитывать перед развертыванием кластера EKS, — это проектирование VPC и выбор сетевого интерфейса контейнера (CNI). По умолчанию EKS работает с AWS CNI, который был разработан для совместимости с другими сервисами AWS, такими как журналы потоков VPC. Благодаря такому выбору дизайна каждому модулю назначается IP-адрес из подсети. Это означает, что не только ваши микросервисы используют IP-адрес, но и другие вспомогательные модули, которыми управляет AWS (например, aws-node, coredns, kube-proxy), а также общие инструменты, такие как агрегаторы журналов, агенты мониторинга и инструменты для конкретных узлов (например, обработчик точечного завершения, агенты обновления), развернутые в виде наборов демонов, также будут потреблять IP-адреса. Чтобы усугубить эту проблему, каждый тип экземпляра имеет максимальное количество IP-адресов, которые могут быть назначены на основе максимального количества сетевых интерфейсов и частных IP-адресов на интерфейс. Другими словами, если вы используете небольшие типы экземпляров для своего кластера, вы очень быстро достигнете этого предела.

Итак, что можно сделать, чтобы смягчить эту проблему?

  1. Используйте вторичные диапазоны CIDR (100.64.0.0/10 и 198.19.0.0/16) для расширения сети VPC.
  2. Включить IPv6 во время создания кластера
  3. Установите для параметра ENABLE_PREFIX_DELEGATION значение true на AWS CNI 1.9.0+ . Это добавит префиксы IPv4-адресов /28.
  4. Используйте другой CNI, например Бязь, Фланель, Плетение или Реснички.

Первые три решения, перечисленные выше, относятся к домену AWS, поэтому это может быть хорошим шагом вперед, если вы хотите убедиться, что у вас есть полная поддержка AWS. С другой стороны, другие CNI предоставляют другие функции, такие как eBPF, шифрование WireGuard и поддержку сетевых политик.

Используйте бутылочную ракету

Подобно ОС Google, оптимизированной для контейнеров, AWS предоставляет Bottlerocket, операционную систему на базе Linux, предназначенную для размещения контейнеров. Поскольку Bottlerocket содержит только компоненты, необходимые для запуска контейнеров, он имеет меньшую поверхность атаки, чем AMI Amazon Linux 2 по умолчанию.

Одной из лучших функций Bottlerocket являются автоматические обновления безопасности. Он следует «Структуре обновления» (TUF) для безопасного обновления версии Bottlerocket с автоматическим откатом. Это снижает необходимость обновления AMI каждые несколько недель для всех базовых узлов.

Обратите внимание, что по умолчанию Bottlerocket использует два тома хранилища:

Если вам нужно изменить какой-либо из этих параметров, установите соответствующие значения, например:

additional_ebs_volumes = [{
  block_device_name = "/dev/xvdb"
  volume_size       = "100"
  encrypted         = true
}]

Если по какой-то причине Bottlerocket не работает для вашего варианта использования, установите SSM Agent и Inspector для защиты вашего AMI. Не забудьте также привязать роль AmazonSSMMangedInstanceCore к узлам:

workers_additional_policies = ["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]
OR
self_managed_node_group_defaults = {
  ...
  iam_role_additional_policies = ["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"]
}

Используйте расширения EKS с умом

До недавнего времени пользователям EKS приходилось самостоятельно управлять такими компонентами Kubernetes, как kube-proxy , core-dns и VPC CNI. Для любых кластеров EKS 1.18 или более поздней версии Amazon теперь предоставляет управляемую версию для каждого из этих компонентов, чтобы обеспечить проверку AWS последних исправлений безопасности и исправлений ошибок.

Для новых кластеров выбирайте надстройки kube-proxy и core-dns, если вы не ожидаете значительных изменений в конфигурациях core-dns. Что касается VPC CNI, ответ будет зависеть от модификаций или проектных решений, сделанных выше (например, использование AWS VPC CNI по сравнению с альтернативами с открытым исходным кодом). Существует также надстройка драйвера EBS CSI, но она доступна только в предварительной версии, поэтому я подожду, пока она не появится в GA в будущих выпусках.

Шифрование томов etcd и EBS

Секреты Kubernetes по умолчанию хранятся в незашифрованном виде в etcd на главном узле. EKS дает возможность использовать KMS для включения конвертного шифрования секретов Kubernetes, но это легко упустить из виду. Настройте блок cluster_encryption_config в модуле EKS:

cluster_encryption_config = [{    
  provider_key_arn = aws_kms_key.eks.arn    
  resources        = ["secrets"]  
}]

И соответственно создайте KMS ресурсы:

resource "aws_kms_key" "eks" {
  description             = "EKS Secret Encryption Key"
  deletion_window_in_days = 7
  enable_key_rotation     = true
  tags = local.tags
}
resource "aws_kms_key" "ebs" {
  description             = "Customer managed key to encrypt EKS managed node group volumes"
  deletion_window_in_days = 7
  policy                  = data.aws_iam_policy_document.ebs.json
}
# This policy is required for the KMS key used for EKS root volumes, so the cluster is allowed to enc/dec/attach encrypted EBS volumes
data "aws_iam_policy_document" "ebs" {
  # Copy of default KMS policy that lets you manage it
  statement {
    sid       = "Enable IAM User Permissions"
    actions   = ["kms:*"]
    resources = ["*"]
principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
    }
  }
# Required for EKS
  statement {
    sid = "Allow service-linked role use of the CMK"
    actions = [
      "kms:Encrypt",
      "kms:Decrypt",
      "kms:ReEncrypt*",
      "kms:GenerateDataKey*",
      "kms:DescribeKey"
    ]
    resources = ["*"]
principals {
      type = "AWS"
      identifiers = [
        "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling", # required for the ASG to manage encrypted volumes for nodes
        module.eks.cluster_iam_role_arn,                                                                                                            # required for the cluster / persistentvolume-controller to create encrypted PVCs
      ]
    }
  }
statement {
    sid       = "Allow attachment of persistent resources"
    actions   = ["kms:CreateGrant"]
    resources = ["*"]
principals {
      type = "AWS"
      identifiers = [
        "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling", # required for the ASG to manage encrypted volumes for nodes
        module.eks.cluster_iam_role_arn,                                                                                                            # required for the cluster / persistentvolume-controller to create encrypted PVCs
      ]
    }
condition {
      test     = "Bool"
      variable = "kms:GrantIsForAWSResource"
      values   = ["true"]
    }
  }
}

Чтобы настроить тома EBS для использования KMS, вам также необходимо создать новый объект StorageClass в Kubernetes и настроить kmsKeyId, который вы создали с помощью приведенного выше кода Terraform. Вы также можете сделать этот новый класс хранилища по умолчанию, чтобы гарантировать, что новые тома EBS, подготовленные с помощью Persistent Volume Claims, всегда будут зашифрованы.

Рассмотрите возможность управления aws-auth вручную

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

Есть два обходных пути:

  1. Удалите ресурс Kubernetes из состояния перед применением изменений (т. е. terraform state rm module.eks.kubernetes_config_map.aws_auth, затем terraform plan).
  2. Установите manage_aws_auth = false в модуле EKS и управляйте configmap вне Terraform (см., как модуль управляет этим здесь).

Настройте автомасштабирование кластера соответствующим образом

В отличие от GKE, EKS не поставляется с автомасштабированием кластера (возможно, в будущем он станет надстройкой, управляемой EKS). Используйте федеративную аутентификацию OIDC и роли IAM для учетных записей служб для развертывания автомасштабирования кластера с включенным автоматическим обнаружением с помощью тегов, настроенных модулем EKS Terraform.

Под капотом автомасштабирования кластера используются группы автоматического масштабирования Amazon EC2 для управления каждой группой узлов, что означает, что на него распространяются те же ограничения, что и на ASG. Например, поскольку тома EBS зависят от зоны, простое развертывание средства автоматического масштабирования кластера может не вызвать событие масштабирования в нужной зоне доступности для StatefulSet, поддерживаемых томами EBS. Чтобы избежать этого, обязательно настройте автомасштабирование кластера с помощью:

  • balance-similar-node-groups=true
  • Группы узлов, настроенные в разных зонах доступности

Альтернативным решением является использование Karpenter, который работает аналогично процессу динамической подготовки узлов GKE Autopilot. Для более глубокого погружения в Карпентер, проверьте:



Используйте инструменты с открытым исходным кодом

К сожалению, ни Terraform, ни AWS не предоставляют возможности автоматического развертывания изменений в базовых экземплярах в кластере EKS. Это означает, что каждый раз, когда необходимо обновить AMI или обновить версии Kubernetes, все узлы необходимо вручную слить и обновить. Способ реализовать такое поведение через Terraform может включать создание новой группы узлов и написание сценария для удаления старых групп узлов и их масштабирования. Другой вариант — использовать deploy функционал инструмента kubergrunt, поддерживаемый командой Gruntwork. Это существенно автоматизирует создание новых групп узлов, блокировку и удаление старых узлов, а также удаление старых рабочих узлов.

Чтобы узнать о других инструментах с открытым исходным кодом, помогающих в управлении EKS, загляните в Полезные инструменты для лучшей разработки Kubernetes:



Заключительные примечания

За последние годы компания EKS добилась огромного прогресса в обеспечении беспрепятственного создания кластера EKS и управления им. Он по-прежнему отстает от GKE и AKS с точки зрения управляемых функций, но с небольшими изменениями существующих наборов инструментов можно легко собрать кластер производственного уровня. Если есть другие советы и приемы, которые я упустил при работе с EKS в масштабе, пожалуйста, прокомментируйте ниже.