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 #инфраструктура
Пока 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 откати...
Происходит чаще, чем хочется признавать. Мониторинг зелёный, алерты молчат, дашборд показывает 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 #инфраструктура
Происходит чаще, чем хочется признавать. Мониторинг зелёный, алерты молчат, дашборд показывает 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 #инфраструктура
Если приложение передает во внешний 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 хуки против коммита секретов. Один утёкший токен способен перечеркнуть годы работы над репутацией.
Суверенитет — это не лозунг, а инжен...
Безопасность и суверенитет данных: что остаётся за вами
152-ФЗ — это не про формальность. Это про физическое место хранения персональных данных резидентов. Если ваша инфраструктура отдаёт PII в сторонний API за пределами РФ, вы уже в зоне риска, даже если контракт подписан. Локализация баз — первый рубеж, но не последний.
Суверенный AI-шлюз решает проблему на уровне архитектуры: перед отправкой запроса во внешнюю модель шлюз вычищает ФИО, паспорта, телефоны, email, адреса и токены. Модель получает обезличенный контекст и не может сохранить то, чего не видела. Это не обфускация, а полное удаление полей до выхода пакета за периметр.
Отдельный пласт — утечка ключей и секретов. Скан репозиториев, git-истории, переменных окружения, docker-образов и логов. Практика: gitleaks или trufflehog в CI, ротация каждые 90 дней, vault вместо env-файлов, pre-commit хуки против коммита секретов. Один утёкший токен способен перечеркнуть годы работы над репутацией.
Суверенитет — это не лозунг, а инженерная дисциплина. Контроль над данными означает контроль над тем, что видит каждая внешняя система. Если вы не можете ответить, куда уходит PII и где лежат ваши ключи, значит ответ уже есть у кого-то другого.
#ftops #devops #linux #freebsd #sre #инфраструктура
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 критерий простой: карантин завершён, когда запрещённый обмен действительно остановлен.
Kubernetes
Network Policies
If you want to control traffic flow at the IP address or port level (OSI layer 3 or 4), NetworkPolicies allow you to specify rules for traffic flow within your cluster, and also between Pods and the outside world. Your cluster must use a network plugin that…
Разбор типового отказа в 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
Kubernetes
Node-pressure Eviction
Node-pressure eviction is the process by which the kubelet proactively terminates pods to reclaim resource on nodes.
The kubelet monitors resources like memory, disk space, and filesystem inodes on your cluster's nodes. When one or more of these resources…
The kubelet monitors resources like memory, disk space, and filesystem inodes on your cluster's nodes. When one or more of these resources…
Учебный постмортем, 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-сервера>, затем проверяем о...
Учебный постмортем, 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-сервера>, затем проверяем обратное направление. Повторяющиеся хопы — зацепка; подтверждение — FIB соседних маршрутизаторов отправляет адрес назначения друг через друга. Параметры TCP-трассировки: [traceroute](https://www.man7.org/linux/man-pages/man8/traceroute.8.html). Причина сценария — изменение BGP-политики создало цикл пересылки. Проверка выбранных next-hop и установленных маршрутов связала петлю с изменением; один traceroute этого не умеет. Откатываем политику, проверяем оба направления и восстановление handshake. Убираем удалённую зависимость из liveness, её доступность учитываем в readiness по смыслу сервиса. BGP Established не гарантирует доставку. Разбор эксплуатации: https://ftops.space.
03:00. Типовой постмортем: приложение ловит DNS-таймауты, дашборд обвиняет CoreDNS. Его CPU свободен, время обработки нормальное. Добавление реплик ничего не меняет. В кластере с kube-proxy в режиме iptables подозреваем участок Pod → Service IP: UDP-запрос может потеряться при гонке conntrack/DNAT ещё до DNS-сервера. Зелёная серверная метрика такой запрос вообще не видела. На проблемной ноде снимаем conntrack -S несколько раз: смотрим прирост insertfailed, drop, earlydrop. Команда sysctl net.netfilter.nfconntrackcount net.netfilter.nfconntrackmax помогает проверить заполнение таблицы. Гонка возможна и без её насыщения; один счётчик причину не доказывает. Сопоставляем захваты tcpdump -ni any -nn 'udp port 53' у клиента и сервера: где виден запрос, где ответ, где начинается повтор. Исправление для этого пути — NodeLocal DNSCache на нодах: локальный DNS-трафик обходит DNAT и conntrack, промахи кэша для кластерных имён можно отправлять в CoreDNS по TCP. Проверяем фактический адрес ре...
03:00. Типовой постмортем: приложение ловит DNS-таймауты, дашборд обвиняет CoreDNS. Его CPU свободен, время обработки нормальное. Добавление реплик ничего не меняет. В кластере с kube-proxy в режиме iptables подозреваем участок Pod → Service IP: UDP-запрос может потеряться при гонке conntrack/DNAT ещё до DNS-сервера. Зелёная серверная метрика такой запрос вообще не видела. На проблемной ноде снимаем conntrack -S несколько раз: смотрим прирост insertfailed, drop, earlydrop. Команда sysctl net.netfilter.nfconntrackcount net.netfilter.nfconntrackmax помогает проверить заполнение таблицы. Гонка возможна и без её насыщения; один счётчик причину не доказывает. Сопоставляем захваты tcpdump -ni any -nn 'udp port 53' у клиента и сервера: где виден запрос, где ответ, где начинается повтор. Исправление для этого пути — NodeLocal DNSCache на нодах: локальный DNS-трафик обходит DNAT и conntrack, промахи кэша для кластерных имён можно отправлять в CoreDNS по TCP. Проверяем фактический адрес резолвера и правила обхода: один DaemonSet ещё не доказывает изменение маршрута. Механизм описан в документации Kubernetes. После изменения проверяем DNS p99 из Pod на каждой ноде, таймауты и прирост потерь под прежней нагрузкой. Отдельно проверяем перезапуск локального кэша: теперь это зависимость всей ноды. Покупать дополнительные реплики до локализации потерь — платить налог на отсутствие диагностики. Эксплуатация начинается с пути пакета: https://ftops.space.
Kubernetes
Using NodeLocal DNSCache in Kubernetes Clusters
Feature state: Stable since Kubernetes v1.18 This page provides an overview of NodeLocal DNSCache feature in Kubernetes.
Before you beginYou need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.…
Before you beginYou need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.…
03:00, сценарий планового вывода узла K3s. Дежурный выставил Longhorn allowScheduling\=false и выключил сервер. Тома стали degraded, восстановление реплик нагрузило соседние диски. Поверхностный диагноз: «хранилище тормозит». Настоящий: запрет новых реплик приняли за перенос существующих. Kubernetes не отменяет физику дисков, зато прекрасно размножает зелёные статусы. До отключения смотрим размещение: kubectl -n longhorn-system get replicas.longhorn.io -o custom-columns\=NAME:.metadata.name,NODE:.spec.nodeID,VOLUME:.spec.volumeName. На оставшихся узлах: cat /proc/pressure/io и iostat -xz 1. Рост PSI io some/full показывает время задержек задач из-за I/O; await — задержки блочных запросов. Это следы нагрузки, а не доказательство поломки диска. Сопоставляем их с началом rebuild. Для эвакуации нужны allowScheduling\=false и evictionRequested\=true в Longhorn Node CR. Longhorn переносит реплику после успешного восстановления замены — это описано в документации
03:00, сценарий планового вывода узла K3s. Дежурный выставил Longhorn allowScheduling\=false и выключил сервер. Тома стали degraded, восстановление реплик нагрузило соседние диски. Поверхностный диагноз: «хранилище тормозит». Настоящий: запрет новых реплик приняли за перенос существующих. Kubernetes не отменяет физику дисков, зато прекрасно размножает зелёные статусы. До отключения смотрим размещение: kubectl -n longhorn-system get replicas.longhorn.io -o custom-columns\=NAME:.metadata.name,NODE:.spec.nodeID,VOLUME:.spec.volumeName. На оставшихся узлах: cat /proc/pressure/io и iostat -xz 1. Рост PSI io some/full показывает время задержек задач из-за I/O; await — задержки блочных запросов. Это следы нагрузки, а не доказательство поломки диска. Сопоставляем их с началом rebuild. Для эвакуации нужны allowScheduling\=false и evictionRequested\=true в Longhorn Node CR. Longhorn переносит реплику после успешного восстановления замены — это описано в документации. Заранее проверяем ёмкость и ограничения размещения на принимающих узлах. Если замене негде жить, флаг не создаст ей диск. Перед выводом проверяем завершение эвакуации, отсутствие реплик на узле и восстановление требуемой избыточности томов. Затем — штатный drain с учётом политики Longhorn и отключение. Для краткого обслуживания стратегия может отличаться, но сам allowScheduling\=false разрешением на shutdown не становится. Эксплуатация начинается с проверки результата: https://ftops.space.
Longhorn
Longhorn | Evicting Replicas on Disabled Disks or Nodes
03:17. Учебный постмортем: потерян quorum etcd, начинаем восстановление K3s. Последняя выгрузка в S3 зелёная, API недоступен, restore с прежним S3 Secret не работает. Первый диагноз — отвалился маршрут до бакета. Покупка объектного хранилища уже состоялась. Покупка работоспособного DR — только в презентации. Проверяем журнал: journalctl -u k3s -b -n 200 --no-pager. Снимаем nstat -az TcpRetransSegs до и после попытки, сравниваем прирост; при включённом conntrack смотрим sysctl net.netfilter.nfconntrackcount net.netfilter.nfconntrackmax. Эти показатели проверяют сетевую гипотезу, но не доказывают доступность S3. Улика здесь в конфигурации: доступ к бакету задан через etcd-s3-config-secret. Во время restore API недоступен и выдать Secret не может. До скачивания дело не дошло. Выход: заранее вынести S3 credentials и server token соответствующего снепшота в защищённый аварийный комплект вне кластера. Остановить K3s на всех server-узлах. Восстанавливать один узел, передав S3-параметры яв...