ftops.space
84 subscribers
555 photos
98 videos
33 files
278 links
ftops.space
Сервера на linux, FreeBSD, сети на микротик и сиськах.
Download Telegram
Инфраструктура как код — это не про скрипты, а про воспроизводимость

Когда продакшн падает в субботу в три часа ночи, тебе не нужно вспоминать, какую кнопку нажал коллега полгода назад. Тебе нужен код, который из пустого железа поднимает всё заново: разметка дисков, сеть, ключи, сервисы, роуты. Ansible и Terraform здесь не модные тулзы, а единственный способ не быть единственной точкой отказа в собственной команде.

Неизменяемая система (immutable Linux) идёт дальше. Образ собирается один раз, запекается, проверяется в CI и выкатывается на ноды целиком. Если что-то пошло не так — не чинишь руками, а откатываешься на предыдущий проверенный образ. Патчинг из ритуала с шаманскими бубнами превращается в версионирование артефакта.

Отдельная тема — защита критичных конфигов на проде. chattr +i на fstab, sshd_config и ключах. Это не паранойя, это защита от самого себя в три часа ночи, когда рука тянется быстро поправить и перезапустить. Иммутабельность превращает случайное изменение в ошибку, которую невозможно сделать молча.

Воспроизводимость аварии — высший пилотаж. Инцидент переводится в сценарий: та же команда, тот же конфиг, то же состояние. Пока авария не воспроизводится по кнопке — она не закрыта, а просто притихла.

#ftops #devops #linux #freebsd #sre #инфраструктура
Автоматический бэкап etcd в S3 создает у инженеров опасное чувство защищенности. В K3s встроенный механизм etcd-snapshot отлично отправляет снимки состояния в S3-хранилище, но процесс катастрофического восстановления (Disaster Recovery) на bare-metal превращается в хаос, если пытаться применить снепшот на работающем кластере без подготовки нод контрол-плейна. Главная ошибка при сбое — запуск процедуры восстановления на одном из мастеров при живых остальных. В этот момент etcd упирается в рассинхронизацию Cluster ID и отказ кворума. Нативный регламент восстановления требует жесткой последовательности действий: 1. Полная остановка службы k3s на всех нодах управления. 2. Физическая очистка каталога /var/lib/rancher/k3s/server/db/ на всех ведомых нодах, чтобы вычистить старое состояние etcd. 3. Выполнение команды k3s server --cluster-reset с указанием параметров S3 и имени снимка строго на одном первичном мастере. При выполнении cluster-reset K3s переинициализирует etcd в режим одиночного ...
Автоматический бэкап etcd в S3 создает у инженеров опасное чувство защищенности. В K3s встроенный механизм etcd-snapshot отлично отправляет снимки состояния в S3-хранилище, но процесс катастрофического восстановления (Disaster Recovery) на bare-metal превращается в хаос, если пытаться применить снепшот на работающем кластере без подготовки нод контрол-плейна. Главная ошибка при сбое — запуск процедуры восстановления на одном из мастеров при живых остальных. В этот момент etcd упирается в рассинхронизацию Cluster ID и отказ кворума. Нативный регламент восстановления требует жесткой последовательности действий: 1. Полная остановка службы k3s на всех нодах управления. 2. Физическая очистка каталога /var/lib/rancher/k3s/server/db/ на всех ведомых нодах, чтобы вычистить старое состояние etcd. 3. Выполнение команды k3s server --cluster-reset с указанием параметров S3 и имени снимка строго на одном первичном мастере. При выполнении cluster-reset K3s переинициализирует etcd в режим одиночного узла и генерирует новый идентификатор кластера. Однако восстановленная из S3 база данных все еще содержит старые записи о топологии и IP-адресах прошлых участников. До запуска остальных мастеров необходимо удалить неактивные ноды через kubectl и убедиться в корректности состояния API-сервера. Только после того как первичный мастер перешел в здоровый статус, ведомые узлы запускаются для чистой повторной инициализации etcd-репликации. Настоящая отказоустойчивость проверяется не наличием архива в облаке, а автоматизированным скриптом сброса локальных состояний нод. Технические разборы архитектуры K3s и сетевого стека ядра публикуются на https://ftops.space.
Автоматическая выгрузка S3-снепшотов etcd в K3s создает ложное чувство защищенности. Команда аварийного восстановления с флагами cluster-reset и cluster-reset-restore-path инициализирует новый etcd cluster ID и пересоздает ансамбль с единственным ведущим узлом. Если попытаться выкатить снепшот на одну из нод без предварительного отключения и очистки остальных участников control plane, система уходит в невосстановимый сплит-брейн. Главная техническая ловушка заключается в расхождении состояния Raft-журнала и сетевого стека. Сохранившиеся ноды master продолжают считать старый cluster ID валидным и отвергают TLS-handshake от восстановленного лидера. Параллельно с этим возникает рассинхрон WireGuard mesh: таблицы адресации и туннельные интерфейсы, восстановленные из S3-снепшота, содержат устаревшие привязки pod CIDR. В результате etcd рапортует об успехе, пока межсерверный трафик молча уходит в blackhole ядра. Регламент аварийного поднятия кластера на bare-metal требует жесткой последовате...
Автоматическая выгрузка S3-снепшотов etcd в K3s создает ложное чувство защищенности. Команда аварийного восстановления с флагами cluster-reset и cluster-reset-restore-path инициализирует новый etcd cluster ID и пересоздает ансамбль с единственным ведущим узлом. Если попытаться выкатить снепшот на одну из нод без предварительного отключения и очистки остальных участников control plane, система уходит в невосстановимый сплит-брейн. Главная техническая ловушка заключается в расхождении состояния Raft-журнала и сетевого стека. Сохранившиеся ноды master продолжают считать старый cluster ID валидным и отвергают TLS-handshake от восстановленного лидера. Параллельно с этим возникает рассинхрон WireGuard mesh: таблицы адресации и туннельные интерфейсы, восстановленные из S3-снепшота, содержат устаревшие привязки pod CIDR. В результате etcd рапортует об успехе, пока межсерверный трафик молча уходит в blackhole ядра. Регламент аварийного поднятия кластера на bare-metal требует жесткой последовательности действий: - Полная остановка службы k3s на всех контроллер-нодах одновременно. - Полное удаление содержимого /var/lib/rancher/k3s/server/db на всех ведомых нодах master. - Выполнение восстановления на выделенном лидере через cluster-reset с явным указанием пути к S3-снепшоту. - Поочередный запуск ведомых нод с пустым локальным хранилищем etcd для штатного прохождения процедуры rejoin. - Принудительный сброс и перезапуск интерфейсов WireGuard для обновления таблиц маршрутизации ядра. Настоящий Disaster Recovery проверяется не наличием файлов в S3-бакете, а возможностью поднятия полностью согласованного кворума с нуля на изолированном сетевом сегменте. Разборы архитектуры bare-metal Kubernetes, сетевого стека ядра и сценариев disaster recovery публикуются в проекте https://ftops.space.
FreeBSD не умер. Он просто отказался деградировать.

Пока Linux-мир тащит systemd, overlayfs-костыли и eBPF-хаки для того, чтобы хоть как-то обеспечить изоляцию процессов, во FreeBSD это решено архитектурно. Jails появились в 2000 году — за 13 лет до Docker. Не как эксперимент, а как production-примитив с чёткой семантикой: отдельный filesystem namespace, отдельный сетевой стек, полная изоляция PID. Никаких cgroup-иерархий, никакого overlayfs. Просто работает.

ZFS на FreeBSD — это не feature, это фундамент. ARC кэш адаптивно занимает свободную RAM и освобождает её под давлением без участия оператора. Copy-on-write гарантирует, что partial write при отказе питания физически невозможен. Checksumming на уровне блоков ловит bit rot, который ext4 и xfs молча пропускают годами. Для сетевого шлюза, где данные — это конфиги, сертификаты и состояние туннелей, это не опция, это требование.

Пул ZFS на 4 дисках с mirror vdev даёт read IOPS, которые линейно масштабируются с числом дисков. zfs sen...
FreeBSD не умер. Он просто отказался деградировать.

Пока Linux-мир тащит systemd, overlayfs-костыли и eBPF-хаки для того, чтобы хоть как-то обеспечить изоляцию процессов, во FreeBSD это решено архитектурно. Jails появились в 2000 году — за 13 лет до Docker. Не как эксперимент, а как production-примитив с чёткой семантикой: отдельный filesystem namespace, отдельный сетевой стек, полная изоляция PID. Никаких cgroup-иерархий, никакого overlayfs. Просто работает.

ZFS на FreeBSD — это не feature, это фундамент. ARC кэш адаптивно занимает свободную RAM и освобождает её под давлением без участия оператора. Copy-on-write гарантирует, что partial write при отказе питания физически невозможен. Checksumming на уровне блоков ловит bit rot, который ext4 и xfs молча пропускают годами. Для сетевого шлюза, где данные — это конфиги, сертификаты и состояние туннелей, это не опция, это требование.

Пул ZFS на 4 дисках с mirror vdev даёт read IOPS, которые линейно масштабируются с числом дисков. zfs send/receive — атомарная репликация снапшотов по сети без rsync и без риска рассинхрона. Один скрипт в cron, и у тебя полная DR-копия шлюза на удалённом узле, актуальная с точностью до часа.

Для сетевых шлюзов и хранилищ FreeBSD выигрывает не маркетингом, а архитектурным консерватизмом: стек проверен, ABI стабилен, обновления предсказуемы. В 2026 году это редкость.

https://ftops.space

#ftops #devops #linux #freebsd #sre #инфраструктура
Разбор аварии: systemctl is-active врёт

Происходит чаще, чем хочется признавать. Мониторинг зелёный, алерты молчат, дашборд показывает healthy. Пользователи не могут подключиться уже 40 минут.

Корневая причина: systemd оценивает состояние юнита по exit-коду ExecStart, а не по тому, работает ли сам сервис. Если процесс запустился, инициализировался и завершился с кодом 0 — юнит помечается active (exited). Это нормальное поведение для oneshot-сервисов. Но если так же ведёт себя ваш nginx или postgres — у вас тихая авария.

Конкретный сценарий: база данных поднялась, провела миграции, лог написала, завершилась с кодом 0. Systemd: active. В реальности — сокет не слушает, соединения не принимаются, приложение падает при первом запросе.

Что делать правильно:

1. Проверять функцию, а не юнит. После деплоя: nc -z localhost 5432, psql -c '\l', curl -sf http://localhost/health — не systemctl is-active.
2. Настроить ExecStartPost с реальной проверкой. Если ExecStartPost падает — systemd откати...
Разбор аварии: systemctl is-active врёт

Происходит чаще, чем хочется признавать. Мониторинг зелёный, алерты молчат, дашборд показывает healthy. Пользователи не могут подключиться уже 40 минут.

Корневая причина: systemd оценивает состояние юнита по exit-коду ExecStart, а не по тому, работает ли сам сервис. Если процесс запустился, инициализировался и завершился с кодом 0 — юнит помечается active (exited). Это нормальное поведение для oneshot-сервисов. Но если так же ведёт себя ваш nginx или postgres — у вас тихая авария.

Конкретный сценарий: база данных поднялась, провела миграции, лог написала, завершилась с кодом 0. Systemd: active. В реальности — сокет не слушает, соединения не принимаются, приложение падает при первом запросе.

Что делать правильно:

1. Проверять функцию, а не юнит. После деплоя: nc -z localhost 5432, psql -c '\l', curl -sf http://localhost/health — не systemctl is-active.
2. Настроить ExecStartPost с реальной проверкой. Если ExecStartPost падает — systemd откатит юнит в failed и вы получите алерт.
3. В мониторинге использовать blackbox-экспортер (Prometheus) или аналогичный инструмент, который проверяет порт или HTTP-эндпоинт снаружи, а не статус юнита.
4. Для критичных сервисов добавить Restart=on-failure + StartLimitIntervalSec — но это страховка, не диагностика.

BGP-постмортем по аналогии: провайдер объявляет маршрут, IGP его принимает, is-active говорит ОК. А трафик уходит в петлю, потому что AS-path не проверялся, а next-hop недостижим. Мониторинг видит сессию established — и молчит. Реальная проверка — это synthetic probe через этот маршрут, а не состояние BGP-сессии.

Вывод один: статус — это мнение системы о себе. Функция — это факт.

https://ftops.space

#ftops #devops #linux #sre #инфраструктура
PII нельзя отправлять в API по умолчанию

Если приложение передает во внешний AI-шлюз объект запроса целиком, вместе с полезным текстом наружу могут уйти ФИО, телефоны, cookies, внутренние URL и секреты конфигурации. HTTPS защищает канал, но не меняет получателя данных.

Защита начинается до отправки: локальный шлюз классифицирует поля, удаляет персональные данные и секреты, заменяет идентификаторы на псевдонимы, фиксирует аудит и только затем выбирает внешний или локальный inference. Маскирование после API-вызова — это уже не защита.

Для 152-ФЗ важен доказуемый контроль потока данных: какие поля разрешены, куда они уходят, кто это подтвердил и можно ли восстановить историю обращения.

Проверьте интеграции: что произойдет, если разработчик случайно передаст в prompt объект запроса целиком? Практические схемы суверенного шлюза: https://ftops.space

#ftops #devops #linux #freebsd #sre #инфраструктура
Безопасность и суверенитет данных: что остаётся за вами

152-ФЗ — это не про формальность. Это про физическое место хранения персональных данных резидентов. Если ваша инфраструктура отдаёт PII в сторонний API за пределами РФ, вы уже в зоне риска, даже если контракт подписан. Локализация баз — первый рубеж, но не последний.

Суверенный AI-шлюз решает проблему на уровне архитектуры: перед отправкой запроса во внешнюю модель шлюз вычищает ФИО, паспорта, телефоны, email, адреса и токены. Модель получает обезличенный контекст и не может сохранить то, чего не видела. Это не обфускация, а полное удаление полей до выхода пакета за периметр.

Отдельный пласт — утечка ключей и секретов. Скан репозиториев, git-истории, переменных окружения, docker-образов и логов. Практика: gitleaks или trufflehog в CI, ротация каждые 90 дней, vault вместо env-файлов, pre-commit хуки против коммита секретов. Один утёкший токен способен перечеркнуть годы работы над репутацией.

Суверенитет — это не лозунг, а инжен...
Безопасность и суверенитет данных: что остаётся за вами

152-ФЗ — это не про формальность. Это про физическое место хранения персональных данных резидентов. Если ваша инфраструктура отдаёт PII в сторонний API за пределами РФ, вы уже в зоне риска, даже если контракт подписан. Локализация баз — первый рубеж, но не последний.

Суверенный AI-шлюз решает проблему на уровне архитектуры: перед отправкой запроса во внешнюю модель шлюз вычищает ФИО, паспорта, телефоны, email, адреса и токены. Модель получает обезличенный контекст и не может сохранить то, чего не видела. Это не обфускация, а полное удаление полей до выхода пакета за периметр.

Отдельный пласт — утечка ключей и секретов. Скан репозиториев, git-истории, переменных окружения, docker-образов и логов. Практика: gitleaks или trufflehog в CI, ротация каждые 90 дней, vault вместо env-файлов, pre-commit хуки против коммита секретов. Один утёкший токен способен перечеркнуть годы работы над репутацией.

Суверенитет — это не лозунг, а инженерная дисциплина. Контроль над данными означает контроль над тем, что видит каждая внешняя система. Если вы не можете ответить, куда уходит PII и где лежат ваши ключи, значит ответ уже есть у кого-то другого.

#ftops #devops #linux #freebsd #sre #инфраструктура
Сценарий ночного отказа: 03:00, API сыплет 502. На хосте свободная RAM, CPU скучает. Поверхностный диагноз — «мало воркеров, добавим сервер». Сервис работает в chroot с cgroups v2 и seccomp. После роста нагрузки пул пытается создавать потоки, но clone() возвращает EAGAIN. Запросы обслуживать некому. Начинаем с cat /proc/$PID/cgroup: в cgroups v2 строка 0:: укажет путь группы. Для найденной группы читаем pids.current, pids.max и pids.events; проверяем также предков. Рост счётчика max вместе с отказами создания потоков выводит на PID-лимит. Он учитывает и потоки. strace -f -e trace\=clone,clone3 -p "$PID" позволяет увидеть отказ при воспроизведении. Один EAGAIN ещё не доказывает причину: есть и другие ограничения. Семантика счётчиков — в документации ядра. Исправление — ограничить рост пула, согласовать его размер с pids.max и оставить запас под служебные потоки. Алертить нужно на рост pids.events:max и приближение pids...
Сценарий ночного отказа: 03:00, API сыплет 502. На хосте свободная RAM, CPU скучает. Поверхностный диагноз — «мало воркеров, добавим сервер». Сервис работает в chroot с cgroups v2 и seccomp. После роста нагрузки пул пытается создавать потоки, но clone() возвращает EAGAIN. Запросы обслуживать некому. Начинаем с cat /proc/$PID/cgroup: в cgroups v2 строка 0:: укажет путь группы. Для найденной группы читаем pids.current, pids.max и pids.events; проверяем также предков. Рост счётчика max вместе с отказами создания потоков выводит на PID-лимит. Он учитывает и потоки. strace -f -e trace\=clone,clone3 -p "$PID" позволяет увидеть отказ при воспроизведении. Один EAGAIN ещё не доказывает причину: есть и другие ограничения. Семантика счётчиков — в документации ядра. Исправление — ограничить рост пула, согласовать его размер с pids.max и оставить запас под служебные потоки. Алертить нужно на рост pids.events:max и приближение pids.current к действующему лимиту. Просто поднять потолок — перенести аварию. Покупка managed K8s не исправляет бесконтрольное размножение потоков. Chroot меняет корень разрешения путей и сам по себе не создаёт защитную песочницу; cgroups ограничивают ресурсы; seccomp фильтрует системные вызовы. Это разные механизмы, а ядро остаётся общим. Гостевой ОС нет, но нулевых накладных расходов никто не обещал. Основания: chroot(2), seccomp(2). Эксплуатация начинается с понимания границ: https://ftops.space.
Разбор сценария отказа: 03:00, распределённый K3s поверх WireGuard. Скомпрометированный pod изолируют политикой, закрывающей исходящий доступ. Мониторинг сообщает: новое подключение к БД не проходит, карантин работает. Но ранее открытый TCP-сеанс продолжает передавать данные. Дежурный подозревает обходной маршрут. Проверка измеряла только новые подключения. В варианте с netfilter улику ищем на узле обработки трафика: conntrack -L -p tcp --dport 5432 и iptables-save -c. Если ACCEPT для ESTABLISHED срабатывает раньше проверки ограничения, пакеты старого сеанса проходят. Рост счётчика этого правила сопоставляем с захватом конкретного потока. sysctl net.netfilter.nfconntrackcount net.netfilter.nfconntrackmax показывает заполнение таблицы, но само наличие записи не доказывает обход политики. Это не универсальное поведение Kubernetes: применение изменённой NetworkPolicy к существующим соединениям зависит от реализации. Это прямо закреплено в документации Kubernetes
Разбор сценария отказа: 03:00, распределённый K3s поверх WireGuard. Скомпрометированный pod изолируют политикой, закрывающей исходящий доступ. Мониторинг сообщает: новое подключение к БД не проходит, карантин работает. Но ранее открытый TCP-сеанс продолжает передавать данные. Дежурный подозревает обходной маршрут. Проверка измеряла только новые подключения. В варианте с netfilter улику ищем на узле обработки трафика: conntrack -L -p tcp --dport 5432 и iptables-save -c. Если ACCEPT для ESTABLISHED срабатывает раньше проверки ограничения, пакеты старого сеанса проходят. Рост счётчика этого правила сопоставляем с захватом конкретного потока. sysctl net.netfilter.nfconntrackcount net.netfilter.nfconntrackmax показывает заполнение таблицы, но само наличие записи не доказывает обход политики. Это не универсальное поведение Kubernetes: применение изменённой NetworkPolicy к существующим соединениям зависит от реализации. Это прямо закреплено в документации Kubernetes. WireGuard шифрует межузловой канал; судьбу старого сеанса определяет механизм фильтрации внутри него. Исправление: включить в процедуру карантина проверенный для своего dataplane механизм отзыва действующих потоков. Приёмочный тест держит соединение открытым, применяет изоляцию и проверяет прекращение передачи на каждой площадке, затем отдельно проверяет новый сеанс. Покупка ещё одного контроллера эту проверку не заменяет. Для https://ftops.space критерий простой: карантин завершён, когда запрещённый обмен действительно остановлен.
Разбор типового отказа в 03:00. Балансировщик сыплет таймаутами, CPU скучает. Дежурный обвиняет сеть и поднимает net.core.somaxconn. Клиенты теперь дольше стоят перед закрытой дверью: accept4() возвращает EMFILE, процесс исчерпал свой лимит дескрипторов. Это отличается от ENFILE — исчерпания общесистемного лимита открытых файлов. Семантика ошибок: accept(2). Сначала улики: prlimit --pid "$PID" --nofile показывает лимит работающего процесса; ls -U /proc/$PID/fd \| wc -l — приблизительное число занятых FD. PID задаём для нужного worker. ss -lnt показывает очередь слушающего сокета. Два замера nstat -az TcpExtListenOverflows TcpExtListenDrops под нагрузкой выявляют прирост счётчиков. В K3s сетевые замеры выполняем в network namespace приложения. Переполнение очереди само по себе ещё не доказывает нехватку FD: нужны ошибки accept и заполнение лимита. net.core.somaxconn ограничивает backlog, запрошенный приложением через listen(); подня...
Разбор типового отказа в 03:00. Балансировщик сыплет таймаутами, CPU скучает. Дежурный обвиняет сеть и поднимает net.core.somaxconn. Клиенты теперь дольше стоят перед закрытой дверью: accept4() возвращает EMFILE, процесс исчерпал свой лимит дескрипторов. Это отличается от ENFILE — исчерпания общесистемного лимита открытых файлов. Семантика ошибок: accept(2). Сначала улики: prlimit --pid "$PID" --nofile показывает лимит работающего процесса; ls -U /proc/$PID/fd \| wc -l — приблизительное число занятых FD. PID задаём для нужного worker. ss -lnt показывает очередь слушающего сокета. Два замера nstat -az TcpExtListenOverflows TcpExtListenDrops под нагрузкой выявляют прирост счётчиков. В K3s сетевые замеры выполняем в network namespace приложения. Переполнение очереди само по себе ещё не доказывает нехватку FD: нужны ошибки accept и заполнение лимита. net.core.somaxconn ограничивает backlog, запрошенный приложением через listen(); поднять только sysctl недостаточно. Увеличение очереди помогает пережить короткий всплеск, если обработчик затем её разгребает. listen(2). tcptwreuse разрешает повторное использование TIMEWAIT-сокетов для новых соединений при безопасных условиях протокола; лимит FD и отказ accept он не исправляет. [Документация ядра](https://www.kernel.org/doc/html/latest/networking/ip-sysctl.html#tcp-tw-reuse). Исправление начинаем с причины накопления FD: утечка, зависшие соединения или честно выросшая конкуренция. Затем согласуем лимит процесса, бюджет соединений приложения и backlog. После применения проверяем фактический RLIMITNOFILE у worker, ошибки accept, прирост ListenOverflows и задержку под нагрузкой. Kubernetes не рассчитывает этот бюджет за инженера. Эксплуатация начинается с измеренного предела: https://ftops.space.
Разбор типового отказа в 03:00: маленький VPS, K3s, поды уходят в Evicted. Мониторинг доступности требует ещё одну ноду, график свободных гигабайтов зелёный. Ложный диагноз — «кластеру мало мощности». Реальная причина: кеш приложения на общей файловой системе съел inode. DiskPressure возникает и по нехватке inode, до полного исчерпания байтов. Механизм описан в [документации Kubernetes](https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/). Улики: df -h /var/lib/rancher/k3s /var/lib/kubelet и df -i /var/lib/rancher/k3s /var/lib/kubelet для стандартных путей. Затем kubectl describe node NODE: сверяем Conditions и Events. В node_exporter смотрим node_filesystem_avail_bytes и node_filesystem_files_free по нужному mountpoint. Это два разных ресурса файловой системы. Для поиска россыпи файлов — sudo du --inodes -x -d 2 /var/lib/kubelet; обход большого дерева создаёт дополнительную нагрузку. ImageGC удаляет неиспользуемые образы. Его пороги заполнения в байтах не о...
Разбор типового отказа в 03:00: маленький VPS, K3s, поды уходят в Evicted. Мониторинг доступности требует ещё одну ноду, график свободных гигабайтов зелёный. Ложный диагноз — «кластеру мало мощности». Реальная причина: кеш приложения на общей файловой системе съел inode. DiskPressure возникает и по нехватке inode, до полного исчерпания байтов. Механизм описан в [документации Kubernetes](https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/). Улики: df -h /var/lib/rancher/k3s /var/lib/kubelet и df -i /var/lib/rancher/k3s /var/lib/kubelet для стандартных путей. Затем kubectl describe node NODE: сверяем Conditions и Events. В node_exporter смотрим node_filesystem_avail_bytes и node_filesystem_files_free по нужному mountpoint. Это два разных ресурса файловой системы. Для поиска россыпи файлов — sudo du --inodes -x -d 2 /var/lib/kubelet; обход большого дерева создаёт дополнительную нагрузку. ImageGC удаляет неиспользуемые образы. Его пороги заполнения в байтах не ограничивают число файлов приложения; даже успешная уборка образов не устраняет источник роста. Для байтового запаса настраиваем imageGCHighThresholdPercent и imageGCLowThresholdPercent с учётом eviction-порогов и размера очередной распаковки. Low должен быть ниже High. Поведение — в [документации ImageGC](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#containers-images). Профилактика: ограничить число и срок жизни файлов кеша, настроить ротацию логов, алертить отдельно свободные байты и inode. Запас проверять на деплое, когда старый и новый образы сосуществуют. Покупать VPS вместо ограничения бесконечного кеша — платить налог на лень. https://ftops.space
Учебный постмортем, 03:00. Мониторинг кричит: рестарты, exit 137, «добавьте памяти». В K3s падает liveness-проверка, завязанная на удалённую зависимость. После истечения срока завершения kubelet добивает контейнер. Облачный рецепт — купить RAM. Но маршрут от этого короче не станет. Проверяем версию OOM: journalctl -k --since '-15 min' и cat /sys/fs/cgroup/<путь-контейнера>/memory.events. Нужна дельта oom_kill за аварию, пока cgroup ещё существует. В этом сценарии прироста нет, журнал ядра без OOM, события kubelet подтверждают провал liveness. Один пустой журнал ничего не доказывает. Семантика счётчика: [документация ядра](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). На клиенте и сервере одновременно запускаем tcpdump -ni any -nn -vv 'tcp port 443 or icmp', сопоставляем адреса с учётом NAT. Клиент повторяет SYN, сервер их не видит: локализовали потерю между точками захвата, но ещё не доказали петлю. Выполняем traceroute -n -T -p 443 <IP-сервера>, затем проверяем о...