Для последнего проекта для AWS EKS использовал AMI на базе
https://aws.amazon.com/bottlerocket/
Название амишки и версию в голове и коде не держу, смелости и дурости у меня много, так что у меня идёт latest (на самом деле там почти хардкод, просто выглядит пугающе). Сбоев не было никогда из-за последнего в ssm.
С точки зрения кода там просто:
Если пугает такое обновление версий, то можно залепить такое и обновлять раз в месяц/квартал вручную.
Стратегий у меня несколько:
- event-driven
- load-driven
Ноды готовы очень быстро. При тюнинге в основном секунд 15.
В самых худших кейсах 2 минут 24 секунды. Такое было раз 5 по наблюдениям.
Зависит от типа инстанса, региона и спот ли.
Например типичный сценарий. Есть сервис в десятках подов, кто читает SQS. Они разные и цели у них разные.
- всего 2 ноды, 0 подов с без рабочей нагрузки.
- прилетели тонны мессаджей в AWS SQS, секунд за 5-15 на бурст в 100000+ сообщений
- KEDA через 5 секунд после threshold поднимается пару десятков подов
- кластер-автоскейлер/карпентер (зависит от проекта) поднимает одну или несколько нод в нод группу.
* Кластер автоскейлер мгновенно триггерит, если видит, что не хватает ресурсов и хоть что-то в
- сами ноды на ботлрокете поднимаются секунд за 12-15, каждая из нод. то есть через 15 секунд в основном уже
- поды на новых нодах шедулятся, проходят 2 пробы(startup, readiness), ещё 8-15 секунд.
- приложение готово к работе и разбирает мессаджи в sqs (+20 секунд к таймингам, если на этой SQS long polling)
- после разбора sqs всё тушится к нулям через KEDA, чтобы не платить
Ради теста повторил, лог такой:
Как видно ноды очень быстро стартуют. Это самый главный плюс.
Почему
- крайне быстрый старт нод, основная причина
- чуть более удобная(для меня) кастомизация kubelet, хоть там и не любимый мной TOML
- ну а как же без пункта best-CV-project, надо и новые вещи изучать
#AWS #EKS #bottlerocket
bottlerocket.https://aws.amazon.com/bottlerocket/
Название амишки и версию в голове и коде не держу, смелости и дурости у меня много, так что у меня идёт latest (на самом деле там почти хардкод, просто выглядит пугающе). Сбоев не было никогда из-за последнего в ssm.
С точки зрения кода там просто:
locals {
aws_ami_name = "bottlerocket"
aws_ami_architecture = "x86_64"
aws_ami_type = "${upper(local.aws_ami_name)}_${local.aws_ami_architecture}"
}
data "aws_ssm_parameter" "eks_ami_image_version" {
name = "/aws/service/${local.aws_ami_name}/aws-k8s-${aws_eks_cluster.eks.version}/${local.aws_ami_architecture}/latest/image_version"
}
resource "aws_eks_node_group" "blue-green-group" {
...
ami_type = local.aws_ami_type
release_version = data.aws_ssm_parameter.eks_ami_image_version.value
...Если пугает такое обновление версий, то можно залепить такое и обновлять раз в месяц/квартал вручную.
lifecycle {
ignore_changes = [release_version]
...
}Стратегий у меня несколько:
- event-driven
- load-driven
Ноды готовы очень быстро. При тюнинге в основном секунд 15.
В самых худших кейсах 2 минут 24 секунды. Такое было раз 5 по наблюдениям.
Зависит от типа инстанса, региона и спот ли.
Например типичный сценарий. Есть сервис в десятках подов, кто читает SQS. Они разные и цели у них разные.
- всего 2 ноды, 0 подов с без рабочей нагрузки.
- прилетели тонны мессаджей в AWS SQS, секунд за 5-15 на бурст в 100000+ сообщений
- KEDA через 5 секунд после threshold поднимается пару десятков подов
- кластер-автоскейлер/карпентер (зависит от проекта) поднимает одну или несколько нод в нод группу.
* Кластер автоскейлер мгновенно триггерит, если видит, что не хватает ресурсов и хоть что-то в
Pending статусе из POD-ов- сами ноды на ботлрокете поднимаются секунд за 12-15, каждая из нод. то есть через 15 секунд в основном уже
ready.- поды на новых нодах шедулятся, проходят 2 пробы(startup, readiness), ещё 8-15 секунд.
- приложение готово к работе и разбирает мессаджи в sqs (+20 секунд к таймингам, если на этой SQS long polling)
- после разбора sqs всё тушится к нулям через KEDA, чтобы не платить
Ради теста повторил, лог такой:
ip-10-1-33-89.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal NotReady <none> 1s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal NotReady <none> 1s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal NotReady <none> 1s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal NotReady <none> 1s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal NotReady <none> 10s v1.30.5-eks-baa6d11
ip-10-1-33-89.ec2.internal Ready <none> 13s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 0s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 5s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal NotReady <none> 10s v1.30.5-eks-baa6d11
ip-10-1-34-52.ec2.internal Ready <none> 14s v1.30.5-eks-baa6d11
Как видно ноды очень быстро стартуют. Это самый главный плюс.
Почему
bottlerocket:- крайне быстрый старт нод, основная причина
- чуть более удобная(для меня) кастомизация kubelet, хоть там и не любимый мной TOML
#AWS #EKS #bottlerocket
🆒3❤1
Мне уже двое написали про
Немного теории:
В Kubernetes существует два типа эвикции (выселения) подов:
- Kubernetes сначала посылает сигнал SIGTERM поду, давая ему время корректно завершить работу
- Pod получает grace period (период отсрочки) для завершения работы
- По умолчанию grace period составляет 30 секунд
Можно настроить через параметр
- Происходит немедленное удаление пода
- Pod получает сигнал SIGKILL
- Используется когда нужно срочно освободить ресурсы
Настраивается через параметр
Основные триггеры эвикции:
-
-
-
-
Пороговые значения можно задавать как в процентах, так и в абсолютных величинах (например, 100Mi для памяти).
Дефолтные значения ванильного k8s можете посмотреть тут:
https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/
Для
❕Выше была общая теория, ниже практика.
#AWS #EKS #bottlerocket
bottlerocket, так что не теряя времени, пока смелые духом не запустили это в прод, продолжу.Немного теории:
В Kubernetes существует два типа эвикции (выселения) подов:
Soft Eviction (Мягкое выселение):- Kubernetes сначала посылает сигнал SIGTERM поду, давая ему время корректно завершить работу
- Pod получает grace period (период отсрочки) для завершения работы
- По умолчанию grace period составляет 30 секунд
Можно настроить через параметр
--eviction-soft-grace-period /--eviction-softHard Eviction (Жёсткое выселение):- Происходит немедленное удаление пода
- Pod получает сигнал SIGKILL
- Используется когда нужно срочно освободить ресурсы
Настраивается через параметр
--eviction-hardОсновные триггеры эвикции:
-
memory.available: доступная память-
nodefs.available: место на диске ноды-
nodefs.inodesFree: свободные иноды-
imagefs.available: место для образов контейнеровПороговые значения можно задавать как в процентах, так и в абсолютных величинах (например, 100Mi для памяти).
Дефолтные значения ванильного k8s можете посмотреть тут:
https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/
Для
AL2023 вот такие дефолт значения:memory.available: "100Mi"
nodefs.available: "10%"
nodefs.inodesFree: "5%"
imagefs.available: "15%"
❕Выше была общая теория, ниже практика.
#AWS #EKS #bottlerocket
🤔1
У
Вы это можете проверить командой на ноде
Ну или же посмотреть в конфиге:
https://github.com/bottlerocket-os/bottlerocket/blob/1.20.x/packages/kubernetes-1.29/kubelet-kubeconfig
Там пусто.
Что же это значит?
Это значит, что по дефолту если у вас:
- под(ы) с эфемерным хранилищем сожрёт все место на ноде
- под(ы) без лимитов цпу сожрёт всё процессорное время на ноде
- под(ы) без лимитов памяти сожрёт всю память на ноде
- диск заполнится имаджами под(а/ов) и гарбадж коллектор не успеет отработать
Ваша нода умрёт. Системные компоненты перестанут работать, кублету не хватит памяти и нода умрёт.
Нода не защищена от неконтролируемых действий со стороны подов.
Давайте это исправим:
- создадим темплейт/конфиг
- внутри добавим нечто типа такого
- добавить этот конфиг через юзердату
Не буду описывать все параметры, они описаны тут:
https://bottlerocket.dev/en/os/1.20.x/api/settings/kubernetes/#eviction-hard
https://github.com/bottlerocket-os/bottlerocket/blob/develop/README.md#description-of-settings
Цифры можете брать из дефолта(выше писал), в моём примере цифры ровно под те требования, которые есть у меня в моим кластерам и приложениям. Не обязательно использовать все параметры, что есть в моём примере, можете только 4 параметра использовать.
* если вы хотите выдать доступ к вашим нодам, то в моем конфиге надо false поменять на true и дальше по инструкции
https://github.com/bottlerocket-os/bottlerocket?tab=readme-ov-file#control-container
#AWS #EKS #bottlerocket
bottlerocket нет дефолтных значений.Вы это можете проверить командой на ноде
apiclient -u /settings | jq
Ну или же посмотреть в конфиге:
https://github.com/bottlerocket-os/bottlerocket/blob/1.20.x/packages/kubernetes-1.29/kubelet-kubeconfig
Там пусто.
Что же это значит?
Это значит, что по дефолту если у вас:
- под(ы) с эфемерным хранилищем сожрёт все место на ноде
- под(ы) без лимитов цпу сожрёт всё процессорное время на ноде
- под(ы) без лимитов памяти сожрёт всю память на ноде
- диск заполнится имаджами под(а/ов) и гарбадж коллектор не успеет отработать
Ваша нода умрёт. Системные компоненты перестанут работать, кублету не хватит памяти и нода умрёт.
Нода не защищена от неконтролируемых действий со стороны подов.
Давайте это исправим:
- создадим темплейт/конфиг
bottlerocket.tpl в нашем репозитории- внутри добавим нечто типа такого
[settings.kubernetes]
api-server = "${endpoint}"
cluster-certificate = "${cluster_auth_base64}"
cluster-name = "${cluster_name}"
pod-pids-limit = 1024
image-gc-high-threshold-percent = 85
image-gc-low-threshold-percent = 80
container-log-max-files = 50
container-log-max-size = "100Mi"
[settings.kubernetes.system-reserved]
cpu = "200m"
ephemeral-storage = "1Gi"
memory = "1Gi"
[settings.kubernetes.kube-reserved]
memory = "893Mi"
[settings.kernel]
lockdown = "integrity"
[settings.host-containers.admin]
enabled = ${enable_admin_container}
[settings.host-containers.control]
enabled = ${enable_control_container}
[settings.kubernetes.eviction-hard]
"memory.available" = "1Gi"
"nodefs.available" = "20%"
"nodefs.inodesFree" = "5%"
"imagefs.available" = "15%"
[settings.kubernetes.eviction-soft]
"memory.available" = "10%"
[settings.kubernetes.eviction-soft-grace-period]
"memory.available" = "30s"
- добавить этот конфиг через юзердату
resource "aws_launch_template" "node-launch-template" {
...
user_data = base64encode(templatefile("${path.module}/../../templates/bottlerocket.tpl",
{
"cluster_name" = aws_eks_cluster.eks.name #обязательный параметр!!!
"endpoint" = aws_eks_cluster.eks.endpoint #обязательный параметр!!!
"cluster_auth_base64" = aws_eks_cluster.eks.certificate_authority[0].data #обязательный параметр!!!
"aws_region" = var.AWS_DEFAULT_REGION #обязательный параметр!!!
"enable_admin_container" = false
"enable_control_container" = true
}
))
}Не буду описывать все параметры, они описаны тут:
https://bottlerocket.dev/en/os/1.20.x/api/settings/kubernetes/#eviction-hard
https://github.com/bottlerocket-os/bottlerocket/blob/develop/README.md#description-of-settings
Цифры можете брать из дефолта(выше писал), в моём примере цифры ровно под те требования, которые есть у меня в моим кластерам и приложениям. Не обязательно использовать все параметры, что есть в моём примере, можете только 4 параметра использовать.
* если вы хотите выдать доступ к вашим нодам, то в моем конфиге надо false поменять на true и дальше по инструкции
https://github.com/bottlerocket-os/bottlerocket?tab=readme-ov-file#control-container
#AWS #EKS #bottlerocket
🤩2
Bottlerocket, storage.
Ну а куда без боттлрокета.
Допустим вы решили перейти на боттлрокет после моих постов - https://xn--r1a.website/makebreakreflect/35
Сразу споткнувшись про пустой дефолтный конфиг кублета читаете и тут
https://xn--r1a.website/makebreakreflect/38
Готово.
У вас и кластер AWS EKS и нод группа(ы) и лаунчтемплейт.
Всё работает, всё круто, но спустя время вы замечаете, что у вас участились алёрты
Так же в ивентах у вас нечто типа
"Какогох*ра рожна" думаете вы, ведь у меня диск как был 200 гигабайт, так и остался.
Смотрите свой код, видите там нечто типа
"ну да, двести гигов" говорите вы вслух самому себе и идёте проверять терраформ/террагрант план.
Всё ок. Никаких
Лезете в кубер, смотрите а чо там рили.
Внезапно там ну вообще ни 200 гигов, там 20.
Начинаете перепроверять код, лаунчемплейт, ласт вершн и issue github.
А нет ничего.
У вас желаемое 200 гигов, а реально видно 20.
И тут подстава, откуда вы не ждали.
У
Чтобы ноде под поды выделить больше места дефолта с 20 гигами, вам надо выдать отдельный маунт на побольше.
Терраформ план, терраформ апплай, проверяем
Отлично, теперь под эфемерку у нас 200 гигов, а не дефолтные 20(или 30, я не помню если честно) гигабайт.
Разуемся, алёрты пропадают, эфемерки всем хватает, кластер снова сладкий как яблочки с огорода у бабушки.
Кому интересно могут почитать на официальном сайте детальнейшее описание причин, но там на самом деле скукота.
#aws #eks #bottlerocket
Ну а куда без боттлрокета.
Допустим вы решили перейти на боттлрокет после моих постов - https://xn--r1a.website/makebreakreflect/35
Сразу споткнувшись про пустой дефолтный конфиг кублета читаете и тут
https://xn--r1a.website/makebreakreflect/38
Готово.
У вас и кластер AWS EKS и нод группа(ы) и лаунчтемплейт.
Всё работает, всё круто, но спустя время вы замечаете, что у вас участились алёрты
DiskPressure.Так же в ивентах у вас нечто типа
The node had condition: [DiskPressure].
The node was low on resource: ephemeral-storage. Threshold quantity: 4281126156, available: 3438556Ki
"Какого
Смотрите свой код, видите там нечто типа
resource "aws_launch_template" "node-launch-template" {
...
block_device_mappings {
device_name = "/dev/xvda"
ebs {
volume_size = 200
volume_type = "gp3"
}
}
..."ну да, двести гигов" говорите вы вслух самому себе и идёте проверять терраформ/террагрант план.
Всё ок. Никаких
lifecycle {
ignore_changes Лезете в кубер, смотрите а чо там рили.
kubectl get nodes -o yaml | grep -i -A6 ephemeral-storage
Внезапно там ну вообще ни 200 гигов, там 20.
Начинаете перепроверять код, лаунчемплейт, ласт вершн и issue github.
А нет ничего.
У вас желаемое 200 гигов, а реально видно 20.
И тут подстава, откуда вы не ждали.
У
bottlerocket не совсем типичный подход к монтированию томов.Чтобы ноде под поды выделить больше места дефолта с 20 гигами, вам надо выдать отдельный маунт на побольше.
resource "aws_launch_template" "node-launch-template" {
...
# !!! вот тут много не надо, это для самой ноды, операционка, можно хоть 10
block_device_mappings {
device_name = "/dev/xvda"
ebs {
volume_size = 20
volume_type = "gp3"
}
}
# !!! вот это добавляем, для POD-ов
block_device_mappings {
device_name = "/dev/xvdb"
ebs {
volume_size = 200
volume_type = "gp3"
}
}Терраформ план, терраформ апплай, проверяем
kubectl get nodes -o yaml | grep -i -A6 ephemeral-storage
Отлично, теперь под эфемерку у нас 200 гигов, а не дефолтные 20(или 30, я не помню если честно) гигабайт.
Разуемся, алёрты пропадают, эфемерки всем хватает, кластер снова сладкий как яблочки с огорода у бабушки.
Кому интересно могут почитать на официальном сайте детальнейшее описание причин, но там на самом деле скукота.
#aws #eks #bottlerocket
👍6
#aws #eks #sqs #CostOptimization
Материал уровня middle.
Снова про экономию.
У нас есть AWS SQS.
В него прилетает миллион вебхуков с полезным и важным payload.
Бывают пики, бывают нет.
У нас есть AWS EKS и приложение в POD-e, который вычитывает SQS, процессит и всё ок.
Нам надо настроить масштабирование не за счёт CPU/memory usage, а за счёт количества сообщений.
В этом нам помогает KEDA. Опустим этапы установки/настройки/прав и авторизации.
У нас есть готовый манифест
Всё работает, всё скейлится, всё ок.
В HPA некрасиво выглядят цифры, хочется видеть точное количество мессаджем. Добавляем
И теперь в
Этого нам мало, нужна точная подстройка.
Читаем дальше доку, у нас есть адвансед настройки.
Теперь у нас всё динамически скейлится, прописаны все триггеры, трешхолды.
Всё отлично и бизнес ликует(не вру, прям ликует, сильно помогло).
Однако меня, как рьяного и верного пса девопс церкви, напрягает, что в период высокой нагрузки всё упирается в максимум реплик. Да, можно поставить не 50, а 100, но я думаю, что настройка неверная.
Углубляемся дальше в доку(вру, я ничо не понял и просто спросил ребят-гуру-AWS-технологий в телеге) и вспоминаем про визибл/анвизибл настройки у sqs.
https://keda.sh/docs/2.14/scalers/aws-sqs/
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
Окончательно пилим манифест.
Отлично. Теперь самая точная и потрясающая настройка.
Материал уровня middle.
Снова про экономию.
У нас есть AWS SQS.
В него прилетает миллион вебхуков с полезным и важным payload.
Бывают пики, бывают нет.
У нас есть AWS EKS и приложение в POD-e, который вычитывает SQS, процессит и всё ок.
Нам надо настроить масштабирование не за счёт CPU/memory usage, а за счёт количества сообщений.
В этом нам помогает KEDA. Опустим этапы установки/настройки/прав и авторизации.
У нас есть готовый манифест
scaledobject.---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
...
spec:
cooldownPeriod: 300
maxReplicaCount: 50
minReplicaCount: 2
pollingInterval: 30
scaleTargetRef:
name: application
triggers:
- authenticationRef:
name: keda-aws-credentials
metadata:
awsRegion: us-east-1
identityOwner: operator
queueLength: "500"
queueURL: https://sqs.us-east-1.amazonaws.com/123456789/sqsname
type: aws-sqs-queue
Всё работает, всё скейлится, всё ок.
В HPA некрасиво выглядят цифры, хочется видеть точное количество мессаджем. Добавляем
metricType---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
...
spec:
...
metricType: Value
И теперь в
kubectl get hpa blablabla видим точное количество мессаджей в TARGETS(а не системы счисления инопланетян).Этого нам мало, нужна точная подстройка.
Читаем дальше доку, у нас есть адвансед настройки.
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
...
spec:
advanced:
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
policies:
- periodSeconds: 15
type: Pods
value: 1
stabilizationWindowSeconds: 300
scaleUp:
policies:
- periodSeconds: 15
type: Pods
value: 1
selectPolicy: Max
stabilizationWindowSeconds: 60
... (остальное так же)
Теперь у нас всё динамически скейлится, прописаны все триггеры, трешхолды.
Всё отлично и бизнес ликует(не вру, прям ликует, сильно помогло).
Однако меня, как рьяного и верного пса девопс церкви, напрягает, что в период высокой нагрузки всё упирается в максимум реплик. Да, можно поставить не 50, а 100, но я думаю, что настройка неверная.
Углубляемся дальше в доку(вру, я ничо не понял и просто спросил ребят-гуру-AWS-технологий в телеге) и вспоминаем про визибл/анвизибл настройки у sqs.
https://keda.sh/docs/2.14/scalers/aws-sqs/
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
Окончательно пилим манифест.
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
...
spec:
advanced:
...(тут тоже самое)
metadata:
...
scaleOnInFlight: "false" << - - вот это вот важное нам
...
Отлично. Теперь самая точная и потрясающая настройка.
🔥5
#aws #eks #sqs #CostOptimization
Благодаря точной настройке мы неслабо экономим:
- во время нагрузки мы не скейлим так много реплик
- нет большого лишнего скейла реплик - нет и скейла нод кластера AWS EKS
- нет скейла нод - платим серьёзно меньше
Всего один параметр и в разы снижаем нагрузку и косты.
❕Прежде чем делать подобное, уточните у девелоперов и бизнеса - подойдёт ли это вам и продукту.
Не все процессинги можно переключить только на инфлайт режим.
Полный пример манифеста(код в телеге неудобно читать).
https://gist.github.com/kruchkov-alexandr/e6328137107e49c6a5e7c05c40851680
scaleOnInFlight - Indication of whether or not to include in-flight messages when calculating the number of SQS messages. (default: true, Optional)Благодаря точной настройке мы неслабо экономим:
- во время нагрузки мы не скейлим так много реплик
- нет большого лишнего скейла реплик - нет и скейла нод кластера AWS EKS
- нет скейла нод - платим серьёзно меньше
Всего один параметр и в разы снижаем нагрузку и косты.
❕Прежде чем делать подобное, уточните у девелоперов и бизнеса - подойдёт ли это вам и продукту.
Не все процессинги можно переключить только на инфлайт режим.
Полный пример манифеста(код в телеге неудобно читать).
https://gist.github.com/kruchkov-alexandr/e6328137107e49c6a5e7c05c40851680
👍8
#aws #eks #kubernetes
Задача уровня
Ну вот подключил ты Karpenter/Cluster Autoscaler + SPOT инстансы через разные node group.
Всё даже работает, ты проверяешь в EKS web консоли.
Задача: как быстро и удобно понять когда/сколько у тебя
Для аналитики использования и вообще для удобства.
Перебираешь все метрики и не видишь ничего сходу.
А сходу их и нет. (а, ну или мне сейчас накидают горелых пирожков с гусятками в мою печурку в комментариях)
Прометей/VM не знает ничего про споты или не споты.
А давайте мы сделаем всё сами.
Сперва в наших существующих нод группах вешаем лейблы
Задеплоили, проверяем, есть ли лейблы
Видим свои лейблы:
-
- - spot
- - on-demand
Ок, лейбл повесили, теперь ноды с разных нод-групп имеют лейбл, по которому мы определяем кто есть кто.
А что же дальше?
Дальше нам нужно научить "какой-то" компонент обсервабилити кубернетиса собирать его.
У нас есть метрика с именем
Компонент
Смотрим в прометиусе/ВМ - метрика есть, но наших новых лейблов нет.
Как бы вы его не ставили, добавьте в его конфиг такой параметр
Тем самым, мы разрешаем обогащать метрику новыми лейблами из списка.
* Звездочку писать не рекомендую - этим вы лишь будете занимать сильно больше лишнего места в хранилище прометиуса/викиторииметрикс.
Применяем, смотрим в графане - красота(скриншот).
Результат: пару простых движений и у нас есть график в графане сколько каких нод у нас было в нужный момент времени.
Видим график и понимаем "ага, нам есть над чем работать, надо сделать тюнинг спот инстансов больше, чем он деманд, чтобы платить меньше", но об этом мы поговорим в следующий раз.
* параметр extraArgs может отличаться синтаксисом вашего чарта, читайте документацию по тому способу, как вы ставили куб стейт метрикс.
Задача уровня
junior+/middle-
Ну вот подключил ты Karpenter/Cluster Autoscaler + SPOT инстансы через разные node group.
Всё даже работает, ты проверяешь в EKS web консоли.
Задача: как быстро и удобно понять когда/сколько у тебя
on-demand нод, а когда spot нод?Для аналитики использования и вообще для удобства.
Перебираешь все метрики и не видишь ничего сходу.
А сходу их и нет.
Прометей/VM не знает ничего про споты или не споты.
А давайте мы сделаем всё сами.
Сперва в наших существующих нод группах вешаем лейблы
resource "aws_eks_node_group" "on-demand-group" {
...
labels = {
"node-type" = "on-demand"
...
}
...
}
resource "aws_eks_node_group" "spot-group" {
...
labels = {
"node-type" = "spot"
...
}
...
}Задеплоили, проверяем, есть ли лейблы
kubectl get nodes -L node-role,node-type
NAME STATUS ROLES AGE VERSION NODE-ROLE NODE-TYPE
ip-10-1-123-114.ec2.internal Ready <none> 70d v1.31.4-eks-aeac579 infrastructure on-demand
ip-10-1-14-194.ec2.internal Ready <none> 42m v1.31.6-eks-aad632c applications on-demand
ip-10-1-24-165.ec2.internal Ready <none> 52s v1.31.6-eks-aad632c applications spot
Видим свои лейблы:
-
NODE-TYPE, тип ноды - нам нужно как раз это- - spot
- - on-demand
Ок, лейбл повесили, теперь ноды с разных нод-групп имеют лейбл, по которому мы определяем кто есть кто.
А что же дальше?
Дальше нам нужно научить "какой-то" компонент обсервабилити кубернетиса собирать его.
У нас есть метрика с именем
kube_node_labels от компонента kube-state-metricsКомпонент
kube-state-metrics вы можете ставить разными способами: от оператора, отдельный манифест, стак набор, да не важно.Смотрим в прометиусе/ВМ - метрика есть, но наших новых лейблов нет.
Как бы вы его не ставили, добавьте в его конфиг такой параметр
kube-state-metrics:
...
extraArgs:
- --metric-labels-allowlist=nodes=[node-type,node-role]
Тем самым, мы разрешаем обогащать метрику новыми лейблами из списка.
* Звездочку писать не рекомендую - этим вы лишь будете занимать сильно больше лишнего места в хранилище прометиуса/викиторииметрикс.
Применяем, смотрим в графане - красота(скриншот).
sum(kube_node_labels) by (label_node_type)
Результат: пару простых движений и у нас есть график в графане сколько каких нод у нас было в нужный момент времени.
Видим график и понимаем "ага, нам есть над чем работать, надо сделать тюнинг спот инстансов больше, чем он деманд, чтобы платить меньше", но об этом мы поговорим в следующий раз.
* параметр extraArgs может отличаться синтаксисом вашего чарта, читайте документацию по тому способу, как вы ставили куб стейт метрикс.
👍11👏1
#aws #aurora #eks #troubleshooting #longread
Лонгрид "история одного бага".
Часть 1 из 3.
Веселье.
Жил был стартап. Сперва на пару человек, но уже в облаке.
Пару сервисов в ECS и база MySQL.
Всем было весело и интересно.
Со временем продукт вырос, у него появилось масса нового: новые микросервисы, postgresql(а потом была удалена), Mongo и так далее. Обычный жизненный цикл любого продукта.
Стартап перешёл из этапа pre-seed в seed.
Уже есть реальные живые пользователи, кто реально платит живые деньги за продукт.
Это привело к тому, что на инфраструктуре появилась нагрузка.
Из одноинстансовой базы был совершён переход на cluster Aurora(mySQL compatible), был добавлен RDS proxy(а я не знаю зачем изначально), а ECS заменён на EKS.
На самом деле много всего было сделано, но выходе в проекте был макросервис(наполовину распиленный монолит) монорепы и десятки микросервсов.
Потом пришла series a и клиентов появилось сильно больше.
Пришла НАГРУЗКА.
Масштабирование
Продукт, не смотря на то, что это макросервис и монорепозиторий, научили в масштабирование.
Сперва было тупое через HPA и ресурсы, затем появилась KEDA и продукт научился в масштабирование по количеству сообщений в SQS или лагу в кафка топике. Стало не хватать нод, добавили автоскейлер (впоследствии заменив на карпентер).
Да и в целом было сделано на 99% масштабирование и кластеризация всего и вся.
Где-то на этом моменте продукт начал получать весьма негативные фидбеки "
Observability, v1.
Была добавлена графана для инфры, прометиус в куб и опенсёрч для логов(вообще не связан с историей).
Помимо всей инфры в кубах, начали мониторить и алертить стандартные метрики всех ресурсов Амзаона.
невероятно обширная работа, от 60 дашбордов, больше 400 панелей в графане по всем ресурсам стандартных графиков.
И.. и это ничего не дало.
Не верю.
Команда ничего не понимала.
Да как так-то? Все метрики есть, дашборды украдены из интернетов, но любой случай "
Начали копать дальше, читать про базы данных, движки, прокси и многое другое.
Стартап вырос из своих штанишек, надо было пересилить себя и разобраться.
Сложность была в том, что никто не понимал что не так то. Откуда вообще копать.
Так же всё усложнялось тем, что нет времени на раскачку и траблшутинг, проблема возникает редко, а надо пилить новые фичи, люди ждут продукт, как и инвесторы.
Шли недели и месяцы. Многие думали, что это не проблема софта, а проблема Амазон. Не верю, картинно возражали они и шли дальше пилить код.
А затем пришёл series b и пришла даже не нагрузка, а НАГРУЗИЩЕ.
х800 трафик и количество от клиентов от того, что было месяц назад.
Проблема стала так же в сотни раз чаще и пришло время её фиксировать.
Observability, v2.
Команда научилась отслеживать slow logs и реагировать на них.
https://xn--r1a.website/makebreakreflect/33
Есть запросы больше 10 секунд? Изучаем query и катим фикс.
И так до тех пор, пока слоу логи не прекратились.
И.. это не решило проблему.
Кубер/хелм/девопс во всём виноват.
Обратили внимание, что частично проблема повторятся, когда идёт деплой или скейлинг.
Проверили всё, пробы, макссёрж, количество реплик, стратеджи, перешли на KEDA с детальнейшим конфигом, пофиксили пару серёезных багов со стороны не совсем корректной настойки проб.
https://xn--r1a.website/makebreakreflect/9
И.. это не решило проблему.
Лонгрид "история одного бага".
Часть 1 из 3.
Веселье.
Жил был стартап. Сперва на пару человек, но уже в облаке.
Пару сервисов в ECS и база MySQL.
Всем было весело и интересно.
Со временем продукт вырос, у него появилось масса нового: новые микросервисы, postgresql(а потом была удалена), Mongo и так далее. Обычный жизненный цикл любого продукта.
Стартап перешёл из этапа pre-seed в seed.
Уже есть реальные живые пользователи, кто реально платит живые деньги за продукт.
Это привело к тому, что на инфраструктуре появилась нагрузка.
Из одноинстансовой базы был совершён переход на cluster Aurora(mySQL compatible), был добавлен RDS proxy(а я не знаю зачем изначально), а ECS заменён на EKS.
На самом деле много всего было сделано, но выходе в проекте был макросервис(наполовину распиленный монолит) монорепы и десятки микросервсов.
Потом пришла series a и клиентов появилось сильно больше.
Пришла НАГРУЗКА.
Масштабирование
Продукт, не смотря на то, что это макросервис и монорепозиторий, научили в масштабирование.
Сперва было тупое через HPA и ресурсы, затем появилась KEDA и продукт научился в масштабирование по количеству сообщений в SQS или лагу в кафка топике. Стало не хватать нод, добавили автоскейлер (впоследствии заменив на карпентер).
Да и в целом было сделано на 99% масштабирование и кластеризация всего и вся.
Где-то на этом моменте продукт начал получать весьма негативные фидбеки "
ЧОТА ТОРМОЗИТ ИНОГДА" и команда впервые задумалась о мониторинге.Observability, v1.
Была добавлена графана для инфры, прометиус в куб и опенсёрч для логов(вообще не связан с историей).
Помимо всей инфры в кубах, начали мониторить и алертить стандартные метрики всех ресурсов Амзаона.
невероятно обширная работа, от 60 дашбордов, больше 400 панелей в графане по всем ресурсам стандартных графиков.
И.. и это ничего не дало.
Не верю.
Команда ничего не понимала.
Да как так-то? Все метрики есть, дашборды украдены из интернетов, но любой случай "
ЧОТА ТОРМОЗИТ ИНОГДА" по метрикам и графикам не видно.Начали копать дальше, читать про базы данных, движки, прокси и многое другое.
Стартап вырос из своих штанишек, надо было пересилить себя и разобраться.
Сложность была в том, что никто не понимал что не так то. Откуда вообще копать.
Так же всё усложнялось тем, что нет времени на раскачку и траблшутинг, проблема возникает редко, а надо пилить новые фичи, люди ждут продукт, как и инвесторы.
Шли недели и месяцы. Многие думали, что это не проблема софта, а проблема Амазон. Не верю, картинно возражали они и шли дальше пилить код.
А затем пришёл series b и пришла даже не нагрузка, а НАГРУЗИЩЕ.
х800 трафик и количество от клиентов от того, что было месяц назад.
Проблема стала так же в сотни раз чаще и пришло время её фиксировать.
Observability, v2.
Команда научилась отслеживать slow logs и реагировать на них.
https://xn--r1a.website/makebreakreflect/33
Есть запросы больше 10 секунд? Изучаем query и катим фикс.
И так до тех пор, пока слоу логи не прекратились.
И.. это не решило проблему.
Кубер/хелм/девопс во всём виноват.
Обратили внимание, что частично проблема повторятся, когда идёт деплой или скейлинг.
Проверили всё, пробы, макссёрж, количество реплик, стратеджи, перешли на KEDA с детальнейшим конфигом, пофиксили пару серёезных багов со стороны не совсем корректной настойки проб.
https://xn--r1a.website/makebreakreflect/9
И.. это не решило проблему.
❤2
#aws #aurora #eks #troubleshooting #longread
Лонгрид "история одного бага".
Часть 2 из 3.
Observability, v3
Было принято решение мониторить поэтапно, каждый элемент инфры отдельно, а не комплексно, как это было ранее.
Например не просто "базу", а "базу поэтапно.
Что приходит на приложении при обращении к прокси, что происходит на RDS proxy, что приходит от прокси до БД, что внутри БД. На всё метрики и новые дашборды. Где не было метрик - писали сами.
Часть в графине, часть в CloudWatch, смотря откуда source был или быстрее/удобнее.
Эээ трейсинг мониторинга?
Первая зацепка попалась впервые за много месяцев, когда появился дашборд RDS proxy и там был замечен спайк.
Честно говоря не представляю, кто первый придумал назвать это спайком, но дальше по всем post mortem данный фигурант назвался спайк. Спайк количество подключений клиента к БД. Вместо частых 300-500 спайки доходили до 40000(в зависимости от типа инстанса и от настроек, их меняли часто во время эксплуатации и траблшутинга)
И.. спайки совпали с временем жалоб "
Радость, v1.
О чудо, кричала команда, мы нашли причину.
Однако радость быстро омрачилась осознанием того, что никто не знал ээээ а кто собственно создаёт спайки подключений и зачем? Все микросервисы, от монолита, макросервиса монорепы и других микросервисов сидели под одной учёткой на один ендпойнт.
Кастомизейшн, v1
Были созданы отдельные учётные записи для каждого сервиса.
И.. это ничего не дало.
Видно спайк, видно проблему, не видно источника.
Кастомизейшн? v2
Были созданы отдельные RDS proxy endpoint для каждого сервиса отдельно.
https://xn--r1a.website/makebreakreflect/55
То есть каждый сервис со своими подами(независимо сколько их в скейлинге сейчас) подключается через отдельный эндпойнт RDS proxy, с отдельной учётной записи.
Радость, v2.
О чудо, снова закричала команда.
Радость улетучилась раньше, чем прошло эхо от коллективного крика.
Стало понятно, что нагрузка идет только на один определённый эндпойнт, только от конкретного юзера-приложения.
Команда глянула в код и.. это ничего не дало.
Приложением из монорепозитория.
У него буквально 1-2 параметра энтрипойнта других и немного другой функционал.
Сами параметры запуска этого сервиса 100% на влияют на проблему.
Грубо говоря у одного сервиса задача "слушай вебхуки, пушь в базу", у второго "слушай sqs, пушь в базу", а у третьего "слушай кафку, пушь в базу". Всё остальное одинаковое.
Observability, v4
Ок, команда знает про спайк, про нагрузку от RDS proxy от одного сервиса, но откуда оно?
Создаётся ещё несколько новых dashboard, устанавливается Performance insight от AWS.
Команда видит, что есть нагрузка на read/write IOPS область, снова читаются книги, статьи, снова оптимизация кода и инфры.
https://xn--r1a.website/makebreakreflect/115
Лонгрид "история одного бага".
Часть 2 из 3.
Observability, v3
Было принято решение мониторить поэтапно, каждый элемент инфры отдельно, а не комплексно, как это было ранее.
Например не просто "базу", а "базу поэтапно.
Что приходит на приложении при обращении к прокси, что происходит на RDS proxy, что приходит от прокси до БД, что внутри БД. На всё метрики и новые дашборды. Где не было метрик - писали сами.
Часть в графине, часть в CloudWatch, смотря откуда source был или быстрее/удобнее.
Эээ трейсинг мониторинга?
Первая зацепка попалась впервые за много месяцев, когда появился дашборд RDS proxy и там был замечен спайк.
Честно говоря не представляю, кто первый придумал назвать это спайком, но дальше по всем post mortem данный фигурант назвался спайк. Спайк количество подключений клиента к БД. Вместо частых 300-500 спайки доходили до 40000(в зависимости от типа инстанса и от настроек, их меняли часто во время эксплуатации и траблшутинга)
И.. спайки совпали с временем жалоб "
ЧОТА ТОРМОЗИТ ИНОГДА".Радость, v1.
О чудо, кричала команда, мы нашли причину.
Однако радость быстро омрачилась осознанием того, что никто не знал ээээ а кто собственно создаёт спайки подключений и зачем? Все микросервисы, от монолита, макросервиса монорепы и других микросервисов сидели под одной учёткой на один ендпойнт.
Кастомизейшн, v1
Были созданы отдельные учётные записи для каждого сервиса.
И.. это ничего не дало.
Видно спайк, видно проблему, не видно источника.
Кастомизейшн? v2
Были созданы отдельные RDS proxy endpoint для каждого сервиса отдельно.
https://xn--r1a.website/makebreakreflect/55
То есть каждый сервис со своими подами(независимо сколько их в скейлинге сейчас) подключается через отдельный эндпойнт RDS proxy, с отдельной учётной записи.
Радость, v2.
О чудо, снова закричала команда.
Радость улетучилась раньше, чем прошло эхо от коллективного крика.
Стало понятно, что нагрузка идет только на один определённый эндпойнт, только от конкретного юзера-приложения.
Команда глянула в код и.. это ничего не дало.
Приложением из монорепозитория.
У него буквально 1-2 параметра энтрипойнта других и немного другой функционал.
Сами параметры запуска этого сервиса 100% на влияют на проблему.
Грубо говоря у одного сервиса задача "слушай вебхуки, пушь в базу", у второго "слушай sqs, пушь в базу", а у третьего "слушай кафку, пушь в базу". Всё остальное одинаковое.
Observability, v4
Ок, команда знает про спайк, про нагрузку от RDS proxy от одного сервиса, но откуда оно?
Создаётся ещё несколько новых dashboard, устанавливается Performance insight от AWS.
Команда видит, что есть нагрузка на read/write IOPS область, снова читаются книги, статьи, снова оптимизация кода и инфры.
https://xn--r1a.website/makebreakreflect/115
🤔1
#aws #aurora #eks #troubleshooting #longread
Лонгрид "история одного бага".
Часть 3 из 3.
Финал. Финал без разбивки.
Понимаю, что вы уже устали читать, но конец близок.
И вот мы приходим к состоянию, что команда видит чуть ли не каждый трейс, обращение, логи, слоу логи, мониторинг базовых сущностей и метрик, мониторинг кастом метрик, всё это обвешано алёртингом, а количество дашбордов больше 50(панелей около 450). Господи, да даже влияние запроса на IOPS видно в аналитике.
Все. Ждут. Проблему.
Создана целая вселенная, как во Black and White и теперь под микроскопом смотрим кто же из наших мелких хулиганит.
Наступает проблема и.. никто ничего не понимает.
Обвешаны всем, словно звезды на кителе известного генерала, а поделать ничего не может команда.
Собираются все скриншоты, метрики, ссылки, логи и всю историю и уходим в саппорт.
В саппорте сперва сперва катают как в доте новичка тупыми вопросами категории "вы пробовали выключить и включить", на что сразу получают максимально подробный и отчасти грубый ответ "дайте нам другого менеджера" и сразу переключают на очень умного инженера, явно выше первого уровня технической поддержки.
Он анализирует все десятки скриншотов, логов, аргументов, истории траблшутинга и даёт одну единственную ссылку на документацию и ссылку на логи.
первая ссылка https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-pinning.html
где нас интересует только это
А вторая ссылка на логи, которые упустила команда, и где есть чёткое
(это было пропущено при траблшутинге, есть косяк).
Срочный созвон, брейншторм разработчиков за 0.00000001мс, фикс на 2 строчки(ограничение payload).
И.. и проблема ушла.
Итог.
Вот так, в поисках одного бага, который возникал на 1-3 секунды, аффектил всех клиентов, который появился только при нагрузке при росте продукта, позволили потратить больше 11.000 долларов(дебаг, включение фичей, доп услуги, хранение и обогащение метрик, борды, разделение по rdx proxy endpoints и многоие другое), десятки часов траблшутинга, научив всю команду обсервабилити и пониманию КАЖДОГО этапа всех элементов продукта.
Всего-лишь большой payload в базу через прокси.. Всего-лишь большой payload..
*В этой истории упущены ещё два десятка незначительных модификаций, которые либо вели команду не тудла, либо ну совсем ни на что не влияли, а текста отняли бы ещё на пару постов.
Лонгрид "история одного бага".
Часть 3 из 3.
Финал. Финал без разбивки.
Понимаю, что вы уже устали читать, но конец близок.
И вот мы приходим к состоянию, что команда видит чуть ли не каждый трейс, обращение, логи, слоу логи, мониторинг базовых сущностей и метрик, мониторинг кастом метрик, всё это обвешано алёртингом, а количество дашбордов больше 50(панелей около 450). Господи, да даже влияние запроса на IOPS видно в аналитике.
Все. Ждут. Проблему.
Создана целая вселенная, как во Black and White и теперь под микроскопом смотрим кто же из наших мелких хулиганит.
Наступает проблема и.. никто ничего не понимает.
Обвешаны всем, словно звезды на кителе известного генерала, а поделать ничего не может команда.
Собираются все скриншоты, метрики, ссылки, логи и всю историю и уходим в саппорт.
В саппорте сперва сперва катают как в доте новичка тупыми вопросами категории "вы пробовали выключить и включить", на что сразу получают максимально подробный и отчасти грубый ответ "дайте нам другого менеджера" и сразу переключают на очень умного инженера, явно выше первого уровня технической поддержки.
Он анализирует все десятки скриншотов, логов, аргументов, истории траблшутинга и даёт одну единственную ссылку на документацию и ссылку на логи.
первая ссылка https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-pinning.html
где нас интересует только это
Any statement with a text size greater than 16 KB causes the proxy to pin the session.А вторая ссылка на логи, которые упустила команда, и где есть чёткое
The proxy can't reuse this connection until the session ends. Reason: The connection ran a SQL query which exceeded the 16384 byte limit.(это было пропущено при траблшутинге, есть косяк).
Срочный созвон, брейншторм разработчиков за 0.00000001мс, фикс на 2 строчки(ограничение payload).
И.. и проблема ушла.
Итог.
Вот так, в поисках одного бага, который возникал на 1-3 секунды, аффектил всех клиентов, который появился только при нагрузке при росте продукта, позволили потратить больше 11.000 долларов(дебаг, включение фичей, доп услуги, хранение и обогащение метрик, борды, разделение по rdx proxy endpoints и многоие другое), десятки часов траблшутинга, научив всю команду обсервабилити и пониманию КАЖДОГО этапа всех элементов продукта.
Всего-лишь большой payload в базу через прокси.. Всего-лишь большой payload..
*В этой истории упущены ещё два десятка незначительных модификаций, которые либо вели команду не тудла, либо ну совсем ни на что не влияли, а текста отняли бы ещё на пару постов.
🤯24🔥10👍6
#aws #devops #EKS #IRSA
На одном проекте пришла задача избавиться от IAM-кредов в подах и перейти на роли.
Есть три давно созданных EKS-кластера. Я написал Terraform-код: полиси, роль, policy attachment, service account, OIDC и всё остальное. Поправил Helm-чарт, добавив service account. Прокатил изменения по всем кластерам - всё ок.
На DEV я убрал IAM-креды из секретов, чтобы CDK перешёл на роль - всё ок. Сто раз всё проверил: секреты почистил, аппликейшены передеплоил, в AWS-консоли видно, что роль используется, IAM-креды - нет. Удалил IAM для DEV - всё работает. Повторил на STAGE - тоже всё ок.
И тут прод. Удалил креды - и всё рухнуло к чертям. Поды начали использовать роль ноды 🤡, у которой, естественно, нет доступа ко всем ресурсам AWS. Вернул креды, откатил, прод поднял, получил по щщам и начал дебажить.
Сто раз перепроверил Terraform-код - всё идентично. Проверил OIDC, IRSA, роли - всё совпадает, проблем нет. Но почему-то на проде поды не берут нужную роль.
Нырнул в документацию и пошёл шаг за шагом. Это был скучный этап, просто читал, как всё это работает в кишках. Через пару часов упёрся в мутейшн хуки.
Проверил
dev
stage
prod
Кто-то (или что-то) когда-то как-то удалил pod-identity-webhook на проде. Как так вышло - история умалчивает, это останется тайной. Жаль только часов дебага, когда я матчил код, роли, OIDC и IRSA, не подозревая, что мутейшн хука просто нет.🚶♀
Что делает этот вебхук? (текст украден из чата кубера):
- Добавляет переменные среды:
Добавляет в волумы:
И всё. Дальше куб сам выписывает SA-токен с aud: sts.amazonaws.com.
Принял быстрый фикс:
Установил cert-manager (если его не было):
Склонировал и развернул:
Проверил логи:
Запустил тест:
Получил:
Ура, теперь поды используют новую роль. Убил тестовый под. Удалил IAM-креды, накатил снова - всё ок.
Задача решена.🎉
.....
Прошло пару дней.
.....
Сижу, значит, пишу этот текст-заметку, пока не забыл, и задумался: неужели такое возможно в 2025? Зачем? Зачем, мистер Андерсон, вообще руками что-то ставить в кластер,
Читаю за утренним кофе документацию, пока жена не видит:
- https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html
- https://docs.aws.amazon.com/eks/latest/userguide/pod-id-agent-setup.html
Дошёл до:
- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_pod_identity_association
.
..
...
Прочитал, промолчал, набычился, посмотрел на пол, закатил глаза, наделkubectl apply -f клоунский нос 🤡 и отправил пост в телеграм.
На одном проекте пришла задача избавиться от IAM-кредов в подах и перейти на роли.
Есть три давно созданных EKS-кластера. Я написал Terraform-код: полиси, роль, policy attachment, service account, OIDC и всё остальное. Поправил Helm-чарт, добавив service account. Прокатил изменения по всем кластерам - всё ок.
На DEV я убрал IAM-креды из секретов, чтобы CDK перешёл на роль - всё ок. Сто раз всё проверил: секреты почистил, аппликейшены передеплоил, в AWS-консоли видно, что роль используется, IAM-креды - нет. Удалил IAM для DEV - всё работает. Повторил на STAGE - тоже всё ок.
И тут прод. Удалил креды - и всё рухнуло к чертям. Поды начали использовать роль ноды 🤡, у которой, естественно, нет доступа ко всем ресурсам AWS. Вернул креды, откатил, прод поднял, получил по щщам и начал дебажить.
Сто раз перепроверил Terraform-код - всё идентично. Проверил OIDC, IRSA, роли - всё совпадает, проблем нет. Но почему-то на проде поды не берут нужную роль.
Нырнул в документацию и пошёл шаг за шагом. Это был скучный этап, просто читал, как всё это работает в кишках. Через пару часов упёрся в мутейшн хуки.
Проверил
mutatingwebhookconfigurations:dev
kubectl get mutatingwebhookconfigurations | grep pod-identity-webhook
pod-identity-webhook
stage
kubectl get mutatingwebhookconfigurations | grep pod-identity-webhook
pod-identity-webhook
prod
kubectl get mutatingwebhookconfigurations | grep pod-identity-webhook
hui
Кто-то (или что-то) когда-то как-то удалил pod-identity-webhook на проде. Как так вышло - история умалчивает, это останется тайной. Жаль только часов дебага, когда я матчил код, роли, OIDC и IRSA, не подозревая, что мутейшн хука просто нет.
Что делает этот вебхук? (текст украден из чата кубера):
- Добавляет переменные среды:
AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount
AWS_ROLE_ARN (значение берётся из аннотации к SA)
Добавляет в волумы:
- name: aws-iam-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
audience: sts.amazonaws.com
expirationSeconds: 86400
path: token
...
- mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
name: aws-iam-token
readOnly: true
И всё. Дальше куб сам выписывает SA-токен с aud: sts.amazonaws.com.
Принял быстрый фикс:
Установил cert-manager (если его не было):
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.yaml
Склонировал и развернул:
git clone https://github.com/aws/amazon-eks-pod-identity-webhook
cd amazon-eks-pod-identity-webhook
make cluster-up IMAGE=amazon/amazon-eks-pod-identity-webhook:latest
Проверил логи:
kubectl logs -n default -l app=pod-identity-webhook
Запустил тест:
kubectl run irsa-test --image=amazon/aws-cli -n production --overrides='{"spec":{"serviceAccountName":"new-sa"}}' --command -- sh -c "aws sts get-caller-identity && sleep 3600"Получил:
{
"UserId": "54252523:botocore-session-2345452354",
"Account": "2345452345",
"Arn": "arn:aws:sts::234534524:assumed-role/expected-new-role/botocore-session-345235"
}Ура, теперь поды используют новую роль. Убил тестовый под. Удалил IAM-креды, накатил снова - всё ок.
Задача решена.🎉
.....
Прошло пару дней.
.....
Сижу, значит, пишу этот текст-заметку, пока не забыл, и задумался: неужели такое возможно в 2025? Зачем? Зачем, мистер Андерсон, вообще руками что-то ставить в кластер,
kubectl apply -f??Читаю за утренним кофе документацию, пока жена не видит:
- https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html
- https://docs.aws.amazon.com/eks/latest/userguide/pod-id-agent-setup.html
Дошёл до:
- https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_pod_identity_association
.
..
...
Прочитал, промолчал, набычился, посмотрел на пол, закатил глаза, надел
Please open Telegram to view this post
VIEW IN TELEGRAM
😁16👍2😨2
#aws #eks #kubernetes #bottlerocket #troubleshooting
Case:
AWS EKS, Bottlerocket AMI. Случайно уронили коллектор логов, сбора не было несколько часов, но логи нужны прям сейчас. Если коллектор починить, то ждать долго(кстати какого фига долго я хз).
Нужных логов в поде нет, в ArgoCD их тоже нет(логично же).
Как быть?
Можно слить с EKS node(s), но этот путь не очевидный, ведь у нас
Для начала нужно быть уверен, что вы включали админ доступ в TOML конфиге.
Ок, админ доступ включён.
Смотрим на какой ноде запущен наш под.
Узнаем айди инстанса.
Подключаемся к инстансу через SSM
Сейчас нет никаких прав, переходим в админа.
Ок, мы стали админами(через контейнер), теперь нам нужен шелл - шелти.
Дальше просто смотрим в
Ну и смотрим логи
"но Алекс, нам нужны все логи, как их слить к себе локально?"
Ок, запускаем сборку логов в шелти
После коллекции у нас логи хранятся на ноде в
Теперь со своей локальной машины дёргаем их к себе через k8s API (да-да, я тоже не знал)
У нас локально теперь все логи в
Задача решена.
Case:
AWS EKS, Bottlerocket AMI. Случайно уронили коллектор логов, сбора не было несколько часов, но логи нужны прям сейчас. Если коллектор починить, то ждать долго(кстати какого фига долго я хз).
Нужных логов в поде нет, в ArgoCD их тоже нет(логично же).
Как быть?
Можно слить с EKS node(s), но этот путь не очевидный, ведь у нас
Bottlerocket.Для начала нужно быть уверен, что вы включали админ доступ в TOML конфиге.
*# Доступ к системным логам, получению root-оболочки (sheltie), запуску journalctl, logdog и пр.
[settings.host-containers.admin]
enabled = true
# Доступ к Bottlerocket API для настроек и диагностики, но без глубокого доступа к логам и файловой системе ноды.
[settings.host-containers.control]
enabled = true
Ок, админ доступ включён.
Смотрим на какой ноде запущен наш под.
kubectl get pods -o wide | grep podname
... ip-10-1-114-226.ec2.internal ...
Узнаем айди инстанса.
kubectl get node -o yaml ip-10-1-114-226.ec2.internal | grep -A4 -i "nodeid"
... "i-09cd72826bee50209" ...
Подключаемся к инстансу через SSM
aws ssm start-session --target i-09cd72826bee50209
Сейчас нет никаких прав, переходим в админа.
enter-admin-container
Ок, мы стали админами(через контейнер), теперь нам нужен шелл - шелти.
[root@admin]# sudo sheltie
Дальше просто смотрим в
/var/log/ls /var/log/containers/
argo-cd-argocd-application-controller-0_argo-cd_application-controller-dfb4d12f601e71ac373b30bfaad8d02b56141218e7bcc5f1358f3a7d8f7df7f7.log
...
Ну и смотрим логи
cat argo-cd-argocd-application-controller-0_argo-cd_application-controller-dfb4d12f601e71ac373b30bfaad8d02b56141218e7bcc5f1358f3a7d8f7df7f7.log
"но Алекс, нам нужны все логи, как их слить к себе локально?"
Ок, запускаем сборку логов в шелти
bash-5.1# logdog
После коллекции у нас логи хранятся на ноде в
logs are at: /var/log/support/bottlerocket-logs.tar.gz
Теперь со своей локальной машины дёргаем их к себе через k8s API (да-да, я тоже не знал)
kubectl get --raw "/api/v1/nodes/ip-10-1-114-226.ec2.internal/proxy/logs/support/bottlerocket-logs.tar.gz" > ./bottlerocket-logs.tar.gz
У нас локально теперь все логи в
bottlerocket-logs.tar.gzЗадача решена.
*** Если изначально админ доступ не включён, то всё не ок. По идее если его включаешь в момент задачи, то ноды пересоздаются и старые логи с нод исчезают в пучине небытия и бездны. Тогда уж лучше ждать окончания работы починенного коллектора логов.** При необходимости повторить для других нод, если исторически старый под был запущен на других нодах.👍8❤5🔥3
#aws #eks #kubernetes #troubleshooting #одинденьизжизни #argocd
"Алекс, у нас что-то приложение не раскатывается, деплой завис. Кластер новый, вроде ты деплоил, посмотри плиз".
Ну раз я, значит мне и смотреть.
Смотрю в арго что там зависло, перехожу в аппликейшнсет - вижу процессинг.
Processing, что же ты за зверь такой?
Это означает, что ArgoCD обнаружил разницу между желаемым состоянием (в гите) и текущим состоянием (в кластере) и активно пытается синхронизировать ресурсы.
Есть проблема, которая мешает завершить развертывание (например, нехватка ресурсов, неправильная конфигурация, ожидание завершения работы пода или борьба между контроллерами).
На самом деле самый дебильный статус, потому что в практике это может быть что угодно🐒 .
Ладно, надо чинить.
Смотрю сперва "а не может ли кто сражаться за ресурсы?"
Вдруг опять арго и оператор вцепились как два деда.
Я как-то выше писал старый пример про #dapr.
Смотрю:
А тут всё нормально:
- helm один раз создал/обновил сам ApplicationSet
- argocd-applicationset-controller дальше управляет этим ApplicationSet и генерит Application(ы)
Значит дело не в конфликте.
Иду дальше, что с самим аппликейшн
И нет ли там конфликтов
Конфликтов нет, ведь:
- argocd-applicationset-controller следит за соответствием шаблону ApplicationSet.
Он не ходит в кластерные ресурсы (Deployment, Service и т.д.), только создаёт/обновляет/удаляет сами Application CR.
- argocd-application-controller следит за тем, чтобы ресурсы в кластере совпадали с Git, и считает health (если хоть один дочерний ресурс не равен Healthy, приложение остаётся Progressing).
Идём дальше. Так какие же ресурсы генерируются и какой у них статус?
Ага! Попался!
Какой-то
Что там с тобой:
Визуально вроде ок,
Стоп, нет,не ок.
Ведь это означает, что контроллер, отвечающий за provision (создание) AWS Load Balancer, не смог выполнить свою работу, и поэтому поле status.loadBalancer.ingress не заполнено IP-адресом или Hostname.
* У нас LoadBalancer создаётся контроллером AWS.
Ещё раз проверяю в дескрайб:
Ладно, иду в неймспейс, где обычно лежит AWS Load Balancer, логи смотреть.
А там нет ничего! Удивляюсь, смотрю
Нет ничего!
Спрашиваю коллег, а мне ехидно говорят "да ты же сам не задеплоил лоадбалансер в этом новом кластере".
https://github.com/kubernetes-sigs/aws-load-balancer-controller
Смотрю свои коммиты, MR - и правда, именно в этом кластере я забыл добавить AWS LB.🐒
Пилю новый MR, добавляю LB, жду, когда всё поднимется - всё, проблема решена!
У проблемного
Добавляю в документацию по кластеру, что "не забыть про LB и иду работать дальше".
Ну хорошо, хоть это не продуктовый кластер, без клиентского ворклоада🤡
"Алекс, у нас что-то приложение не раскатывается, деплой завис. Кластер новый, вроде ты деплоил, посмотри плиз".
Ну раз я, значит мне и смотреть.
Смотрю в арго что там зависло, перехожу в аппликейшнсет - вижу процессинг.
Processing, что же ты за зверь такой?
Это означает, что ArgoCD обнаружил разницу между желаемым состоянием (в гите) и текущим состоянием (в кластере) и активно пытается синхронизировать ресурсы.
Есть проблема, которая мешает завершить развертывание (например, нехватка ресурсов, неправильная конфигурация, ожидание завершения работы пода или борьба между контроллерами).
На самом деле самый дебильный статус, потому что в практике это может быть что угодно
Ладно, надо чинить.
Смотрю сперва "а не может ли кто сражаться за ресурсы?"
Вдруг опять арго и оператор вцепились как два деда.
Я как-то выше писал старый пример про #dapr.
Смотрю:
kubectl get applicationsets APPSET1 \
-n NAMESPACE \
-o jsonpath='{.metadata.managedFields[*].manager}' \
| tr ' ' '\n' | sort | uniq -c
1 argocd-applicationset-controller
1 helm
А тут всё нормально:
- helm один раз создал/обновил сам ApplicationSet
- argocd-applicationset-controller дальше управляет этим ApplicationSet и генерит Application(ы)
Значит дело не в конфликте.
Иду дальше, что с самим аппликейшн
kubectl get applications -n NAMESPACE \
-o wide | grep APP1
APP1 Synced Progressing
И нет ли там конфликтов
kubectl get applications APP1 -n NAMESPACE \
-o jsonpath='{.metadata.managedFields[*].manager}' \
| tr ' ' '\n' | sort | uniq -c
1 argocd-application-controller
1 argocd-applicationset-controller
Конфликтов нет, ведь:
- argocd-applicationset-controller следит за соответствием шаблону ApplicationSet.
Он не ходит в кластерные ресурсы (Deployment, Service и т.д.), только создаёт/обновляет/удаляет сами Application CR.
- argocd-application-controller следит за тем, чтобы ресурсы в кластере совпадали с Git, и считает health (если хоть один дочерний ресурс не равен Healthy, приложение остаётся Progressing).
Идём дальше. Так какие же ресурсы генерируются и какой у них статус?
kubectl get applications APP1 -n NAMESPACE -o json \
| jq '.status.resources[] | select(.health.status != "Healthy")'
...
{
"kind": "ConfigMap",
"name": "CM1",
"namespace": "NAMESPACE",
"status": "Synced",
"version": "v1"
}
...
{
"health": {
"status": "Progressing"
},
"kind": "Service",
"name": "SVC1",
"namespace": "NAMESPACE",
"status": "Synced",
"version": "v1"
}
...
Ага! Попался!
Какой-то
service в процессинге.Что там с тобой:
kubectl get service SVC1 -o yaml -n NAMESPACE
...
type: LoadBalancer
status:
loadBalancer: {}
Визуально вроде ок,
Стоп, нет,не ок.
Ведь это означает, что контроллер, отвечающий за provision (создание) AWS Load Balancer, не смог выполнить свою работу, и поэтому поле status.loadBalancer.ingress не заполнено IP-адресом или Hostname.
* У нас LoadBalancer создаётся контроллером AWS.
Ещё раз проверяю в дескрайб:
kubectl describe service SVC1 -n NAMESPACE
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal EnsuringLoadBalancer 55m ***** Ensuring load balancer
Ладно, иду в неймспейс, где обычно лежит AWS Load Balancer, логи смотреть.
А там нет ничего! Удивляюсь, смотрю
kubectl get pods -A | grep -i load
Нет ничего!
Спрашиваю коллег, а мне ехидно говорят "да ты же сам не задеплоил лоадбалансер в этом новом кластере".
https://github.com/kubernetes-sigs/aws-load-balancer-controller
Смотрю свои коммиты, MR - и правда, именно в этом кластере я забыл добавить AWS LB.
Пилю новый MR, добавляю LB, жду, когда всё поднимется - всё, проблема решена!
У проблемного
applicationsset статус стал Healthy.Добавляю в документацию по кластеру, что "не забыть про LB и иду работать дальше".
Ну хорошо, хоть это не продуктовый кластер, без клиентского ворклоада
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18
#eks #aks #kubernetes
Апгрейд кластера кубернетис.
С чего начинать?
Начать сперва с проверки совместимости.
Время от времени некоторые ресурсы меняют версию API.
- что-то становится deprecated, например PSP
- что-то меняет версию с alpha, вырастая до v1
- что-то несёт с собой breaking changes
У AWS EKS есть собственные механизмы EKS Upgrade Insights/preflight‑checks, которые дают подсказки по deprecated API и аддонам прямо перед апгрейдом.
https://aws.amazon.com/blogs/containers/accelerate-the-testing-and-verification-of-amazon-eks-upgrades-with-upgrade-insights/
В OpenShift есть свои "pre‑update" проверки и рекомендации, но они более завязаны на платформу.
Значительная часть логики проверки касается операторов, etcd, сети и прочих специфичных для OpenShift компонентов.
https://docs.redhat.com/en/documentation/openshift_container_platform/4.14/html/updating_clusters/preparing-to-update-a-cluster
У Azure есть AKS Upgrade Readiness Check. AKS автоматически блокирует апгрейд, если обнаружены deprecated API. Так же проверяет не только deprecated API, но и всякие PDB, квоты, серты, IP адреса в сабнете и так далее.
https://learn.microsoft.com/en-us/azure/aks/upgrade-cluster
Это всё облачные куберы и их вендорлок решения.
Для bare-metal кластеров и для клауд куберов есть более универсальные решения:
- консольные утилиты для проверки всех сущностей куба (локально или в CICD):
- - https://github.com/doitintl/kube-no-trouble
- - https://github.com/kubepug/kubepug
- github action для CI/CD
- - https://github.com/FairwindsOps/pluto
- проверки аутдейт/депрекейтед helm чартов (НЕ связана с API/апгрейд, опциональная проверка)
- - https://github.com/FairwindsOps/Nova
Крайне важно понимать, что AKS проверяет deprecated API в течение 12 часов перед апгрейдом, а EKS использует 30-дневное окно, что важно для планирования процесса upgrade. То есть даже если вы исправили deprecated API, ошибка может оставаться в течении указанного времени. Планируйте заранее.
Всё эти проверки необходимо сделать ДО обновления кластера, иначе у вас будут весёлые часы после апгрейда.
Апгрейд кластера кубернетис.
С чего начинать?
Начать сперва с проверки совместимости.
Время от времени некоторые ресурсы меняют версию API.
- что-то становится deprecated, например PSP
- что-то меняет версию с alpha, вырастая до v1
- что-то несёт с собой breaking changes
У AWS EKS есть собственные механизмы EKS Upgrade Insights/preflight‑checks, которые дают подсказки по deprecated API и аддонам прямо перед апгрейдом.
https://aws.amazon.com/blogs/containers/accelerate-the-testing-and-verification-of-amazon-eks-upgrades-with-upgrade-insights/
В OpenShift есть свои "pre‑update" проверки и рекомендации, но они более завязаны на платформу.
Значительная часть логики проверки касается операторов, etcd, сети и прочих специфичных для OpenShift компонентов.
https://docs.redhat.com/en/documentation/openshift_container_platform/4.14/html/updating_clusters/preparing-to-update-a-cluster
У Azure есть AKS Upgrade Readiness Check. AKS автоматически блокирует апгрейд, если обнаружены deprecated API. Так же проверяет не только deprecated API, но и всякие PDB, квоты, серты, IP адреса в сабнете и так далее.
https://learn.microsoft.com/en-us/azure/aks/upgrade-cluster
Это всё облачные куберы и их вендорлок решения.
Для bare-metal кластеров и для клауд куберов есть более универсальные решения:
- консольные утилиты для проверки всех сущностей куба (локально или в CICD):
- - https://github.com/doitintl/kube-no-trouble
- - https://github.com/kubepug/kubepug
- github action для CI/CD
- - https://github.com/FairwindsOps/pluto
- проверки аутдейт/депрекейтед helm чартов (НЕ связана с API/апгрейд, опциональная проверка)
- - https://github.com/FairwindsOps/Nova
Крайне важно понимать, что AKS проверяет deprecated API в течение 12 часов перед апгрейдом, а EKS использует 30-дневное окно, что важно для планирования процесса upgrade. То есть даже если вы исправили deprecated API, ошибка может оставаться в течении указанного времени. Планируйте заранее.
Всё эти проверки необходимо сделать ДО обновления кластера, иначе у вас будут весёлые часы после апгрейда.
43👍16🥰2🙏1