Для последнего проекта для 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 #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
#troubleshooting #kubernetes #bottlerocket #aws # linux #база
Прилетает аномалия: клиенты(живые люди), при обращении к нашему UI, начинают видеть таймауты и ошибки (5xx), особенно при резком росте нагрузки.
Ну ничего необычного. Кроме того, что такого быть не должно.
Смотрю логи фронта - он получает пятисотки от бэкенда.
Иду к бэкендерам, показываю логи, тыкаю пальцем, говорю чините.
Проходит день, два, а ошибки всё идут.
Разработчики чего только не делали:
- включали дебаг
- смотрели логи
- добавляли метрики
- добавляли ресурсы CPU/Memory (хотя нагрузка была не высокой)
- did a barrel roll
Ничего не помогает. По всей статистике, логам и метрикам - всё отлично, но есть проблема с пятисотками.
Я бы может этим и не занимался, но на общем митинге мне ставят блокер и говорят "это ваша инфра и девопсы, чините, но мы, если честно, сами не знаем чо тут и почему".
Хлеб всему голова, как и девопс всем ишшуям затычка, поехали траблшутить.
Вспоминаю, что нечто подобное уже было, и иду читать у себя же https://xn--r1a.website/aws_ru/136623
Проверяю - не, все ок с ALB и настройками приложений.
При помощи фронта и бэка пишу скрипт нагрузочного тестирования, чтобы сымитировать это в stage (да кому он сдался этот ваш dev!). Запускаю, половину не понимая, и да, с*ка, пятисотки.
Ещё раз опускаюсь в логи, трейсы, метрики - не за что зацепиться.
Просидел дня три наверное, пока всё это ковырял как дурачок.
Может и правда мы, из отдела инфры, дурачки и что-то поломали?
Сижу ковыряю коммиты и MR в репозиториях инфраструктуры за последние 3 месяца - ничего критичного.
Ладно. Пошёл ковырять само приложение.
Есть!, Есть су*ка! Ребята меняли код, связанный немного с сетевым стеком и обработчиком на стороне сервера.
Даже спустя время не могу поделится хотя бы примерно что делало приложение и бизнес, так что опустим это.
Хорошо, допустим они что-то меняли, но в метриках и логах ведь ничего нет?
Стало интересно, переношу задачу на следующий спринт, ковыряю ещё несколько часов.
После детального ныряния есть зацепка, что у нас инфра сетевой стек говно и это уже проблема на нашей стороне.
Просидел ещё несколько часов.
Не буду ходить долгим путём как же я это выясни, где-то на грани безумства и безысходности пришла мысль, что проблема именно в том, что приложение стало создавать очень много короткоживущих TCP-сессий. Оно успевает ответить клиенту, но закрывает соединение так, что оно оставляет херню в ядре.
Первым делом иду на ноду, где размещён под, у которого проблема
Я выше писал как на ноду на ботлрокете заходить - https://xn--r1a.website/makebreakreflect/205
И ввожу команду:
И вот оно! Розовый слон в комнате:
Сразу же видна причина, можно было бы и раньше увидеть 🤡(нет)
Пакеты отбрасывает не приложение, не kube-proxy, не CNI - их отбрасывает само ядро Linux ноды, потому что его таблица сетевых состояний забита!
Далее я проверяю, насколько сильно таблица забита и каков ее лимит. Это прямое чтение файлов ядра.
Приложение-бэкенд, после изменений, стало генерировать аномально высокую частоту короткоживущих TCP-соединений. Система просто не успевает их забыть (таймаут 120 секунд слишком велик), и таблица переполняется.
Делаю нагрузочный тест - да, каррент каунт растёт.
Пробую фикс:
меняю таймаут с 120 на 60 на самой ноде и снова запускаю нагрузочный тест.
Тишина. Снова запускаю скрипт нагрузочного тестирования. Пятисотки исчезли! Красота!
Проконсультировался с коллегами - кто должен править:
- на стороне инфры
- на стороне приложения
Пару Очень Авторитетных Коллег Архитекторов сказали, что точно на стороне приложения и мы перекидываем мячик на сторону девелоперов. Они что-то там правят, тестируют этим же скриптом - всё отлично.
Выкатываем и фикс на прод, пятисоток больше нет, кастомеры довольны.
Белиссимо!
Не дай вселенная вам такое дебажить.😭
Прилетает аномалия: клиенты(живые люди), при обращении к нашему UI, начинают видеть таймауты и ошибки (5xx), особенно при резком росте нагрузки.
Ну ничего необычного. Кроме того, что такого быть не должно.
Смотрю логи фронта - он получает пятисотки от бэкенда.
Иду к бэкендерам, показываю логи, тыкаю пальцем, говорю чините.
Проходит день, два, а ошибки всё идут.
Разработчики чего только не делали:
- включали дебаг
- смотрели логи
- добавляли метрики
- добавляли ресурсы CPU/Memory (хотя нагрузка была не высокой)
- did a barrel roll
Ничего не помогает. По всей статистике, логам и метрикам - всё отлично, но есть проблема с пятисотками.
Я бы может этим и не занимался, но на общем митинге мне ставят блокер и говорят "это ваша инфра и девопсы, чините, но мы, если честно, сами не знаем чо тут и почему".
Хлеб всему голова, как и девопс всем ишшуям затычка, поехали траблшутить.
Вспоминаю, что нечто подобное уже было, и иду читать у себя же https://xn--r1a.website/aws_ru/136623
Проверяю - не, все ок с ALB и настройками приложений.
При помощи фронта и бэка пишу скрипт нагрузочного тестирования, чтобы сымитировать это в stage (да кому он сдался этот ваш dev!). Запускаю, половину не понимая, и да, с*ка, пятисотки.
Ещё раз опускаюсь в логи, трейсы, метрики - не за что зацепиться.
Просидел дня три наверное, пока всё это ковырял как дурачок.
Может и правда мы, из отдела инфры, дурачки и что-то поломали?
Сижу ковыряю коммиты и MR в репозиториях инфраструктуры за последние 3 месяца - ничего критичного.
Ладно. Пошёл ковырять само приложение.
Есть!, Есть су*ка! Ребята меняли код, связанный немного с сетевым стеком и обработчиком на стороне сервера.
Даже спустя время не могу поделится хотя бы примерно что делало приложение и бизнес, так что опустим это.
Хорошо, допустим они что-то меняли, но в метриках и логах ведь ничего нет?
Стало интересно, переношу задачу на следующий спринт, ковыряю ещё несколько часов.
После детального ныряния есть зацепка, что у нас инфра сетевой стек говно и это уже проблема на нашей стороне.
Просидел ещё несколько часов.
Не буду ходить долгим путём как же я это выясни, где-то на грани безумства и безысходности пришла мысль, что проблема именно в том, что приложение стало создавать очень много короткоживущих TCP-сессий. Оно успевает ответить клиенту, но закрывает соединение так, что оно оставляет херню в ядре.
Первым делом иду на ноду, где размещён под, у которого проблема
Я выше писал как на ноду на ботлрокете заходить - https://xn--r1a.website/makebreakreflect/205
И ввожу команду:
dmesg | grep conntrack
И вот оно! Розовый слон в комнате:
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
Сразу же видна причина, можно было бы и раньше увидеть 🤡
Пакеты отбрасывает не приложение, не kube-proxy, не CNI - их отбрасывает само ядро Linux ноды, потому что его таблица сетевых состояний забита!
Далее я проверяю, насколько сильно таблица забита и каков ее лимит. Это прямое чтение файлов ядра.
bash-5.1# cat /proc/sys/net/netfilter/nf_conntrack_count
192125
bash-5.1# cat /proc/sys/net/netfilter/nf_conntrack_max
262144
bash-5.1# cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait
120
Приложение-бэкенд, после изменений, стало генерировать аномально высокую частоту короткоживущих TCP-соединений. Система просто не успевает их забыть (таймаут 120 секунд слишком велик), и таблица переполняется.
Делаю нагрузочный тест - да, каррент каунт растёт.
Пробую фикс:
меняю таймаут с 120 на 60 на самой ноде и снова запускаю нагрузочный тест.
Тишина. Снова запускаю скрипт нагрузочного тестирования. Пятисотки исчезли! Красота!
Проконсультировался с коллегами - кто должен править:
- на стороне инфры
- на стороне приложения
Пару Очень Авторитетных Коллег Архитекторов сказали, что точно на стороне приложения и мы перекидываем мячик на сторону девелоперов. Они что-то там правят, тестируют этим же скриптом - всё отлично.
Выкатываем и фикс на прод, пятисоток больше нет, кастомеры довольны.
Белиссимо!
Не дай вселенная вам такое дебажить.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥26😱9👍3🤡1