es
Feedback

¡No caigas en manos de tramposos! Telemetrio encuentra y marca estos canales 👉 Si quieres ver la etiqueta, suscríbete

Make. Build. Break. Reflect.

Make. Build. Break. Reflect.

Ir al canal en Telegram

Полезные советы, всратые истории, странные шутки и заметки на полях от @kruchkov_alexandr

Mostrar más
1 396
Suscriptores
Sin datos24 horas
+17 días
+2530 días
Archivo de publicaciones
Уникальный дизайн всех продуктов 2026 би лайк
Уникальный дизайн всех продуктов 2026 би лайк

У самурая нет цели, есть только patch. И ещё patch. И ещё один. И ещё..
У самурая нет цели, есть только patch. И ещё patch. И ещё один. И ещё..

#devops Обычный день инженера в 2026 - сраные CVE и факапы со всех сторон. https://www.youtube.com/watch?v=mr834Cs9ncs Бл, да
#devops Обычный день инженера в 2026 - сраные CVE и факапы со всех сторон. https://www.youtube.com/watch?v=mr834Cs9ncs Бл, да дайте просто поработать 😢

#всратость Удивительное - рядом. Упал GCP, и вместе с ним наш GitLab, CI/CD и вся AI-трансформация. ИИ умеет хуярить код за секунды, а поднять чужой регион почему-то не может. Как же так вышло? - https://status.cloud.google.com/ --- Эй, Револют, оживай, родненький, мы тоже страдаем от гугла.💞

Но на собесе тебя всё равно в тысячный раз спросят, что происходит, когда вводишь kubectl apply -f pod.yaml 😀

#tools #ai Открыл для себя Remotion (им сто лет в обед). https://github.com/remotion-dev/remotion Вкратце: это React для видео, можно рисовать любые анимированные штуки. План будущей миграции БД, диаграмма сети, как работают вебхуки, как работает TLS, как привлечь инвесторов, как у вас устроены кубер и облако. Любые ваши фантазии. Я, например, долго игрался с "как работают шедулер и кубелет", очень круто. На выходе получаешь гифку или видео. Шаблонов много. Claude Code тоже свободно с этим работает. Из минусов - на опытах и игрульках у меня безбожно сгорали токены. Что, собственно, и отражено в видео к посту 😁 Шуточно-злободневный промпт для этого видео: https://gist.github.com/kruchkov-alexandr/ceff15f054eb05c068c0422943b35ead

С появлением нейросетей многие профильные телеграм-чаты почти затихли. Редко кто что пишет. Ни глупых вопросов, ни ссор, ни х
С появлением нейросетей многие профильные телеграм-чаты почти затихли. Редко кто что пишет. Ни глупых вопросов, ни ссор, ни холиваров. А в чат по терраформу и вовсе наконец-то пришла любовь ❤️

#longread #aws #kubernetes #troubleshooting #devops Ах, как сладок вкус раннего субботнего просыпания во время моего дежурства! Суббота, 03:35 утра, алёрт на AWS RDS: DBLoadRelativeToNumVCPUs p99 > 1.5 three minutes in a row, DB overload. "Нагрузка на базу в субботу утром, когда клиентов почти нет и ничего не деплоят, это очень странно" - думаю я, всё ещё находясь под действием пятничных весёлых напитков, проснувшись на онколл алерт. Открыл AWS Performance Insights, почти вся нагрузка шла от одного запроса: SELECT * FROM job_batches WHERE id = ? LIMIT 1 FOR UPDATE Я был весьма раздосадован нагрузкой БД, ничего не смог понять сам по квери и мне пришлось дёрнуть коллег разработчиков из другого часового пояса, кто не спал, кто мне смог пояснить за запрос и сраные батчи ларавелки. Ниже цитаты коллег
В Laravel есть Bus::batch(): кидаешь в очередь пачку джобов и получаешь общий прогресс, коллбеки then/catch/finally и отмену всей пачки. Состояние пачки хранится в обычной таблице job_batches, одна строка на батч: total_jobs, pending_jobs, failed_jobs, failed_job_ids (JSON-ом в той же строке), cancelled_at, finished_at.
Когда любой джоб из батча завершается, успешно или с ошибкой, фреймворк обновляет счётчики примерно так:
BEGIN;
SELECT * FROM job_batches WHERE id = ? FOR UPDATE;
-- in PHP: pending_jobs - 1, append to failed_job_ids, etc.
UPDATE job_batches SET pending_jobs = ..., failed_jobs = ..., failed_job_ids = ... WHERE id = ?;
COMMIT;
Это честный пессимистичный лок на строку. Пока транзакция одного воркера не закоммитилась, остальные воркеры, у которых закончился джоб из этого же батча, стоят в очереди за той же строкой.
Пока в батче десять джобов и работает пара воркеров, всё нормально. Если в батче тысячи мелких джобов и их молотят десятки воркеров одновременно, все они выстраиваются в очередь к одной строке. Сам запрос летает, это выборка по первичному ключу. В Performance Insights ты видишь не медленный запрос, а время ожидания лока.
Запрос понятен, неясно, откуда в субботу ночью столько батчей, сука. Нашёл быстро: за два дня до этого смержили новый недельный кронджоб. По субботам в 02:00 UTC он проходит по всем клиентам, у которых подключена интеграция с внешней системой (их 480), и для каждого запускает очистку контактов, удалённых во внешней системе. Режим --dry-run, ничего не удаляется, только собирается статистика. Каждый клиент получает Bus::batch из джобов по 100 контактов в low-priority очереди. Один прогон на клиента раз в неделю. Звучит безобидно. Дааа, конечно. В job_batches было: - с 02:00 до 04:48 каждый клиент получил примерно по 30 батчей - всего около 7 тысяч батчей - у одного клиента 30 прогонов по 3200 джобов, это около 96 тысяч джобов - на момент разбора около 1500 батчей ещё открыты, в очереди около 280 тысяч джобов Недельный кронджоб отработал не один раз, а примерно 30 раз за ночь 🤡 Пока я просыпался, разбираясь с этим, я накидал стройную гипотезу: команда возвращает FAILURE, если хотя бы один клиент не встал в очередь, кубер считает это падением и перезапускает, каждый перезапуск заново ставит в очередь всех. Звучало вроде логично. . .. ... Да нет, хуйня какая-то. Пью второй кофе и начинаю проверять. Сначала что реально задеплоено, а не что написано в values:
backoffLimit: 6 (default)
restartPolicy: OnFailure
activeDeadlineSeconds: 1500
resources: {}
restartPolicy и backoffLimit в чарте не заданы вообще, поэтому дефолты. К ним вернусь. Чем заканчивались прогоны:
kube_pod_container_status_last_terminated_reason -> Error
kube_pod_container_status_last_terminated_exitcode -> 255
255. Так не выглядит штатный return FAILURE (это код 1), так выглядит процесс, который умер сам. В PHP это обычно fatal error. Проверяю memory_limit в поде:
kubectl -n production exec deploy/<app> -- php -r 'echo ini_get("memory_limit");'
256M
Смотрю логи кронджоба: на каком клиенте процесс умирает каждый раз. Каждый раз примерно на середине списка, после ~230-го клиента. Следующий по списку клиент выглядит так: contacts=~610000 Больше полмиллиона контактов😱, остальные клиенты в среднем сотни или тысячи. Код команды для каждого клиента делает так: $ids = Contact::where(...)->pluck('id'); Одним запросом забирает все id контактов клиента, потом map, sort, values, array_chunk по 100, и каждая операция создаёт ещё одну копию массива. Воспроизвожу в свежем процессе: беру id контактов для этого клиента (прям в поде, а кто что мне сделает).
Allowed memory size of 268435456 bytes exhausted ... Connection.php:428
command terminated with exit code 255
Вот оно. Заодно проверил, что это не утечка памяти. По ходу цикла память ровная, 60 > 92 MB. Единственный скачок был на клиенте со 160 тысячами контактов. Мемори лик нет, есть один очень большой клиент, и кому-то стоит знать, сколько весит массив из полумиллиона элементов в PHP. Не 4 мегабайта, как кажется по привычке из си, а намного больше: каждая строка из PDO превращается в отдельный объект, сверху пара копий, и.. ..и 256 мегабайт кончаются. Итак, гипотеза про FAILURE отпала. Триггер другой: OOM на одном клиенте. Всё, что я думал про цикл перезапусков и локи, оказалось верным, но если бы чинили по этой версии, то есть убрали бы FAILURE из кода, кронджоб в следующую субботу упал бы точно так же 😂😂😂 Теперь откуда ровно 30 прогонов. restartPolicy: OnFailure значит, что упавший контейнер перезапускается внутри того же пода. Каждый перезапуск выполняет команду с нуля: клиенты 1-230 снова встают в очередь, на 230-м OOM, всё сначала. Ивенты:
02:10:45  BackOff           Back-off restarting failed container
02:25:01  DeadlineExceeded  Pod was active on the node longer than the specified deadline
02:25:41  SuccessfulCreate  Created pod: ...-h7sr2
Каждые 25 минут под упирается в activeDeadlineSeconds: 1500, Job его убивает и создаёт новый, и всё повторяется. Так прошло 7 подов, а в 04:48 пришёл BackoffLimitExceeded, и Job наконец сдался. В логах первый клиент из списка встречается около 30 раз, примерно раз в 5,5 минуты. 30 × (первые ~230 клиентов) × тысячи джобов по 100 контактов, и всё в одну очередь! Каждый джоб при завершении делает SELECT ... FOR UPDATE на строку своего батча. На каждом батче вереница воркеров ждёт лок. Отсюда и картинка в базе: DBLoadRelativeToNumVCPUs (15m avg / max)
01:45  0.04 / 0.19
02:00  0.38 / 2.50   << кронджоб стартует
04:45  0.91 / 2.75
06:15  0.06 / 0.41   << очередь прочищена
Отдельно мне понравилось, что режим dry-run, который сам ничего не трогает: - около 30 лишних полных проходов по API внешней системы для каждого подключённого клиента (их провайдер наверняка тоже порадовался😁😁😁) - сотни тысяч джобов в очереди - лок-контеншен на базе с 02:00 до 06:00 Dry-run для данных, но не для БД инфраструктуры.😁 Итог: Внимательный читатель спросит "а что же ты чинил, Алекс?" и будет прав, ведь я ничего об этом не написал. Ведь я ничего и не чинил.😊 На тот момент принял решение ничего не трогать, само пройдет, так и вышло. Причины простые: - кронджоб к тому времени уже сам умер (BackoffLimitExceeded ), новых джобов не появлялось, значит очередь могла только уменьшаться - это dry-run, данные никто не портил, ну локи в таблицу, ну и чо - всё шло в low-priority, суббота утро, пользователи почти ничего не замечали Спустя время алерт потух, проблема ушла сама. Что починили в будни (до следующей субботы, иначе всё повторилось 😀): - какую то залупу в коде ларавелки, я даже не смотрел в МР - в кронджобе поставили restartPolicy: Never и backoffLimit: 0. Если команда снова упадёт, она упадёт один раз и громко, без 30 тихих повторов Мораль. - дефолты Job в кубере (OnFailure плюс backoffLimit: 6) превращают любой неидемпотентный кронджоб из "упал" в "упал и сделал всё ещё сто раз, сука". Если команда ставит работу в очередь, а не выполняет её сама, ретраи в Job почти всегда ебаное зло - Bus::batch с тысячами мелких джобов означает одну горячую строку в таблице и лок на каждый завершённый джоб. Батч это не бесплатный счётчик прогресса. - иногда надо быть Улиточкой-дежурным-работником месяца

#aws #пятница 2016 год. AWS re:Invent. Под музыку прямо на сцену въезжает фура. Это AWS Snowmobile: контейнер на 100 петабайт
#aws #пятница 2016 год. AWS re:Invent. Под музыку прямо на сцену въезжает фура. Это AWS Snowmobile: контейнер на 100 петабайт с охраной и GPS. Зал аплодирует 😲😮😮. Никто не понимает, зачем это нужно, но все снимают на телефон. 2024 год. Snowmobile тихо убирают из списка сервисов, без пресс-релиза и без прощальной вечеринки. Дальше о нём помнят только авторы вопросов к экзамену AWS и несчастные экзаменующиеся. 2032 год. Дата-центры выходят из строя чаще, чем падают деплои по пятницам. Единственный бэкап в соседнем регионе удалил ИИ-агент. Его попросили почистить неиспользуемые ресурсы, и бэкап выглядел весьма таким заманчиво неиспользуемым. Кто-то в Сиэтле вспоминает старую мудрость: never underestimate the bandwidth of a truck full of disks 💪. Грузовик находят на задворках склада в Неваде. Обшивают железом и шипами, как в "Безумном Максе", и запускают программу "Snow-бэкап региона". В 2016-м 100 петабайт казались бесконечностью. Теперь же в них влезает целый регион, если не брать логи и стактрейсы джавы. С современными же дисками влезает даже node_modules. Он несётся по пустому шоссе из Техаса в Миннесоту. Рулит ИИ-агент со своим роем сабагентов. Каждые 50 миль он спрашивает: - "Продолжить? (y/n)". Охранник в кабине жмёт Y 🤪. За грузовиком летят дроны. Чьи - никто уже не помнит. Дронов сбивают беспилотные Waymo, впервые в истории никому не перегородив дорогу. Роботы Unitree забрасывают остальных сетками. Кто согласовал эту поддержку, неизвестно. Кажется, просто чёт так навайбкодилось 🤷. Ночью помятый и в подпалинах грузовик с гирляндой на кабине въезжает в резервный дата-центр. Играет "Праздник к нам приходит" из рекламы Кока-Колы. Люди обнимаются. Кто-то плачет. Восстановление из бэкапа прошло успешно. Впервые в истории его кто-то реально проверил. Вернулся даже Netflix. Первым делом он предложил продолжить просмотр с 2031 года. В слаке инженер пишет: - "Ашалеть, не думал, что вопрос про Snowmobile с экзамена мне когда-нибудь пригодится 😮" На ближайшем re:Invent под музыку The Chemical Brothers - Go прямо на сцену въезжает фура. С шипами. На борту надпись "Snowmobile AI. Now with AI agents. AI!". Зал аплодирует 😲😮😮. Никто не понимает, зачем там агенты, но все снимают на телефон.

#troubleshooting #devops #одинденьизжизни Однажды пришёл на работу, я oncall, вижу алерт - поды рестартятся. Смотрю, что там:
kubectl get pods -n <namespace> | grep redis
redis-ha-server-1    1/4     Running   7    10m
Ага, один под постоянно рестартится. 7 раз за 10 минут. Смотрю логи:
kubectl logs -p redis-ha-server-1 -c redis -n <namespace>

1:S * MASTER <-> REPLICA sync started
1:S * Full resync from master
1:S * MASTER <-> REPLICA sync: receiving streamed RDB from master
1:signal-handler Received SIGTERM scheduling shutdown...
1:S * User requested shutdown...
Реплика начинает Full Resync, а через 27 секунд получает SIGTERM и умирает. А синхронизация большой базы занимает минуты. Смотрю ивенты:
kubectl get events -n <namespace> --field-selector involvedObject.name=redis-ha-server-1 --sort-by='.lastTimestamp'

Normal    Killing     pod/redis-ha-server-1   Container redis failed startup probe, will be restarted
Warning   Unhealthy   pod/redis-ha-server-1   Startup probe failed: role=slave; repl=sync
Ага, контейнер убивает стартап проб. Проверяю настройки:
kubectl describe pod redis-ha-server-1 -n <namespace> | grep -A1 Startup:

Startup: exec [sh -c /health/redis_readiness.sh] delay=5s timeout=15s period=10s #success=1 #failure=3

failureThreshold: 3, periodSeconds: 10, initialDelaySeconds: 5.
Первая проверка на 5-й секунде, дальше каждые 10: 5, 15, 25. Третья неудача подряд, и контейнер убивают. Плюс пара секунд на сам скрипт, отсюда и мои 27. А база весит 550 мегабайт, и Full Resync идёт дольше. Пока реплика синхронизируется, health check возвращает ошибку. Через три неудачи подряд startup probe считает контейнер мёртвым, и кублет его перезапускает. Синк начинается заново, и так по кругу. Проблема вроде бы понятна. Нужно увеличить failureThreshold. Правлю StatefulSet: kubectl edit statefulset redis-ha-server -n <namespace> Меняю failureThreshold у контейнера redis с 3 на 120. Сохраняю. Удаляю под: kubectl delete pod redis-ha-server-1 -n <namespace> Жду, смотрю логи. Та же херня, рестарты продолжаются. Сука. Проверяю, что применилось в поде:
kubectl get pod redis-ha-server-1 -n <namespace>
  -o jsonpath='{.spec.containers[?(@.name=="redis")].startupProbe.failureThreshold}'
3
Бл, под создался со старым значением. А в StatefulSet что?
kubectl get statefulset redis-ha-server -n <namespace>
  -o jsonpath='{.spec.template.spec.containers[?(@.name=="redis")].startupProbe.failureThreshold}'
120
В StatefulSet уже 120, а в поде 3. Что за ебанная магия? Проверяю, кто управляет StatefulSet:
kubectl get statefulset redis-ha-server -n <namespace> -o yaml | head -30

metadata:
  annotations:
    meta.helm.sh/release-name: <release>
    meta.helm.sh/release-namespace: <namespace>
  labels:
    app.kubernetes.io/managed-by: Helm
Helm. Но сам по себе Helm ничего не откатывает: reconcile у него нет, ресурсы он трогает только на helm upgrade. Кто именно подсунул поду старый шаблон, я так и не выяснил. Если поймаете такое, смотрите managedFields: там видно, кто и когда писал в объект. kubectl get statefulset redis-ha-server -n <namespace> --show-managed-fields -o yaml Ладно. Шаблон в StatefulSet правильный, значит, надо заставить контроллер пересоздать поды из него. Смотрю стратегию обновления:
kubectl get statefulset redis-ha-server -n <namespace> -o jsonpath='{.spec.updateStrategy}'
{"type":"OnDelete"}
При OnDelete контроллер обновляет под, только когда его удаляют. Я его и удалил, а он всё равно поднялся со старым шаблоном. Почему, честно, не знаю. Переключаю на RollingUpdate, чтобы контроллер перекатил всё сам:
kubectl patch statefulset redis-ha-server -n <namespace> --type=json -p='[
  {"op": "replace", "path": "/spec/updateStrategy/type", "value": "RollingUpdate"}
]'
Проверяю новый под:
kubectl get pod redis-ha-server-1 -n <namespace>
  -o jsonpath='{.spec.containers[?(@.name=="redis")].startupProbe.failureThreshold}'
120
Отлично, теперь 120. Смотрю логи: Full Resync завершился успешно, всё синхронизировалось. Но дальше вижу, что сразу после успешной синхронизации соединение теряется. Смотрю логи мастера:
kubectl logs redis-ha-server-0 -c redis -n <namespace> --tail=50

1:M * Connection with replica lost.
1:M # closed for overcoming of output buffer limits
Ага, мастер рвёт соединение, потому что переполнился output buffer. Проверяю лимиты:
kubectl exec redis-ha-server-0 -c redis -n <namespace> --
  sh -c 'redis-cli -a $AUTH CONFIG GET client-output-buffer-limit'

slave 268435456 67108864 60
Hard limit 256 MB, soft limit 64 MB на 60 секунд. Буфер на мастере дорос до 152 MB. До hard limit не дотянул, но soft limit (64 MB) держался превышенным дольше 60 секунд. Этого достаточно, чтобы мастер убил соединение. Пока мастер стримит RDB, все новые записи копятся в этом буфере. Большая база и активная запись дают ровно такую картину. Увеличиваю лимиты:
kubectl exec redis-ha-server-0 -c redis -n <namespace> --
  sh -c 'redis-cli -a $AUTH CONFIG SET client-output-buffer-limit "slave 1073741824 536870912 60"'
Теперь hard limit 1 GB, soft limit 512 MB. CONFIG SET применяется сразу, без рестарта. Важен он именно на мастере, но я прописал его на всех нодах: sentinel может переключить мастера в любой момент. Заодно поднимаю repl-backlog-size до 512 MB. Full sync это не лечит: backlog нужен, чтобы после короткого разрыва реплика догналась частичным PSYNC, а не начинала полный синк заново. Но и памяти он съедает столько же, так что проверь лимиты, если не хочешь поймать OOMKill. Перезапускаю реплику, чтобы она заново прошла full sync уже с новыми лимитами: kubectl delete pod redis-ha-server-1 -n <namespace> Смотрю логи: теперь всё ок. Соединение не теряется, реплика стабильна, никто не пиздит в канале алёртов. Что сделать, чтобы всё это не слетело Всё, что я накрутил руками, временное: - kubectl edit, kubectl patch и смена updateStrategy слетят на следующем helm upgrade или sync - CONFIG SET живёт до рестарта пода, потом конфиг снова берётся из ConfigMap По-нормальному это должно жить в values чарта, в Git:
redis-ha:
  redis:
    startupProbe:
      failureThreshold: 120
    config:
      client-output-buffer-limit: "slave 1073741824 536870912 60"
      repl-backlog-size: "512mb"
Итог. - дефолты редиса (или чарта редиса?) не рассчитаны на 550 MB кеша (на тот момент было около 25000+ аппилкейшнов) - Helm не делает reconcile, но ручные правки в кластере всё равно не живут, всё постоянное должно лежать в values - если под пересоздаётся со старым спеком, смотрите managedFields; RollingUpdate может помочь, но мастер тоже перекатится, будет failover - CONFIG SET живёт до рестарта 🫠 Довольный, на дейли рассказываю, как героически победил редис. Лид дослушивает, кивает и спрашивает: - А нахера ты с этим возился? Это ж редис арго, там только кеш. Дропнул бы базу, и всё. - ... Читаю интернеты, так и есть. Всё лечилось одной командой на мастере:
kubectl exec redis-ha-server-0 -c redis -n <namespace> --
  sh -c 'redis-cli -a $AUTH FLUSHALL'
Реплика синкает пустую базу за секунды, арго сам заново греет кеш. Справедливости ради, кеш снова дорастёт до 550 MB, так что values с лимитами всё равно пригодятся. Но это можно было сделать спокойно, а не под алертами! Мораль: прежде чем героически чинить, спроси себя, что это вообще за данные и жалко ли их.🤡🤡🤡 Сгорая от стыда, пишу эту заметку и скрываюсь в тумане 🚶‍♀

#kubernetes #devops Kubernetes не решает проблемы хуёвого софта. Если приложение течёт по памяти, не умеет в пробы, не отдаёт
#kubernetes #devops Kubernetes не решает проблемы хуёвого софта. Если приложение течёт по памяти, не умеет в пробы, не отдаёт метрик, не умеет в параллельность, падает от каждого чиха и хранит стейт в локальной папке, то в кубере оно будет делать то же самое, только теперь с регулярным рестартом и алертами в три ночи.

Последние пару лет, и на этой работе, и на прошлой, каждая встреча у меня начинается одинаково: я либо игнорирую, либо радост
Последние пару лет, и на этой работе, и на прошлой, каждая встреча у меня начинается одинаково: я либо игнорирую, либо радостно жамкаю "отклонить" всем ноттейкерам в лобби. Позиция простая: либо приходите сами, либо сами нажимайте "разрешить" своим ботам и идите по своим делам. Всю жизнь мечтал работать швейцаром у ботов в Zoom/Teams/Google Meet 🙂 На самом деле бесит пздц.

Интересно, а что там внутри? Типа полетели алёрты в слак из датадог/ньюрелик/алертменеджер. Потом включается Claude on-call.
Интересно, а что там внутри? Типа полетели алёрты в слак из датадог/ньюрелик/алертменеджер. Потом включается Claude on-call. Caramelizing... Flibbertigibbeting... ... Cogitating ... Contemplating... Coalescing... И потом типа он такой выдаёт Found root cause... It was ... Release!... Opening a revert PR... С вас 500k токенов, лол. Так? Ну я к тому, что когда агент работает от моего ПК, у меня есть скиллы, инструкции где что брать, настроен конфиг, есть MCP, есть VPN, ежедневно прохожу авторизацию для SSO, раз в пару недель для google аккаунта - и от меня всё работает так, как я хочу при траблшутинге по алертам. Не очень хорошо, но терпимо работает агент в автономном режиме с моего пк, лишь ровно до тех пор, пока не слетят авторизации и VPN или пока он не начнёт нести херню в слаке коллегам, раздражая их (ему пофиг на запреты не писать в слак свои простыни текста моим коллегам, сука). Только проблема далеко не всегда в релизе, а в куче других факторов. Для анализа нужны метрики, логи, ивенты и так далее. Всё это под SSO авторизацией, в закрытом контуре. А если всё-таки проблема в релизе - простите, роллбек кривого релиза сделает любой инженер, который умеет считать дважды два и у него есть хотя бы один глаз. Зачем тут агент? А как это работает с клод онколлл? Как он сможет траблшутить чего-либо, если у него физического доступа нет? Предоставить доступ? Задеплоить сабагента в кубер и дать ему IRSA/pod identity на нужные ресурсы? Сделать мир прекраснее и открытее для всех агентов? Короче маркетинговая коричневая магия какая-то. Решил посмотреть документацию. Оказалось, что живёт он не в наших кластерах, а в песочнице Антропика, так что IRSA мимо. Креды берёт из сервисных учёток, которые мне надо завести и отдать им, и ходит только по HTTPS. VPN, SSH, SMM и прямой доступ к базам ему недоступны, тоже мимо.😁 Если весь обсервабилити в SaaS (Datadog, New Relic) - ок, выдал read-only апи ключ и поехали. А если Prometheus/VictoriaMetrics, логи и кубер живут за VPN - либо открывать ему всё наружу🤣, либо получаешь тот самый "It was Release… Opening a revert PR…". Ну в общем пока поживём на локальных/кубер агентах (типа https://github.com/kagent-dev/kagent или http://github.com/mezmo/aura, тысячи их), без клод онколла.

#aws #AWScommunity #eks #kubernetes Что выбрать при создании нового AWS EKS кластера в 2026 году: стандартный режим или Auto
#aws #AWScommunity #eks #kubernetes Что выбрать при создании нового AWS EKS кластера в 2026 году: стандартный режим или Auto Mode? Выбирайте стандартный режим (без Auto Mode), если вы: - хотите разобраться в облачном кубере Амазона и изучить десяток компонентов (Karpenter, VPC CNI, CoreDNS, kube-proxy, EBS CSI, Load Balancer Controller…), которые вам теперь придётся обслуживать примерно всегда - любите тюнить кубер или компоненты минимум раз в квартал - боитесь, что вас заменят ИИ, и хотите оставить себе крепкий якорь, который помешает вас уволить - любите читать матрицы совместимости и GitHub issues по каждому компоненту - гоняете большой флот на спотах или сейвинг план и умеете считать деньги - без своего AMI, софта прямо на ноде или собственного CNI жить не можете - любите зайти на ноду по SSM и посмотреть чо там - живёте на Windows- или Ubuntu нодах 😬 Выбирайте Auto Mode, если: - у вас нет DevOps/Platform команды, которая бы поддерживала кубер, потому что вы стартап - вы руководитель, всех уволили, заменив на ИИ, и теперь, как Дункан Маклауд, остались один и не знаете, что делать с вашим кубером ⚔️ - хотите тратить время на код и манифесты, а не на поддержку инфраструктуры - готовы потерять последние крохи экспертизы по эксплуатации нод и аддонов для куба, ведь уже через год на автомод вы не сможете объяснить на собесе, как у вас апгрейдится CNI и что это такое - у вас нормальная зрелая компания, которая ценит время инженеров дороже 12% к счёту за EC2 и не страдает ИИстерией Лично я бы всегда по умолчанию брал автомод.

#пятница Ждём, чо. А вообще да, заебали эти охринительно полезные новости с невероятными достижениями.
#пятница Ждём, чо. А вообще да, заебали эти охринительно полезные новости с невероятными достижениями.

#kubernetes - https://laravel-news.com/laravel-health-kubernetes-prometheus Жаль, что такого пакета не было, когда я работал
#kubernetes - https://laravel-news.com/laravel-health-kubernetes-prometheus Жаль, что такого пакета не было, когда я работал с Laravel. Раньше приходилось городить костыли: самописные эндпоинты, несколько разрозненных пакетов, ручная настройка liveness/readiness-проб и прометиус-метрик. Был spatie/laravel-health с хорошим набором проверок, но отдельных эндпоинтов под кубер и прометиус из коробки в нём (раньше) не было. Теперь есть новый пакет (по ссылке от cboxdk): - много проверок: БД, кэш, очереди, редис, storage, диск, расписание (через heartbeat шедулера), окружение, CPU и память - отдельные эндпоинты под кубер: /health (liveness), /health/ready (readiness), /health/startup (startup) - встроенные прометиус-метрики на /health/metrics: статус и длительность каждой проверки плюс системные метрики - container-aware метрики из cgroups v1/v2: лимиты и потребление памяти, CPU quota, CPU throttling и OOM kills Пакет совсем молодой, звёзд с неба не хватает на гитхабе пока мало, так что в прод я бы тащил его после внимательного взгляда на код. И сначала стоит проверить, что именно попадает в liveness: если туда входит проверка БД, то при падении базы кублет начнёт перезапускать все поды разом😁. Однако авторы, если не ошибаюсь, это https://cbox.dk/, у них точно есть опыт с PHP/Laravel и я уверен, что пакет будет весьма успешным. В целом хорошая новость для владельцев Laravel стека, кто в кубере живёт. Требования: - PHP 8.3+ - Laravel 11-13

Но стоит взять задачу из смежной области, где общее понимание есть, а глубокой экспертизы нет, – и всё меняется до неузнаваем
Но стоит взять задачу из смежной области, где общее понимание есть, а глубокой экспертизы нет, – и всё меняется до неузнаваемости, с ИИ из помощника превращается в пожирателя времени.
Действительно, а почему так выходит.😕 Непонятно, ведь ИИ всех заменит, а образование и экспертиза через время и опыт больше не нужны, да. https://lnkd.in/p/d7JDGDdQ

В удивительнейшее время живём. - https://typesafe.ai/blog/introducing-system-one-models-and-jev TypeSafe анонсировали Jev, свою первую "System One" модель - быстрые типизированные решения вместо генерации текста. - https://github.com/mizorewww/laya-mlx (на минуточку это уже опенсорс!) а это похожая по духу модель, но от другой компании (Convai Innovations), уже в опенсорсе и с портом под Apple Silicon (eto ya со своим макбуком). И она меньше гигабайта! То есть Jev сам по себе проприетарный и закрытый, но концепция уже доступна в опенсорсе - я погонял именно Laya. Поигрался - весьма интересно. Пример использования (первым пришло в голову для тестов): - установить этот опенсорс decision-модель pip install laya-mlx - залогиниться в hugging face - запилить скрипт laya_triage.py
"""Local Laya (MLX) triage of a SQL query; escalate to a Hugging Face LLM only if needed.

Usage:
    HF_TOKEN=hf_xxx python ~/laya_triage.py            # uses the built-in sample query
    HF_TOKEN=hf_xxx python ~/laya_triage.py query.sql  # or a query from a file
Optional env: HF_MODEL (default below), LAYA_THRESHOLD (default 0.5).
"""

import os
import sys

import laya_mlx
from huggingface_hub import InferenceClient

HF_MODEL = os.environ.get("HF_MODEL", "Qwen/Qwen2.5-Coder-32B-Instruct")
THRESHOLD = float(os.environ.get("LAYA_THRESHOLD", "0.5"))

SAMPLE_SQL = """
SELECT u.id, u.name, COUNT(o.id)
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at >= '2026-01-01'
GROUP BY u.id, u.name;
"""


QUESTIONS = {
    "needs_optimization": {
        "type": "noul",
        "instructions": "Does this SQL query contain potential performance bottlenecks "
        "(full table scans, inefficient joins, missing filters on large tables)?",
    },
    "issue": {
        "type": "choice",
        "instructions": "What is the most likely performance problem in this SQL query?",
        "criteria": {
            "missing_index": "The query filters or joins on columns that likely need an index",
            "heavy_aggregation": "The query uses GROUP BY / COUNT over very large tables",
            "fine": "The query looks optimal",
        },
    },
}


def triage(agent, sql):
    answers = agent.predict(sql, QUESTIONS)["answers"]
    p_slow = answers["needs_optimization"]["noul"]
    issue = answers["issue"]["choice"]
    print(f"[laya] needs_optimization p={p_slow:.2f}")
    print(f"[laya] issue={issue} probs={answers['issue']['probabilities']}")
    return p_slow >= THRESHOLD and issue != "fine", issue


def optimize(sql, issue):
    token = os.environ.get("HF_TOKEN")
    if not token:
        sys.exit("HF_TOKEN is not set; cannot escalate to Hugging Face")
    client = InferenceClient(api_key=token)
    resp = client.chat_completion(
        model=HF_MODEL,
        messages=[
            {"role": "system", "content": "You are a senior database performance engineer."},
            {
                "role": "user",
                "content": f"A classifier flagged this query as likely '{issue}'. "
                "Explain the bottleneck briefly, suggest indexes, and give an optimized "
                f"query if one exists.\n\n```sql\n{sql.strip()}\n```",
            },
        ],
        max_tokens=800,
    )
    return resp.choices[0].message.content


def main():
    sql = open(sys.argv[1]).read() if len(sys.argv) > 1 else SAMPLE_SQL
    agent = laya_mlx.load()  # convaiinnovations/laya, downloaded once to the HF cache
    needs_llm, issue = triage(agent, sql)
    if not needs_llm:
        print("[laya] query looks fine, no LLM call")
        return
    print(f"[hf] escalating to {HF_MODEL} ...\n")
    print(optimize(sql, issue))


if __name__ == "__main__":
    main()
- запускаем HF_TOKEN=hf_Tgar5555555jlOS python ~/laya_triage.py - и практически мгновенно получаем результат
[laya] needs_optimization p=0.19
[laya] issue=heavy_aggregation probs={'missing_index': 0.0781, 'heavy_aggregation': 0.6264, 'fine': 0.2955}
[laya] query looks fine, no LLM call
Магия магией. Важно: это триаж локальной моделью (Laya), а не замена ревью!!! Ни она, ни HF-модель при эскалации не трогают базу, они только советуют. Финальное решение (индекс добавлять или нет) всё равно за человеком!