Make. Build. Break. Reflect.
#пятница #байки #troubleshooting Задолго до работы в айти я был простым советским инженером спутниковой связи. Тарелки, антенны, модемы, кабели, бесконечные командировки. В то время случалось масса странных историй. Мы разрабатывали спутниковое оборудование…
#пятница #байки #всратость
Не дописал ни одну из технических заметок на неделе из-за большого количества работы, а потому сегодня ранее написанная байка.
Помимо производства и продажи наземного спутникового оборудования, компания хотела занять и другие ниши на рынке. Одна из ниш была продажа спутниковой ёмкости.
Компания закупала целый транспондер или широкую полосу на спутнике и продавала маленькие кусочки/полосы желающим. Купили оптом одно, нарубили на кусочки, продавать их, но уже по розничной цене.
Ведь для клиентов ты либо арендуешь на месяц/год небольшую полосу и платишь невероятно сумасшедшие деньги, либо арендуешь пару мегагерц на месяц/год. Конечно рынок сбыта был, не у всех есть деньги на большие полосы и надо было лишь узкую полосу.
Однако есть и другие категории клиентов: покупка полосы, допустим 1-2 мегагерца, на короткое время - час-два.
Это актуально для телеканалов, которым нужно было выехать буквально в поле, открыть антенну на автомобиле, автоматикой арендовать полосу на спутнике, снять репортаж онлайн, свернуть антенну и поехать дальше. Не надо покупать целую полосу или транспондер, это многократно, на порядки дешевле.
В общем компания решила войти в эту новую нишу: в мир автоматизации и продажи программного обеспечения, которое позволит на время арендовать канал телевизионщикам.
Какая была основная идея:
- мы пилим некий heatmap по дате/времени/календарю/частотам/полосам/спутникам, где отображены цветами полоса занята или нет
- у компании-оператора есть эта панель
- клиенты заходят на сайт, при помощи планировщика запрашивают полосу, допустим 0.5МГц, на два часа на четверг днём
- компания-оператор даёт согласие
- нужный кусок конфигурации(частота, ширина полосы, модуляция и тп) попадает на спутниковый модем от этого планировщика
- съёмочная бригада выезжает на место, просто включает оборудование, смотрит на свою собственную панель, на которой он видит ОК или НЕ ОК, можно выходить на связь или нет, убеждается, что всё ок, снимают репортаж, сворачивают антенну
- компания-оператор выставляет счёт клиенту-телеканалу за использование полосы
Это общий план, в котором всё были бы довольны:
- дежурная съёмочная бригада не ломает голову над конфигом, просто включил оборудование, получил что надо на автомате, увидел, что всё ок, вышел в эфир, выключил всё. А если не ок, то и не выходит.
- оператор удачно продал полосу, автоматизировав всё для клиентов
- телеканал за недорого получил услугу
Задача всем понятна, выкатываем первый релиз.
Первый релиз - первая всратость.😭
Разработчики из компании подошли к разработке интерфейса для клиентов максимально логично, с их стороны.
- Зеленый цвет - всё ок, можете выходить в эфир. Всё работает.👍
- Красный цвет - всё не ок, полоса занята/оборудование не работает, конфиг не получен, выходить на связь нельзя.👎
Ну всё же логично!
Логично, но не для мира телевещания.
Оказывается в мире съёмок и студий красный это ON AIR.
- Красный цвет - всё ок. Можно выходить в эфир.
- Зелёный цвет - standby. Ждите, пока можно выйти в эфир.
Ну вы поняли, да?😁
Приезжает одна съёмочная бригада на место, открывает интерфейс софта, там красный индикатор (не получен конфиг, баг на релизе), думает "ну красный же! Можно выходить в эфир!", выходит в эфир, вываливаясь в чужую частоту, ни сами сигнал не передают, да и другим глушат. Красота.
Выезжает другая бригада в поле, открывает UI интерфейс, видят зелёный, сидят , ждут когда можно выйти в эфир.
Час просидели, как тюлени на солнышке, подумали, что им не дали эфир, уехали. Деньги за полосу уплачены, а эфира не было, да и полоса свободна, что обидно. Скандал. Великолепно.
И так далее.
В общем с того релиза компания стала изучать как же устроен другой бизнес, прежде чем, в него войти, а так же более вдумчиво общаться со всеми участниками процесса, вплоть до конечных инженеров-работяг, не допуская неоднозначных ситуаций.
Хорошо, что для медицины ничего не начали поставлять на старте😀
Не дописал ни одну из технических заметок на неделе из-за большого количества работы, а потому сегодня ранее написанная байка.
Помимо производства и продажи наземного спутникового оборудования, компания хотела занять и другие ниши на рынке. Одна из ниш была продажа спутниковой ёмкости.
Компания закупала целый транспондер или широкую полосу на спутнике и продавала маленькие кусочки/полосы желающим. Купили оптом одно, нарубили на кусочки, продавать их, но уже по розничной цене.
Ведь для клиентов ты либо арендуешь на месяц/год небольшую полосу и платишь невероятно сумасшедшие деньги, либо арендуешь пару мегагерц на месяц/год. Конечно рынок сбыта был, не у всех есть деньги на большие полосы и надо было лишь узкую полосу.
Однако есть и другие категории клиентов: покупка полосы, допустим 1-2 мегагерца, на короткое время - час-два.
Это актуально для телеканалов, которым нужно было выехать буквально в поле, открыть антенну на автомобиле, автоматикой арендовать полосу на спутнике, снять репортаж онлайн, свернуть антенну и поехать дальше. Не надо покупать целую полосу или транспондер, это многократно, на порядки дешевле.
В общем компания решила войти в эту новую нишу: в мир автоматизации и продажи программного обеспечения, которое позволит на время арендовать канал телевизионщикам.
Какая была основная идея:
- мы пилим некий heatmap по дате/времени/календарю/частотам/полосам/спутникам, где отображены цветами полоса занята или нет
- у компании-оператора есть эта панель
- клиенты заходят на сайт, при помощи планировщика запрашивают полосу, допустим 0.5МГц, на два часа на четверг днём
- компания-оператор даёт согласие
- нужный кусок конфигурации(частота, ширина полосы, модуляция и тп) попадает на спутниковый модем от этого планировщика
- съёмочная бригада выезжает на место, просто включает оборудование, смотрит на свою собственную панель, на которой он видит ОК или НЕ ОК, можно выходить на связь или нет, убеждается, что всё ок, снимают репортаж, сворачивают антенну
- компания-оператор выставляет счёт клиенту-телеканалу за использование полосы
Это общий план, в котором всё были бы довольны:
- дежурная съёмочная бригада не ломает голову над конфигом, просто включил оборудование, получил что надо на автомате, увидел, что всё ок, вышел в эфир, выключил всё. А если не ок, то и не выходит.
- оператор удачно продал полосу, автоматизировав всё для клиентов
- телеканал за недорого получил услугу
Задача всем понятна, выкатываем первый релиз.
Первый релиз - первая всратость.
Разработчики из компании подошли к разработке интерфейса для клиентов максимально логично, с их стороны.
- Зеленый цвет - всё ок, можете выходить в эфир. Всё работает.
- Красный цвет - всё не ок, полоса занята/оборудование не работает, конфиг не получен, выходить на связь нельзя.
Ну всё же логично!
Логично, но не для мира телевещания.
Оказывается в мире съёмок и студий красный это ON AIR.
- Красный цвет - всё ок. Можно выходить в эфир.
- Зелёный цвет - standby. Ждите, пока можно выйти в эфир.
Ну вы поняли, да?
Приезжает одна съёмочная бригада на место, открывает интерфейс софта, там красный индикатор (не получен конфиг, баг на релизе), думает "ну красный же! Можно выходить в эфир!", выходит в эфир, вываливаясь в чужую частоту, ни сами сигнал не передают, да и другим глушат. Красота.
Выезжает другая бригада в поле, открывает UI интерфейс, видят зелёный, сидят , ждут когда можно выйти в эфир.
Час просидели, как тюлени на солнышке, подумали, что им не дали эфир, уехали. Деньги за полосу уплачены, а эфира не было, да и полоса свободна, что обидно. Скандал. Великолепно.
И так далее.
В общем с того релиза компания стала изучать как же устроен другой бизнес, прежде чем, в него войти, а так же более вдумчиво общаться со всеми участниками процесса, вплоть до конечных инженеров-работяг, не допуская неоднозначных ситуаций.
Хорошо, что для медицины ничего не начали поставлять на старте
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17🫡10🔥7🥰2🤣1
#kubernetes #linux #база
Существует достаточно частая проблема: ошибки категории "
Когда копаешь в одно, а проблема в другом.
Инженеры Kubernetes иногда сталкиваются с крайне сбивающей с толку ошибкой при запуске пода:
Не зная причины этой ошибки, мы сперва тратим время на:
- просмотр что за PVC используются у деплоймента/пода.
- что за нода сейчас запустила этот под, нет ли нехватки места на самой ноде
- лезут в графану, в метрики и графики по нодам, подам, PV
- как разбиты разделы диска на нодах, что и сколько отдаётся эфемеркам
- чего там по айнодам (ну наконец-то пригодились эти знания!🕺 )
- и так далее
И это правильные мысли и план, это так же может быть причиной ошибки, но наш случай про другое.
Попытка найти строку "
Истинная причина кроется в тонком различии между единицами измерения CPU и памяти в спецификации ресурсов. Это особенно критично для Проецируемых томов (Projected Volumes), таких как Service Account Token (
https://kubernetes.io/docs/concepts/storage/projected-volumes/
Когда инженер по ошибке использует суффикс CPU (m) для лимита памяти, например:
-
-
- Ядро Linux получает запрос на монтирование
То есть в нашем случае ошибка "
❕Стоит понимать, что Kubernetes API сервер не считает "512m" для памяти ошибкой валидации.
Он принимает это как легальное значение (0.512 байта), что позволяет поду быть созданным, но приводит к сбою выполнения (runtime failure) при монтировании на ноде.
Решение очевидное:
всегда используйте бинарные единицы (IEC) для ресурсов памяти: Mi (мебибайты), Gi (гибибайты).
Может есть и другие, я только эти использовал всегда.
Чтобы превентивно избавляться от такой проблемы, используйте дополнительно:
- pre-commit hooks
- валидаторы cli в CI/CD процессе
Какие-то конкретные утилиты советовать не буду, оставлю ссылки для примера:
- https://github.com/instrumenta/kubeval (давно не обновлялся, но он работает ок)
- https://github.com/yannh/kubeconform
- https://github.com/kubernetes-sigs/kubectl-validate
Кстати, аналогичные ошибки встречаются при монтировании секретов, конфигмапов и других tmpfs-бэкендов, использующих лимиты памяти контейнера.
Существует достаточно частая проблема: ошибки категории "
misleading".Когда копаешь в одно, а проблема в другом.
Инженеры Kubernetes иногда сталкиваются с крайне сбивающей с толку ошибкой при запуске пода:
MountVolume.SetUp failed... no space left on device.
Не зная причины этой ошибки, мы сперва тратим время на:
- просмотр что за PVC используются у деплоймента/пода.
- что за нода сейчас запустила этот под, нет ли нехватки места на самой ноде
- лезут в графану, в метрики и графики по нодам, подам, PV
- как разбиты разделы диска на нодах, что и сколько отдаётся эфемеркам
- чего там по айнодам (ну наконец-то пригодились эти знания!
- и так далее
И это правильные мысли и план, это так же может быть причиной ошибки, но наш случай про другое.
Попытка найти строку "
no space left on device" в исходном коде Kubelet на GitHub также не дает результатов, потому что Kubelet не генерирует этот текст - он просто ретранслирует низкоуровневую ошибку, полученную от ядра Linux(или от рантайма, тут могу наврунькать).Истинная причина кроется в тонком различии между единицами измерения CPU и памяти в спецификации ресурсов. Это особенно критично для Проецируемых томов (Projected Volumes), таких как Service Account Token (
kube-api-access-*), которые монтируются как tmpfs (файловая система в RAM).https://kubernetes.io/docs/concepts/storage/projected-volumes/
Когда инженер по ошибке использует суффикс CPU (m) для лимита памяти, например:
resources:
limits:
memory: "512m" # Ошибка, должно быть "512Mi"!
-
Kubelet парсит "512m" для памяти как метрический милли, что равно 0.512 байта. Поскольку размер тома (tmpfs) должен быть целым числом, это значение округляется до 0 байт (или ничтожно малого значения). Kubelet использует этот 0 байт для установки максимального размера тома tmpfs.-
Kubelet использует этот лимит памяти для установки максимального размера тома tmpfs для Service Account токена- Ядро Linux получает запрос на монтирование
tmpfs с нулевым или ничтожно малым размером. Системный вызов mount завершается неудачей (из-за попытки выделить даже минимальный объём, обычно 1 страница = 4 KiB). и возвращает низкоуровневую ошибку ENOSPC ("No space left on device"), поскольку невозможно создать файловую систему (даже в RAM) с таким малым выделением ресурсов.То есть в нашем случае ошибка "
no space left on device" на самом деле означает: "Не удалось создать RAM-диск (tmpfs) требуемого объема, потому что выделенный размер (0 байт) некорректен".❕Стоит понимать, что Kubernetes API сервер не считает "512m" для памяти ошибкой валидации.
Он принимает это как легальное значение (0.512 байта), что позволяет поду быть созданным, но приводит к сбою выполнения (runtime failure) при монтировании на ноде.
Решение очевидное:
всегда используйте бинарные единицы (IEC) для ресурсов памяти: Mi (мебибайты), Gi (гибибайты).
Может есть и другие, я только эти использовал всегда.
Чтобы превентивно избавляться от такой проблемы, используйте дополнительно:
- pre-commit hooks
- валидаторы cli в CI/CD процессе
Какие-то конкретные утилиты советовать не буду, оставлю ссылки для примера:
- https://github.com/instrumenta/kubeval (давно не обновлялся, но он работает ок)
- https://github.com/yannh/kubeconform
- https://github.com/kubernetes-sigs/kubectl-validate
Кстати, аналогичные ошибки встречаются при монтировании секретов, конфигмапов и других tmpfs-бэкендов, использующих лимиты памяти контейнера.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤19👍9
#azure #aws
AWS:
- У нас авария, ничего не понятно, только не пишите в статус пейдже, в самом начале инцидента, что это DNS, пока пишите про что угодно, но не про DNS, ну не знаю, пусть будет свой собственный мониторинг и DynamoDB.
Azure:
- У нас авария, ничего не понятно, там у AWS недавно был DNS, давайте напишем в статус пейдже, что у нас тоже DNS, а потом поменяем на реальную причину, вдруг там AFD.
AWS:
- У нас авария, ничего не понятно, только не пишите в статус пейдже, в самом начале инцидента, что это DNS, пока пишите про что угодно, но не про DNS, ну не знаю, пусть будет свой собственный мониторинг и DynamoDB.
Azure:
- У нас авария, ничего не понятно, там у AWS недавно был DNS, давайте напишем в статус пейдже, что у нас тоже DNS, а потом поменяем на реальную причину, вдруг там AFD.
🤣26👍1😨1
#azure #devops #entra #powershell
Мелкая компания из трёх суетливых инженеров при удаче вырастает до большой организации в 150+ человек.
Люди уходят и приходят, а хорошего процесса оффбординга Entra ID иногда нет.
Иногда удаляют/выключают аккаунты, иногда нет. Иногда просто создают и не пользуются.
Чистка аккаунтов это крайне важный элемент девопс процессов.
Рано или поздно приходит любой аудит и очистка аккаунтов необходима.
И вот аудит пришёл.
Именно тогда прилетают странные задачки, типа "причесать каталог юзеров".
Захожу, а там 200+ аккаунтов, 85% которых я вижу впервые.
Хорошо, моя идея в общих чертах такая:
- найти всех пользователей
- отсортировать тех, у кого аккаунт включён (accountEnabled)
- собрать ключевые данные: Display Name, UPN/Email, дата создания и, главное, дата последнего входа
- отфильтровать по порогу неактивности (например, более 60 дней)
- сформировать таблицу (CSV-файл) с колонкой для решения ("Действие")
- отправить файл руководству (коллегам/боссу/СТО) на согласование, чтобы избежать удаления важных служебных аккаунтов или аккаунтов инвесторов
- удалить/выключить пользователей согласно утвержденному списку.
Как же это сделать? Ведь Microsoft Entra ID не предоставляет таких данных в удобном виде
Да и az cli такого не предоставляет.
На помощь приходит PowerShell и модули.
Поехали пошагово:
- запускаю PowerShell с правами администратора
- проверяю есть ли права на выполнение скриптов
- если рестриктед, то надо включить(не забыть выключить)
- теперь мне надо установить модуль
- импортирую модуль для этой сессии
- затем надо подключиться к Microsoft Graph с такими правами
На этом этапе откроется браузер, надо пройти авторизацию
- пилим скрипт(можно даже построчно вводить)
- на выходе получаю
- копирую, вставляю в Excel, добавляю новую колонку delete/don't touch
(или сразу пилить в CSV, как кому удобнее)
- отправляю руководству
- получаю ответ, выключаю/удаляю ненужных юзеров
Задача закрыта, в каталоге порядок.
Так. А почему именно я делаю эту задачу?
А нечего было всем в рабочих чатах говорить, что винда лучшая операционная система.
Вот и сиди, пиши пош-скрипты😭
Мелкая компания из трёх суетливых инженеров при удаче вырастает до большой организации в 150+ человек.
Люди уходят и приходят, а хорошего процесса оффбординга Entra ID иногда нет.
Иногда удаляют/выключают аккаунты, иногда нет. Иногда просто создают и не пользуются.
Чистка аккаунтов это крайне важный элемент девопс процессов.
Рано или поздно приходит любой аудит и очистка аккаунтов необходима.
И вот аудит пришёл.
Именно тогда прилетают странные задачки, типа "причесать каталог юзеров".
Захожу, а там 200+ аккаунтов, 85% которых я вижу впервые.
Хорошо, моя идея в общих чертах такая:
- найти всех пользователей
- отсортировать тех, у кого аккаунт включён (accountEnabled)
- собрать ключевые данные: Display Name, UPN/Email, дата создания и, главное, дата последнего входа
- отфильтровать по порогу неактивности (например, более 60 дней)
- сформировать таблицу (CSV-файл) с колонкой для решения ("Действие")
- отправить файл руководству (коллегам/боссу/СТО) на согласование, чтобы избежать удаления важных служебных аккаунтов или аккаунтов инвесторов
- удалить/выключить пользователей согласно утвержденному списку.
Как же это сделать? Ведь Microsoft Entra ID не предоставляет таких данных в удобном виде
*.Да и az cli такого не предоставляет.
На помощь приходит PowerShell и модули.
Поехали пошагово:
- запускаю PowerShell с правами администратора
- проверяю есть ли права на выполнение скриптов
Get-ExecutionPolicy
Restricted
- если рестриктед, то надо включить(не забыть выключить)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
Y
- теперь мне надо установить модуль
Install-Module Microsoft.Graph -Scope CurrentUser
- импортирую модуль для этой сессии
Import-Module Microsoft.Graph.Authentication
- затем надо подключиться к Microsoft Graph с такими правами
Connect-MgGraph -Scopes "User.Read.All", "AuditLog.Read.All"
На этом этапе откроется браузер, надо пройти авторизацию
- пилим скрипт(можно даже построчно вводить)
$InactiveDays = 60
$DateCutoff = (Get-Date).AddDays(-$InactiveDays)
$Users = Get-MgUser -All -Filter "accountEnabled eq true" -Property Id, DisplayName, UserPrincipalName, SignInActivity, AccountEnabled
$InactiveUsers = $Users | Where-Object {
$_.SignInActivity -ne $null -and
$_.SignInActivity.LastSignInDateTime -ne $null -and
$_.SignInActivity.LastSignInDateTime -lt $DateCutoff
} | Select-Object DisplayName, UserPrincipalName, @{Name="LastSignInDate"; Expression={$_.SignInActivity.LastSignInDateTime}}
#mock
$InactiveUsers | Format-Table
$NeverSignedInUsers = $Users | Where-Object {
$_.SignInActivity -eq $null -or
$_.SignInActivity.LastSignInDateTime -eq $null
} | Select-Object DisplayName, UserPrincipalName, @{Name="LastSignInDate"; Expression={"Never Signed In (or before Apr 2020)"}}
$InactiveUsers + $NeverSignedInUsers | Format-Table -AutoSize
- на выходе получаю
DisplayName UserPrincipalName LastSignInDate
----------- ----------------- --------------
Ivan Petrov ivan.petrov@contoso.com 2022-03-15 10:45:12
Maria Sidorova (Guest) m.sidorova_ext@contoso.com 2021-11-20 14:02:55
Alexey Smirnov a.smirnov@contoso.com 2022-04-01 08:10:30
New Folder(1) test.user@contoso.com Never Signed In (or before Apr 2020)
- копирую, вставляю в Excel, добавляю новую колонку delete/don't touch
(или сразу пилить в CSV, как кому удобнее)
($InactiveUsers + $NeverSignedInUsers) | Export-Csv -Path "C:\Users\alexk\InactiveUsers_Audit.csv" -NoTypeInformation
- отправляю руководству
- получаю ответ, выключаю/удаляю ненужных юзеров
Задача закрыта, в каталоге порядок.
Так. А почему именно я делаю эту задачу?
А нечего было всем в рабочих чатах говорить, что винда лучшая операционная система.
Вот и сиди, пиши пош-скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8😁5
- - -
В августе 2025 появилась эта фича https://learn.microsoft.com/en-us/entra/identity/users/users-bulk-download, теперь почти всё можно делать в UI. Однако доступны не все поля, нельзя сделать несколько фильтров последовательно, так что подход всё ещё актуален.
*Случай был 2023 году.В августе 2025 появилась эта фича https://learn.microsoft.com/en-us/entra/identity/users/users-bulk-download, теперь почти всё можно делать в UI. Однако доступны не все поля, нельзя сделать несколько фильтров последовательно, так что подход всё ещё актуален.
#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
#helm #kubernetes
Три прыжка.
Прыжок в воду 1.
Можно просто почитать официальную документацию на версию 3.19
Немного лукавит из-за нерегулярного обновления, но в целом 90% инженерам этого достаточно.
Мы теперь знаем, что перед деплойментом у нас есть секрет, перед ним PVC, а ещё раньше их неймспейс.
Это логично и не рождает проблем в стандартных чартах.
Прыжок в воду 2.
Так же можно посмотреть в исходном коде на версию 3.19
Там видно настоящий список, а так же указаны логические операторы про анноун ресурсам и сортировке.
Всякие CRD, хуки и весы.
Чуть точнее и глубже, этого достаточно ещё 5% людей.
Прыжок в воду 3.
Побудем сегодня любопытными инженерами и узнаем всё до конца, нырнув глубже.
В общем и целом есть несколько основных категорий:
-
-
-
-
-
При запуске
1)
Они не шаблонизируются, а применяются как есть.
https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/
2)
Если есть. (
Внутри группы хуков сначала сортируются по весу(
-
-
Внутри одного веса сортировка идёт по имени ресурса (алфавитно).
https://helm.sh/docs/topics/charts_hooks/
3)
Сортировка происходит после рендеринга шаблонов, но до их применения к кластеру.
Рендеринг -> сортировка -> применение.
-
-
..
-
..
-
..
4)
Так сказать всё остальное бесчисленное множество.
Важно понимать, что внутри группы
-
-
..
-
Этот алфавитный порядок зачастую не совпадает с требуемым логическим порядком зависимостей.
5)
Если есть. (
Внутри группы хуков сначала сортируются по весу(
-
-
Внутри одного веса сортировка идёт по имени ресурса (алфавитно).
https://helm.sh/docs/topics/charts_hooks/
Вот теперь картина полная и мы славные инженеры.
- - -
Для чего же мы ныряем так глубоко? Зачем нам это?
Иногда прилетают задачи о оптимизации имеющегося чарта.
Например (это. лишь. пример), у нас сложная технологическая платформа, а в чарте есть и
Все ресурсы категории
Нет ишшуера/не будет выпущен серт - не будет его куда запушить/примонтировать - не будет секрета/пушсикрета - проблема платформы. Да и серт не мгновенно выпускается. Нужно время. Как быть?
Тот же
Как раз тут и пригодятся нам эти глубокие знания.
Зная правила мы спокойно решаем задачу.
- Алекс, а что там с Арго?
Под капотом ArgoCD использует как раз
https://argo-cd.readthedocs.io/en/stable/user-guide/helm/
- А что там с хуками?
Argo CD автоматически конвертирует эту логику в свои Hooks и Waves, сохраняя ваш строгий контроль над порядком.
-
-
https://argo-cd.readthedocs.io/en/release-2.14/user-guide/resource_hooks/
https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/
Занимательное:
- при
Три прыжка.
Как же идёт порядок генерации манифестов по шаблону, сортировка и применение в кластере при использовании Helm v3?
Прыжок в воду 1.
Можно просто почитать официальную документацию на версию 3.19
Немного лукавит из-за нерегулярного обновления, но в целом 90% инженерам этого достаточно.
Мы теперь знаем, что перед деплойментом у нас есть секрет, перед ним PVC, а ещё раньше их неймспейс.
Это логично и не рождает проблем в стандартных чартах.
Прыжок в воду 2.
Так же можно посмотреть в исходном коде на версию 3.19
Там видно настоящий список, а так же указаны логические операторы про анноун ресурсам и сортировке.
Всякие CRD, хуки и весы.
Чуть точнее и глубже, этого достаточно ещё 5% людей.
Прыжок в воду 3.
Побудем сегодня любопытными инженерами и узнаем всё до конца, нырнув глубже.
В общем и целом есть несколько основных категорий:
-
pre-* хуки-
post-* хуки-
Standard ресурсы-
CRD-
Unknown ресурсыПри запуске
helm install/helm upgrade --install у нас идёт такой порядок:1)
CRD. Всегда первым. Из директории <чарт>/crds/.Они не шаблонизируются, а применяются как есть.
https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/
2)
pre-install hooks. Если есть. (
"helm.sh/hook": *)Внутри группы хуков сначала сортируются по весу(
"helm.sh/hook-weight"):-
отрицательный -
ноль (по умолчанию)
- положительный
- по имениВнутри одного веса сортировка идёт по имени ресурса (алфавитно).
https://helm.sh/docs/topics/charts_hooks/
3)
standard ресурсы, по порядку в исходном коде в kind_sorter.goСортировка происходит после рендеринга шаблонов, но до их применения к кластеру.
Рендеринг -> сортировка -> применение.
-
PriorityClass-
Namespace..
-
ClusterRoleBinding..
-
Deployment..
4)
Unknown ресурсыТак сказать всё остальное бесчисленное множество.
Важно понимать, что внутри группы
Unknown ресурсов порядок детерминирован и следует правилу: сначала сортировка по Kind (алфавитно) (например, ApplicationSet перед PostgreSQL), а затем по имени ресурса (алфавитно).-
ApplicationsSet (ArgoCD)-
PostgreSQL (Zalando)..
-
ScaledObject (KEDA)Этот алфавитный порядок зачастую не совпадает с требуемым логическим порядком зависимостей.
5)
post-install хуки. Если есть. (
"helm.sh/hook": *)Внутри группы хуков сначала сортируются по весу(
"helm.sh/hook-weight"):-
отрицательный -
ноль (по умолчанию)
- положительный
- по имениВнутри одного веса сортировка идёт по имени ресурса (алфавитно).
https://helm.sh/docs/topics/charts_hooks/
Вот теперь картина полная и мы славные инженеры.
- - -
Для чего же мы ныряем так глубоко? Зачем нам это?
Иногда прилетают задачи о оптимизации имеющегося чарта.
Например (это. лишь. пример), у нас сложная технологическая платформа, а в чарте есть и
cert-manager с выпуском сертификатов, и externalsecrets и issuer, и многое другое.Все ресурсы категории
Unknown и нам нужен строгий порядок или, что хуже, тайминг(чтобы успело создаться что-то до следующего ресурса).Нет ишшуера/не будет выпущен серт - не будет его куда запушить/примонтировать - не будет секрета/пушсикрета - проблема платформы. Да и серт не мгновенно выпускается. Нужно время. Как быть?
Тот же
issuer по алфавиту идёт после certificate, хотя должно быть и иначе, а pushsecret ничего не сможет прокинуть, потому что серт ещё не выпущен. И всё обёрнуто через ArgoCD.Как раз тут и пригодятся нам эти глубокие знания.
Зная правила мы спокойно решаем задачу.
- Алекс, а что там с Арго?
Под капотом ArgoCD использует как раз
helm template.https://argo-cd.readthedocs.io/en/stable/user-guide/helm/
- А что там с хуками?
Argo CD автоматически конвертирует эту логику в свои Hooks и Waves, сохраняя ваш строгий контроль над порядком.
-
helm.sh/hook -> Resource Hooks-
helm.sh/hook-weight -> Sync Waveshttps://argo-cd.readthedocs.io/en/release-2.14/user-guide/resource_hooks/
https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/
Занимательное:
- при
helm upgrade CRD из crds/ не обновляются (Helm не изменяет их содержимое, нужно делать вручную), только при helm install1👍19❤5🔥1👨💻1🆒1
#terragrunt
Волею случая и нового проекта надо было обновить террагрант.
Ну типа была версия старая, по привычке используемая везде - 0.54.15.
А тут и терраформ новее, и синтаксис подсвечивает модуль, что ошибка, и форматтера нет, и пре-коммит поставил, чтобы форматировал при коммитах.
А пре-коммит в свою очередь хочет минимум версию 0.77.22.
В общем надо было обновиться и я сделал это.
И тут, блин, началось. Мусор какой-то в аутпуте при плане и апплае.
Даже немного попсиховал.
Словно включен инфо/дебаг левел.
Сперва посмотрел в
По диагонали залез в мануал cli - ничего не нашёл.
Попробовал классические варианты типа
Тоже не помогает.
Херня какая, полез для скорости в AI (ох, и я попался на эту удочку снова).
Несёт хрень всякую, я гиеной заорал с советов, там и отключить это нельзя, и давай добавим local-exec с🤣
Делать нечего - полез в документацию, там, неожиданно для меня, произошли изменения касательно аутпута.
Начиная с версии v0.77.0 (вроде бы) террагрант вчистую выводит то, что даёт ему терраформ или другие утилиты типа opentofu.
https://terragrunt.gruntwork.io/docs/reference/logging/#log-levels
Чтобы "было как раньше" и "как привык" я пока нашёл одно решение - в
Ну либо использовать флаг (мне так очевидно неудобно).
Только так он выводит "как раньше", без лишнего мусора.
Предполагаю, что новые изменения удобнее всему комьюнити, кроме меня, ну либо для тех, у кого десятки, сотни модулей и при
Штош, ещё одна переменная в конфигах.
Волею случая и нового проекта надо было обновить террагрант.
Ну типа была версия старая, по привычке используемая везде - 0.54.15.
А тут и терраформ новее, и синтаксис подсвечивает модуль, что ошибка, и форматтера нет, и пре-коммит поставил, чтобы форматировал при коммитах.
---
repos:
- repo: https://github.com/gruntwork-io/pre-commit
rev: v0.1.30
hooks:
- id: terragrunt-hcl-fmt
А пре-коммит в свою очередь хочет минимум версию 0.77.22.
В общем надо было обновиться и я сделал это.
И тут, блин, началось. Мусор какой-то в аутпуте при плане и апплае.
Даже немного попсиховал.
Словно включен инфо/дебаг левел.
09:34:36.050 STDOUT terraform: ~ default_node_pool {
09:34:36.050 STDOUT terraform: ~ auto_scaling_enabled = false -> true
09:34:36.050 STDOUT terraform: ~ max_count = 0 -> 4
09:34:36.050 STDOUT terraform: ~ min_count = 0 -> 2
09:34:36.050 STDOUT terraform: name = "general"
09:34:36.050 STDOUT terraform: tags = {}
09:34:36.050 STDOUT terraform: # (28 unchanged attributes hidden)
09:34:36.050 STDOUT terraform: # (1 unchanged block hidden)
09:34:36.050 STDOUT terraform: }Сперва посмотрел в
env | grep -i terra / env | grep -i tf, но не вижу ничего критичного.По диагонали залез в мануал cli - ничего не нашёл.
Попробовал классические варианты типа
TF_LOG=ERROR TERRAGRUNT_LOG_LEVEL=error terragrunt plan
Тоже не помогает.
Херня какая, полез для скорости в AI (ох, и я попался на эту удочку снова).
Несёт хрень всякую, я гиеной заорал с советов, там и отключить это нельзя, и давай добавим local-exec с
export TF* Делать нечего - полез в документацию, там, неожиданно для меня, произошли изменения касательно аутпута.
Начиная с версии v0.77.0 (вроде бы) террагрант вчистую выводит то, что даёт ему терраформ или другие утилиты типа opentofu.
https://terragrunt.gruntwork.io/docs/reference/logging/#log-levels
Чтобы "было как раньше" и "как привык" я пока нашёл одно решение - в
~/.bashrc добавитьexport TG_LOG_FORMAT=bare
Ну либо использовать флаг (мне так очевидно неудобно).
terragrunt --log-format bare plan
Только так он выводит "как раньше", без лишнего мусора.
~ default_node_pool {
~ auto_scaling_enabled = false -> true
~ max_count = 0 -> 4
~ min_count = 0 -> 2
name = "general"
tags = {}
# (28 unchanged attributes hidden)
# (1 unchanged block hidden)
}Предполагаю, что новые изменения удобнее всему комьюнити, кроме меня, ну либо для тех, у кого десятки, сотни модулей и при
terragrunt run-all становится очень сложно понять, какое именно сообщение относится к какому именно модулю или к какому инструменту (Terragrunt или Terraform). Штош, ещё одна переменная в конфигах.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤1
#terragrunt
Интересную штуку подглядел у коллеги.
Ну с тегами окружения и менеджед бай террагрант меня не удивить.
Но путь до модуля! Это гениально!
Гениально и просто.
Почему я раньше об этом не знал? Это ведь так удобно, сразу видно откуда чего куда и как.
В эпоху модулей из модулей, внутри которых модули из модулей, со стаками, с композитными модулями - это чрезвычайно удобное мелкое дополнение.
Наверняка это придумали в мезозое и уже успели заменить на что-то другое, а я узнал только сегодня, ну да и ладно🤡
Интересную штуку подглядел у коллеги.
provider "aws" {
...
default_tags {
tags = {
environment = "${local.environment}"
managed_by = "terragrunt"
terragrunt_path = "${path_relative_to_include()}" <<<<<< this one
}
}
}
Ну с тегами окружения и менеджед бай террагрант меня не удивить.
Но путь до модуля! Это гениально!
Гениально и просто.
Почему я раньше об этом не знал? Это ведь так удобно, сразу видно откуда чего куда и как.
В эпоху модулей из модулей, внутри которых модули из модулей, со стаками, с композитными модулями - это чрезвычайно удобное мелкое дополнение.
Наверняка это придумали в мезозое и уже успели заменить на что-то другое, а я узнал только сегодня, ну да и ладно
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12👏1
Прям день интересных событий.
- то релиз helm 4 https://helm.sh/docs/overview/
- то nginx retirement https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/
Всё же придётся ехать на k8s Gateway API?😭
- то релиз helm 4 https://helm.sh/docs/overview/
- то nginx retirement https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/
To prioritize the safety and security of the ecosystem, Kubernetes SIG Network and the Security Response Committee are announcing the upcoming retirement of Ingress NGINX
Всё же придётся ехать на k8s Gateway API?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7😭6
#kubernetes #troubleshooting #база
Просыпаюсь, иду работать, ничего не предвещает беды.
Хрен.
Через пару часов падает часть подов. UI - таймауты. Бэкенд - 5xx.
Приложение пишет, что не может создать файл.
Иногда не может прочитать файл.
Иногда "
Иногда "
Иногда просто падает - "
Короче, классический Kubernetes с его прозрачностью в траблшутинге.😀
Ну ладно. Открываю Grafana/VMlogs - ошибок море, но… никакой, блть, логики.
Все поды работают вроде бы одинаково, но часть подов стабильно отваливается примерно через минуту после старта.
Куда копать - сходу непонятно.
Иду в самое очевидное - Storage: PV, PVC
Потому что ошибки про файлы > проблемы с томами > ну значит PV/PVC где-то хромает, как старая лошадь.
Проверяю:
- PVC смонтировались? Да.
- PV healthy? Да.
- Нода здорова? Да.
- Место есть? Да.
- Inodes есть? (снова пригодились знания🕺 ) Да.
Да чтоб тебя, сука.
Пробую перезапустить под на другой ноде - та же история.
Смотрю в события пода - красиво, чисто, как будто всё хорошо.
А приложение продолжает ругаться.
Симптомы - про Storage, причина - явно что-то другое.
Чешу свой пельменоаннигилятор и иду смотреть
Разработчики говорят:
- Мы в PV почти ничего не пишем, у нас всё в /tmp, shared memory, и ещё парочка emptyDir
(я вообще не уверен, что они понимают разницу, наверняка спросили нейронку). Ладно.
Лезу в POD, смотрю
И тут интересное - папка есть, но файлы внутри иногда пропадают, иногда имеют странные владельцы, иногда пустые.
Жмурюсь, словно алкоголик с утра, перезапускаю под - то же самое.
Щёлкают мысли:
- race condition?
- или tmpfs не монтируется как надо?
- коричневая магия?
Проверяю:
Да, монтируется.
Проверяю параметры - тоже всё ок.
Чо ха херня.
Поехали к ноде. Захожу на ноду и смотрю логи kubelet
И тут - первый звоночек:
Вот оно.
Бл, но как так-то?!
Это странно:
* На самом деле этого уже достаточно, чтобы понять причину, но мне это станет ясно только позже.
Пока я этого не понимаю, иду дальше.
Пытаюсь понять, что у файла не так.
Смотрю
Иду в документацию приложения и к разработчикам, выясняю, что приложение должно работать от:
Но папки создаются с 1001, какие-то с root, какие-то с 2000.
Ошибка хаотичная.
При этом разработчики уверяют:
- Мы ничего такого не делали!
Ну да, конечно, лол.
Проверяю
И вот оно:
Ну, думаю, может фигня, мало ли. Но идём дальше.
По дороге читаю документацию к приложению, куберу (я чо, всё помнить должен что-ли? Конечно же я постоянно подсматриваю).
И тут я натыкаюсь на тот самый скрытый момент.
Как я понимаю, если в контейнере есть:
- tmpfs (например /tmp, shared memory, projected volumes)
- emptyDir
- securityContext с fsGroup
- и при этом runAsUser != fsGroup
- И ПРИ ЭТОМ, сука, приложение создаёт файлы при старте до того, как kubelet применил fsGroup, то...
...получаем race condition, когда kubelet пытается chown, но контейнер уже создал свои файлы - с другими UID/GID - и chown уже не проходит.
kubelet такой:
- Я меняю владельца папки!
контейнер такой:
- А я создаю файлы внутри неё!
девопс такой:
- А я в дурку еду от вас двоих!
И кто быстрее - тот и прав.
Результат:
- часть файлов принадлежит пользователю 1001
- часть - root
- часть - fsGroup (предполагаю)
- часть - остаётся как попало
- kubelet иногда пишет permission denied
- приложение иногда пишет permission denied
- иногда - no such file (потому что удаляется побочным процессом?)
- иногда - ломается tmpfs-шляпа полностью
Эти два идиота(кублет и контейнер) сражаются как два бомжа палками, измазанными в говне. Придурошные, лол.
Просыпаюсь, иду работать, ничего не предвещает беды.
Хрен.
Через пару часов падает часть подов. UI - таймауты. Бэкенд - 5xx.
Приложение пишет, что не может создать файл.
Иногда не может прочитать файл.
Иногда "
no such file or directory". Иногда "
permission denied". Иногда просто падает - "
error".Короче, классический Kubernetes с его прозрачностью в траблшутинге.
Ну ладно. Открываю Grafana/VMlogs - ошибок море, но… никакой, блть, логики.
Все поды работают вроде бы одинаково, но часть подов стабильно отваливается примерно через минуту после старта.
Куда копать - сходу непонятно.
Иду в самое очевидное - Storage: PV, PVC
Потому что ошибки про файлы > проблемы с томами > ну значит PV/PVC где-то хромает, как старая лошадь.
Проверяю:
- PVC смонтировались? Да.
- PV healthy? Да.
- Нода здорова? Да.
- Место есть? Да.
- Inodes есть? (снова пригодились знания
Да чтоб тебя, сука.
Пробую перезапустить под на другой ноде - та же история.
Смотрю в события пода - красиво, чисто, как будто всё хорошо.
А приложение продолжает ругаться.
Симптомы - про Storage, причина - явно что-то другое.
Чешу свой пельменоаннигилятор и иду смотреть
emptyDir/tmpfs и вот это вот всё.Разработчики говорят:
- Мы в PV почти ничего не пишем, у нас всё в /tmp, shared memory, и ещё парочка emptyDir
(я вообще не уверен, что они понимают разницу, наверняка спросили нейронку). Ладно.
Лезу в POD, смотрю
/tmp.И тут интересное - папка есть, но файлы внутри иногда пропадают, иногда имеют странные владельцы, иногда пустые.
Жмурюсь, словно алкоголик с утра, перезапускаю под - то же самое.
Щёлкают мысли:
- race condition?
- или tmpfs не монтируется как надо?
- коричневая магия?
Проверяю:
mount | grep tmpfs
Да, монтируется.
Проверяю параметры - тоже всё ок.
Чо ха херня.
Поехали к ноде. Захожу на ноду и смотрю логи kubelet
И тут - первый звоночек:
MountVolume.SetUp failed for volume "cache" : chown /var/lib/kubelet/pods/.../volumes/kubernetes.io~empty-dir/cache: permission denied
Вот оно.
Бл, но как так-то?!
Это странно:
emptyDir монтируется нормально, но kubelet не может сделать chown/chmod.* На самом деле этого уже достаточно, чтобы понять причину, но мне это станет ясно только позже.
Пока я этого не понимаю, иду дальше.
Пытаюсь понять, что у файла не так.
Смотрю
ls -la внутри контейнера:drwxr-xr-x 3 1001 root ...
Иду в документацию приложения и к разработчикам, выясняю, что приложение должно работать от:
runAsUser: 2000
runAsGroup: 2000
fsGroup: 2000
Но папки создаются с 1001, какие-то с root, какие-то с 2000.
Ошибка хаотичная.
При этом разработчики уверяют:
- Мы ничего такого не делали!
Ну да, конечно, лол.
Проверяю
git diff Helm-чарта.И вот оно:
securityContext:
runAsUser: 1001
runAsGroup: 1001
fsGroup: 1001
fsGroupChangePolicy: "OnRootMismatch"
Ну, думаю, может фигня, мало ли. Но идём дальше.
По дороге читаю документацию к приложению, куберу (я чо, всё помнить должен что-ли? Конечно же я постоянно подсматриваю).
И тут я натыкаюсь на тот самый скрытый момент.
Как я понимаю, если в контейнере есть:
- tmpfs (например /tmp, shared memory, projected volumes)
- emptyDir
- securityContext с fsGroup
- и при этом runAsUser != fsGroup
- И ПРИ ЭТОМ, сука, приложение создаёт файлы при старте до того, как kubelet применил fsGroup, то...
...получаем race condition, когда kubelet пытается chown, но контейнер уже создал свои файлы - с другими UID/GID - и chown уже не проходит.
kubelet такой:
- Я меняю владельца папки!
контейнер такой:
- А я создаю файлы внутри неё!
- А я в дурку еду от вас двоих!
И кто быстрее - тот и прав.
Результат:
- часть файлов принадлежит пользователю 1001
- часть - root
- часть - fsGroup (предполагаю)
- часть - остаётся как попало
- kubelet иногда пишет permission denied
- приложение иногда пишет permission denied
- иногда - no such file (потому что удаляется побочным процессом?)
- иногда - ломается tmpfs-шляпа полностью
Эти два идиота(кублет и контейнер) сражаются как два бомжа палками, измазанными в говне. Придурошные, лол.
Please open Telegram to view this post
VIEW IN TELEGRAM
2💊19❤10
#kubernetes #troubleshooting #база
Так какого рожна сломалось именно после обновления?
Вот тут самое вкусное.
Разработчики изменили не приложение, а🤡 :
То есть теперь контейнер стартует не как root, а как 1001.
Но в
fsGroup != runAsGroup и kubelet пытается менять владельцев!!!
А tmpfs создаётся уже внутри контейнера процессом с UID 1001!!!
Получается конфликт:
- kubelet хочет chown
- контейнер уже что-то пишет
- tmpfs/emptyDir получаются с разными владельцами
И Kubernetes начинает жрать собственную ногу.
Ну и чо делать?
- Вариант 1: отключить fsGroup, если он реально не нужен
- Вариант 2: поставить fsGroup = runAsGroup
- Вариант 3: включить legacy режим
Предполагаю, что третий вариант это костыль, пишу как вариант, но, я сделал вариант 2.
Но это не точно.
Какие итоги:
- снова нырнул в дебаггинг. Интересно, но снова потрачено время
- отмазкам "мы ничо не меняли" как обычно верить нельзя. Гит всё покажет
- я вообще не знаю как такое допускает архитектура куба, почему не сделать разумную валидацию где-то на это, ну бред же. Мы самолично стреляем себе в коленные чашечки и потом удивляемся "а чо не так то?"
Так какого рожна сломалось именно после обновления?
Вот тут самое вкусное.
Разработчики изменили не приложение, а
DockerfileUSER 1001
То есть теперь контейнер стартует не как root, а как 1001.
Но в
securityContext при этом осталось:fsGroup: 2000
runAsUser: 1001
runAsGroup: 1001
fsGroup != runAsGroup и kubelet пытается менять владельцев!!!
А tmpfs создаётся уже внутри контейнера процессом с UID 1001!!!
Получается конфликт:
- kubelet хочет chown
- контейнер уже что-то пишет
- tmpfs/emptyDir получаются с разными владельцами
И Kubernetes начинает жрать собственную ногу.
Ну и чо делать?
- Вариант 1: отключить fsGroup, если он реально не нужен
securityContext:
runAsUser: 1001
runAsGroup: 1001
fsGroup: null
- Вариант 2: поставить fsGroup = runAsGroup
securityContext:
runAsUser: 1001
runAsGroup: 1001
fsGroup: 1001
- Вариант 3: включить legacy режим
fsGroupChangePolicy: "Always"
Предполагаю, что третий вариант это костыль, пишу как вариант, но, я сделал вариант 2.
Но это не точно.
Какие итоги:
- снова нырнул в дебаггинг. Интересно, но снова потрачено время
- отмазкам "мы ничо не меняли" как обычно верить нельзя. Гит всё покажет
- я вообще не знаю как такое допускает архитектура куба, почему не сделать разумную валидацию где-то на это, ну бред же. Мы самолично стреляем себе в коленные чашечки и потом удивляемся "а чо не так то?"
Please open Telegram to view this post
VIEW IN TELEGRAM
💊19👍6❤2
Никогда такого не было, но кладуфлёр опять упал.
В статуспейдж пишут, что недоступен только саппорт и портал.
На самом деле он весь упал и у меня упал весь мой пет проект.
Печаль.
- https://www.cloudflarestatus.com/
- https://www.reddit.com/r/CloudFlare/comments/1p09n2i/cloudflare_issuesdown/
В статуспейдж пишут, что недоступен только саппорт и портал.
На самом деле он весь упал и у меня упал весь мой пет проект.
Печаль.
- https://www.cloudflarestatus.com/
- https://www.reddit.com/r/CloudFlare/comments/1p09n2i/cloudflare_issuesdown/
😁11
Из новостей мира AI.
1) Скачал тут IDE от Google и поработал пару часов. (да-да, там внутри всё равно VSCode style).
Первое впечатление - очень круто, в том числе за счет бесплатности моделей.
Даже новейшая Gemini 3 в комплекте🔥 .
Типичные сложнейшие таски по топикам террагрант/хелм/авс/секьюрити попросил - все отвечает ровно так, как я и хочу и код на 99% рабочий. Сами таски/вопросы написаны давно, часто на них проверяю новые IDE/модели.
После Kiro, Claude Code и Cursor всё выглядит на высшем уровне.
Рекомендация 10/10. *
* Особенно если нет возможности платить за альтернативный софт.
https://antigravity.google
2) Невероятно впечатлён моделью Kimi K2 Thinking на Perplexity (у меня прошка).
Если нужно очень глубоко нырнуть в задачу - самый сок и топ.
Таски:
- ресерч архитектуры
- сравнение подходов разработки и флоу
- глубочайшее(чуть ли не побайтовое) погружение в сорс код, чтобы понять где бага
Рекомендация 10/10.
Из минусов - ну вооооооооообще не быстро отвечает.
Подходит для задач, где не нужна спешка.
На сегодня это моя любимая модель для длительного ресёрча и подумать.
https://www.perplexity.ai
1) Скачал тут IDE от Google и поработал пару часов. (да-да, там внутри всё равно VSCode style).
Первое впечатление - очень круто, в том числе за счет бесплатности моделей.
Даже новейшая Gemini 3 в комплекте
Типичные сложнейшие таски по топикам террагрант/хелм/авс/секьюрити попросил - все отвечает ровно так, как я и хочу и код на 99% рабочий. Сами таски/вопросы написаны давно, часто на них проверяю новые IDE/модели.
После Kiro, Claude Code и Cursor всё выглядит на высшем уровне.
Рекомендация 10/10. *
* Особенно если нет возможности платить за альтернативный софт.
https://antigravity.google
2) Невероятно впечатлён моделью Kimi K2 Thinking на Perplexity (у меня прошка).
Если нужно очень глубоко нырнуть в задачу - самый сок и топ.
Таски:
- ресерч архитектуры
- сравнение подходов разработки и флоу
- глубочайшее(чуть ли не побайтовое) погружение в сорс код, чтобы понять где бага
Рекомендация 10/10.
Из минусов - ну вооооооооообще не быстро отвечает.
Подходит для задач, где не нужна спешка.
На сегодня это моя любимая модель для длительного ресёрча и подумать.
https://www.perplexity.ai
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥20❤1👎1🤔1
Чего только не пере изобретают.
Осуждаю.
Уволюсь, если кто такое внедрит на работе.
(нет, кого я обманываю, буду есть ложкой, если заставят 😭 )
https://github.com/toon-format/toon
Осуждаю.
Уволюсь, если кто такое внедрит на работе.
https://github.com/toon-format/toon
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - toon-format/toon: 🎒 Token-Oriented Object Notation (TOON) – Compact, human-readable, schema-aware JSON for LLM prompts.…
🎒 Token-Oriented Object Notation (TOON) – Compact, human-readable, schema-aware JSON for LLM prompts. Spec, benchmarks, TypeScript SDK. - toon-format/toon
😁8💊4❤1
#aws #ecr #kubernetes
Представим себе, что у нас есть некий софт.
Он разрабатывается внутри компании и версионируется.
Результат сборки это готовый имадж в реджистри провайдера.
Затем мы этот софт предоставляете клиентам.
У софта есть версии и он разворачивается на одном регионе AWS.
Прям буквально клиенты тыкают в веб-интерфейсе, выбирают версию софта и регион(ы), в котором хотят видеть и дальше ваша, ну допустим назовём её "платформа" раскатывает софт нужной версии на нужных регионах.
Всё очень просто:
- собрали новый софт с новой версией
- готовый имадж положили в реджистри
- кастомер может задеплоить в доступный(е) регион(ы)
И всё бы хорошо, но как быть, когда у нас добавляются новые регионы?
Подняли новый регион, кастомер может задеплоить новую версию - всё работает.
Однако стоит выбрать старую версию продукта - поды падают с ошибкой пуллинга имаджа.
Старого имаджа в новом регионе ещё нет.
Варианты, которые сходу приходят в голову:
1)
Классная шутка, работает, но не покрывает кейс со "старыми имаджами", работает только для новых имаджей и всех последующих.
Да и она уже включена.
2)
Фича так же уже включена.
3) скрипт на питоне, которые будет синкать старые/имаджи при подключении нового региона
Только не в Слизерин! Лишь бы не скрипт, лишь бы не скрипт 🎩
4) не разрешать кастомеру деплоить на новые регионы старые версии
5) AWS event bridge + Lambda (не сработает, лямбда вроде не умеет работать с PTC)
6) схемы типа "
https://docs.aws.amazon.com/AmazonECR/latest/userguide/pull-through-cache-private.html (именно приват)
Pull-Through Cache для private-ECR-to-ECR-private работает (с 2023 года) с IAM аутентификацией.
Там есть пара ограничений, но для нашей задачи это подходит.
7) уход от парадигмы "один регион = имаджи только из регионального ECR", пуллить все из us-east-1
Смотрю
- как часто происходят релизы софта
- размер этих внутренних имаджа(ей)
- биллинг хранения и трафика ECR
- как часто будут разворачиваться новые регионы и как часто в новых регионах захотят старый софт
Дополнительно ресёрч:
- политики/доступы из других регионов в дефолт ECR из разных EKS
- kyverno policy (не будет ли перетирать путь)
- пулл секрет в новом регионе содержит правильный путь?
Минусы последнего решения понятны:
- цена: хранение/трафик (спойлер - увеличение на 13 баксов в месяц )
- latency на первый пулл
Мне нравятся оба варианта:
- Private Registry Upstream
- дефолт ECR для разных EKS
Дальше все факты, аргументы, расчёты, плюсы и минусы руководству.
Первый вариант это элегантность и оптимизация, второй это простота.
А какой уж вариант выберет руководство мы пока и не знаем. (знаем👍 )
Представим себе, что у нас есть некий софт.
Он разрабатывается внутри компании и версионируется.
Результат сборки это готовый имадж в реджистри провайдера.
Затем мы этот софт предоставляете клиентам.
У софта есть версии и он разворачивается на одном регионе AWS.
Прям буквально клиенты тыкают в веб-интерфейсе, выбирают версию софта и регион(ы), в котором хотят видеть и дальше ваша, ну допустим назовём её "платформа" раскатывает софт нужной версии на нужных регионах.
Всё очень просто:
- собрали новый софт с новой версией
- готовый имадж положили в реджистри
- кастомер может задеплоить в доступный(е) регион(ы)
И всё бы хорошо, но как быть, когда у нас добавляются новые регионы?
Подняли новый регион, кастомер может задеплоить новую версию - всё работает.
Однако стоит выбрать старую версию продукта - поды падают с ошибкой пуллинга имаджа.
Старого имаджа в новом регионе ещё нет.
Katastrofa!Варианты, которые сходу приходят в голову:
1)
ECR Replication - автоматическая репликация имаджей между регионами.Классная шутка, работает, но не покрывает кейс со "старыми имаджами", работает только для новых имаджей и всех последующих.
Да и она уже включена.
2)
Pull-Through Cache - великолепная штука, работает для всех внешних реджистри (ghcr.io, dockerhub, quay.io и тп). Фича так же уже включена.
3) скрипт на питоне, которые будет синкать старые/имаджи при подключении нового региона
4) не разрешать кастомеру деплоить на новые регионы старые версии
5) AWS event bridge + Lambda (не сработает, лямбда вроде не умеет работать с PTC)
6) схемы типа "
ECR-to-ECR PTC"https://docs.aws.amazon.com/AmazonECR/latest/userguide/pull-through-cache-private.html (именно приват)
Pull-Through Cache для private-ECR-to-ECR-private работает (с 2023 года) с IAM аутентификацией.
Там есть пара ограничений, но для нашей задачи это подходит.
7) уход от парадигмы "один регион = имаджи только из регионального ECR", пуллить все из us-east-1
Смотрю
- как часто происходят релизы софта
- размер этих внутренних имаджа(ей)
- биллинг хранения и трафика ECR
- как часто будут разворачиваться новые регионы и как часто в новых регионах захотят старый софт
Дополнительно ресёрч:
- политики/доступы из других регионов в дефолт ECR из разных EKS
- kyverno policy (не будет ли перетирать путь)
- пулл секрет в новом регионе содержит правильный путь?
Минусы последнего решения понятны:
- цена: хранение/трафик (спойлер -
- latency на первый пулл
Мне нравятся оба варианта:
- Private Registry Upstream
- дефолт ECR для разных EKS
Дальше все факты, аргументы, расчёты, плюсы и минусы руководству.
Первый вариант это элегантность и оптимизация, второй это простота.
А какой уж вариант выберет руководство мы пока и не знаем. (знаем
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤2