UPTIME
FAMILY
Оперативные сводки // Дневник исследований
СЕТЕВОЙ ЭФИР // LIVE TELEMETRY · ОБНОВЛЕНИЕ КАЖДЫЕ 6 МИНУТ

Хроника исследований устойчивости

Оперативные сводки, деконструкция микростресса, свежие научные данные и протоколы связи из исследовательских тестов Uptime Family и суверенной сети проектов.

СВОДОК В СЕТИ: 50
АКТИВНЫЙ ПРОТОКОЛ: EVIDENCE-BASED 2026
МЕХАНИКА: ZERO-EMOJI / COGNITIVE HYGIENE
ШЛЮЗ НОВИЗНЫ: SIMILARITY ≤ 0.35
[SRE & BARE-METAL DIAGNOSTICS]

Экспресс-аудит отказоустойчивости & BGP-петель

Диагностика K3s mesh, WireGuard ретрансмитов и выявление BGP-петель транзита. Чек-лист и плейбук самовосстановления в подарок.

LEAD MAGNET // 2026
[FTOPS SPACE]DISPATCH #753

[ftops] SMM Case: Порт 443 открыт

03:00. Учебный постмортем: прямой WireGuard блокируется, после переноса через wstunnel в WSS соединение устанавливается. Проверка TCP/443 зелёная, handshake обновлялся недавно, но SSH зависает под нагрузкой. Дежурный объявляет: «DPI научился резать и это». Проверка порта такого диагноза не даёт. В выбранном режиме UDP WireGuard едет внутри WebSocket поверх TLS/TCP. Потеря внешнего TCP-сегмента задерживает выдачу следующих байтов приложению, даже если они уже пришли. Внутренние TCP-сессии ждут, а при достаточной задержке запускают собственные повторные передачи. Проблемы производительности такой связки отмечены в [трекере wstunnel](https://github.com/erebe/wstunnel/issues/439). Это механизм возможного отказа, ещё не доказательство причины конкретной аварии. На узле wstunnel: ss -tinp '( dport = :443 )'. Находим нужный сокет по адресу и процессу, наблюдаем rtt, rto, retrans и Send-Q во время зависания. nstat -az TcpRetransSegs TcpExtTCPTimeouts снимаем дважды: важен прирост, счётчики относятся ко всему сетевому namespace. Сопоставляем его с захватом tcpdump -ni eth0 'host SERVER_IP and tcp port 443', подставив внешний интерфейс и IP сервера. Повторные передачи подтверждают проблему доставки, но сами по себе не отличают DPI от обычных потерь. Критерий восстановления — полезный трафик и задержка под нагрузкой, включая проверку на потерях. Отдельно проверяем, что маршрут к WSS-серверу не завернулся в сам VPN. WSS не гарантирует обход любого DPI, а уменьшение MTU не отменяет упорядоченную доставку TCP. Ещё один ingress не исправит свойства транспорта. Эксплуатация bare metal: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На узле wstunnel: ss -tinp '( dport = :443 )'. Найдите сокет до WSS-сервера. Во время зависания смотрите retrans, rto и Send-Q: свежий handshake WireGuard не измеряет, сколько полезных данных застряло во внешнем TCP.
[FTOPS SPACE]DISPATCH #747

[ftops] SMM Case: Бэкап etcd лежал в S3

Мониторинг кричал: S3 недоступен, restore упирается в timeout. Проверили ядро: ss -s, nstat -az | egrep 'TcpRetransSegs|IpFragFails', conntrack -C, conntrack -S. Retransmit, фрагментация и conntrack были в норме. Сеть оправдана. Настоящий отказ был выше: настройки S3 хранились в Secret внутри самого кластера. Во время аварийного восстановления kube-apiserver ещё не работает, поэтому --etcd-s3-config-secret бесполезен. Получился классический замок с ключом внутри сейфа. Восстановление запускается на одном остановленном server с явными S3-параметрами и исходным токеном: k3s server --cluster-reset --cluster-reset-restore-path=SNAPSHOT --etcd-s3 --etcd-s3-bucket=BUCKET --etcd-s3-access-key=KEY --etcd-s3-secret-key=SECRET --token=ORIGINAL_TOKEN. Затем обычный запуск K3s; на остальных etcd-server старую базу убирают только после отдельной копии и присоединяют узлы заново. В DR-комплект входят снепшот, /var/lib/rancher/k3s/server/token, CA для S3, автономные credentials и проверенный runbook. Если restore никогда не прогоняли на пустом железе, резервной копии у вас нет. Есть надежда с HTTP API. https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
До остановки фиксируйте контрольную сумму и токен отдельно: sha256sum snapshot.db; install -m 600 /var/lib/rancher/k3s/server/token /mnt/dr/k3s-token. После restore проверьте членов: k3s etcdctl member list -w table.
[FTOPS SPACE]DISPATCH #741

[ftops] SMM Case: Мониторинг кричал: pod’ам не хватает диска

В 03:00 мониторинг показал DiskPressure, pod eviction и провал rollout. Поверхностный диагноз — «маленький VPS». Реальность: /var/lib/rancher/k3s/agent/containerd разросся слоями образов, а ImageGC стартовал слишком поздно и не успел освободить место до eviction threshold. Проверяем не красивый процент в панели, а ноду: kubectl describe node NODE; df -hT; df -ih; sudo du -xhd2 /var/lib/rancher/k3s/agent/containerd | sort -h; sudo k3s crictl images. Если df показывает дефицит, а du нет — ищем удалённые, но открытые файлы: sudo lsof +L1. Смотрим, что происходило внизу: cat /proc/pressure/io; awk '{print $3,$4,$6,$8,$10,$13}' /proc/diskstats; journalctl -u k3s -u k3s-agent --since '-2h' | grep -Ei 'imagegc|diskpressure|evict|filesystem'. Настраиваем kubelet заранее: imageGCHighThresholdPercent и imageGCLowThresholdPercent должны оставлять реальный резерв до evictionHard, а не делить последние гигабайты. На малой ноде свободное место — эксплуатационный бюджет. Ограничивайте размер образов, удаляйте неиспользуемые теги, контролируйте inode и проверяйте GC после каждого обновления K3s. Практика bare-metal эксплуатации: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Быстрая сверка причины: sudo k3s crictl images; sudo du -xsh /var/lib/rancher/k3s/agent/containerd/; df -h /var/lib/rancher/k3s. Ручное удаление каталогов containerd запрещено: чистить нужно через CRI, иначе метаданные и snapshots разъедутся.
[FTOPS SPACE]DISPATCH #705

[ftops] SMM Case: S3-объект найден

Мониторинг кричал: apiserver недоступен, S3 отвечает медленно. Дежурный проверил не легенду, а железо: cat /proc/pressure/io, iostat -xz 1, dmesg -T | tail -100, ss -lntp | egrep ':2379|:2380'. I/O pressure не рос, TCP не терялся. Сломался не транспорт — нарушили процедуру membership. На одной server-ноде K3s остановили и выполнили: k3s server --cluster-reset --cluster-reset-restore-path=<snapshot-name> --etcd-s3 --etcd-s3-bucket=<bucket> .... Для нового хоста нужен исходный --token: им расшифровываются bootstrap-данные. S3 Secret из Kubernetes при restore недоступен — API ещё мёртв, поэтому параметры S3 подаются через CLI или конфиг на диске. После сообщения о завершённом reset запустили только первый server и проверили curl -sf http://127.0.0.1:2381/metrics | egrep 'etcd_server_has_leader|etcd_disk_wal_fsync_duration_seconds'. На остальных server-нодах при остановленном K3s архивировали и удалили из рабочего пути /var/lib/rancher/k3s/server/db, затем присоединили их заново. Старые member ID нельзя пускать в новый quorum. Снепшот в бакете — лишь сырьё. DR существует только после регулярного restore-test, отдельного хранения token и записанного порядка запуска узлов. Практика bare-metal эксплуатации: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Проверка до запуска соседей: curl -sf http://127.0.0.1:2381/metrics | egrep 'etcd_server_has_leader|etcd_server_leader_changes_seen_total'. Затем на каждой peer-ноде: systemctl stop k3s; mv /var/lib/rancher/k3s/server/db /var/lib/rancher/k3s/server/db.stale.
[FTOPS SPACE]DISPATCH #696

[ftops] SMM Case: Exit 137 — ещё не диагноз OOM

03:00. Учебный постмортем: панель объявила OOM по exit 137, дежурный предложил поднять memory limit. Но 137 совместим с SIGKILL и сам по себе не устанавливает причину. Проверяем journalctl -k --since '20 min ago', журнал kubelet и прирост oom_kill в memory.events именно cgroup пострадавшего контейнера за окно аварии. В сценарии OOM-событий нет, зато kubelet зафиксировал провал liveness и принудительное завершение после grace period. Семантика счётчиков: [документация ядра](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). На клиенте и сервере одновременно запускаем tcpdump -ni eth0 -nn -vvv 'tcp port 443 or icmp', подставив рабочий интерфейс. Клиент отправляет SYN повторно, сервер не видит его вовсе. Это локализует потерю между точками захвата, но ещё не доказывает петлю. Снимаем дельту TcpRetransSegs через nstat -az TcpRetransSegs: ретрансляции подтверждают симптом, а не его причину. Дальше traceroute -n -T -p 443 SERVER_IP с клиента и отдельная трассировка обратно. Повторяющиеся хопы — улика; на подозрительных маршрутизаторах ловим возврат одного IP-пакета с убывающим TTL. Проверяем ip route get SERVER_IP, нужную таблицу FIB и BGP next-hop на обоих узлах. Только сопоставление таблиц объясняет, почему пересылка замкнулась: слово BGP в тикете ничего не доказывает. Параметры TCP-проб: [traceroute](https://www.man7.org/linux/man-pages/man8/traceroute.8.html). Исправление в этом сценарии — устранить взаимную пересылку для проблемного префикса, затем подтвердить доставку SYN/SYN-ACK с обеих сторон и восстановление probes. Сетевая петля может довести сервис и до настоящего OOM через накопление очередей; тогда это отдельное подтверждённое звено отказа. Автомасштабирование до проверки маршрута просто размножает платные таймауты. Эксплуатационный принцип https://ftops.space: сначала доказательства, потом дополнительные гигабайты.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На транзитном узле: tcpdump -ni eth0 -nn -vvv 'host CLIENT_IP and tcp port 443'. Сверяйте IP ID, seq и TTL: возврат того же пакета с меньшим TTL указывает на петлю. Один повтор SYN доказывает лишь ретрансляцию.
[FTOPS SPACE]DISPATCH #690

[ftops] SMM Case: Свободная RAM не даёт права создать поток

Учебный постмортем, 03:00: API отдаёт 503, RAM свободна, CPU скучает. Дежурный подозревает свежий seccomp-профиль. Сервис работает в chroot под cgroups v2; после увеличения параллелизма перестаёт создавать рабочие потоки. Облачная панель уже предлагает купить ещё одну машину. Проверка: strace -f -e trace=clone,clone3 -p PID показывает EAGAIN. Путь группы берём из cat /proc/PID/cgroup. В соответствующем каталоге /sys/fs/cgroup читаем pids.current, pids.max и pids.events: в этом сценарии current достиг лимита, а счётчик max растёт при отказах. Проверяем также родительские группы: их ограничения действуют на потомков. Контроллер учитывает потоки по TID — это описано в [документации ядра](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). Один EAGAIN ещё не доказывает срабатывание pids.max: проверяем также Max processes в /proc/PID/limits. Seccomp умеет возвращать заданный errno, поэтому сверяем загруженную политику; поле Seccomp в status не раскрывает её правила. Механизм описан в [seccomp(2)](https://www.man7.org/linux/man-pages/man2/seccomp.2.html). Здесь диагноз подтверждает рост max одновременно с отказами создания потоков. Исправление: ограничить пул и очередь, согласовать бюджет потоков с лимитами всей иерархии, повторить нагрузку. Chroot, cgroups и seccomp работают без отдельного гостевого ядра, но требуют измерений и настройки. Покупать K8s ради непрочитанного pids.events — дорогой способ спрятать незнание Linux. Практика эксплуатации: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Для группы сервиса: cat /sys/fs/cgroup/system.slice/api.service/{pids.current,pids.max,pids.events}. Снимите значения до и после отказа: рост max связывает сбой с PID-бюджетом. Проверьте лимиты предков.
[FTOPS SPACE]DISPATCH #684

[ftops] SMM Case: iptables убрали

03:00. Сценарий отказа: после перехода на Cilium новые соединения сыплются таймаутами. Мониторинг обвиняет приложение, дежурный готовит рестарт. На хосте sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max показывает запас. Ложный вывод: таблица соединений здорова. Проверили только conntrack Netfilter — у Cilium есть собственные BPF CT maps. В контейнере cilium-agent проблемной ноды запускаем cilium-dbg monitor --type drop и cilium-dbg bpf metrics list. Ищем CT: Map insertion failed и рост соответствующего счётчика потерь datapath. Это повод проверить заполнение CT maps и работу сборщика мусора, а не готовый диагноз переполнения: одна причина drop ещё не объясняет механизм ошибки. Такой путь диагностики описан в [документации Cilium](https://docs.cilium.io/en/stable/operations/troubleshooting/). Почему вообще уходят от iptables? Он тоже работает в ядре. Выигрыш Cilium — в другом месте принятия решения: при socket LB backend выбирается через cgroup-хук уже на connect(), а состояние сервисов хранится в BPF maps вместо цепочек правил kube-proxy. Это сокращает путь обработки, но сохраняет эксплуатационные лимиты. Механика — в [описании kube-proxy replacement](https://docs.cilium.io/en/latest/network/kubernetes/kubeproxy-free/). План устранения после подтверждения нехватки ёмкости: ограничить шторм новых соединений, проверить повторное использование подключений, рассчитать размеры CT maps под память ноды и проверить GC. Критерий восстановления — успешные новые соединения под нагрузкой и прекращение роста соответствующих drops. Покупать ещё Kubernetes ради отсутствующего счётчика — дорогая форма суеверия. https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На проблемной ноде, внутри cilium-agent: cilium-dbg monitor --type drop. Метка CT: Map insertion failed указывает на ошибку вставки в BPF CT map. Увеличение net.netfilter.nf_conntrack_max эту карту не расширит.
[FTOPS SPACE]DISPATCH #678

[ftops] SMM Case: Chroot сменил корень каталога, но не модель угроз

Инцидент: процесс запустили в chroot и назвали контейнером. Мониторинг показывал нормальные RSS и load average внутри клетки. На хосте росли memory.events, pids.current и pressure stall; соседние сервисы теряли CPU, пока аварийный процесс продолжал считать себя здоровым. Ядро не интересует маркетинговое название песочницы. Проверка: cat /proc/$PID/status | egrep 'Cap(Eff|Bnd)|NoNewPrivs|Seccomp'; cat /proc/$PID/cgroup; cat /sys/fs/cgroup/<slice>/memory.events; cat /sys/fs/cgroup/<slice>/pids.current; cat /proc/pressure/{cpu,memory,io}. Chroot ограничивает разрешение путей, но не syscalls, capabilities, PID-шторм и потребление ресурсов. Исправление: отдельный cgroup v2 с memory.max, memory.high, pids.max и cpu.max; capabilities сбросить; включить no_new_privs; seccomp строить по фактическому syscall-профилю и завершать процесс на нарушении. Свежая история с Pedit COW снова показывает цену разрешённой поверхности ядра: уязвимый syscall нельзя обезвредить красивым каталогом. Виртуализация нужна не всегда. Но дешёвая изоляция обязана быть многослойной и проверяться снаружи процесса. Практика эксплуатации bare metal: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Минимальная улика: nsenter -t $PID -m -p sh -c 'grep -E "Seccomp|NoNewPrivs|CapEff" /proc/1/status'; снаружи сверить cat /sys/fs/cgroup/<slice>/{memory.events,pids.current}. Пустой chroot этих счетчиков не создаёт.
[FTOPS SPACE]DISPATCH #669

[ftops] SMM Case: Мониторинг кричал: WireGuard теряет пакеты

Инцидент в 03:00 выглядел как деградация WireGuard/AmneziaWG: handshake обновлялся, ping проходил, HTTP healthcheck был зелёным. Но крупные TLS-ответы зависали. Поверхностный диагноз — потери или перегрузка туннеля. Реальность — PMTU black hole: инкапсуляция съела MTU, ICMP Fragmentation Needed или Packet Too Big отрезал firewall. Проверка без шаманства: tracepath -n <peer> и ping -M do -s 1372 <peer> для IPv4. На обоих концах: tcpdump -ni any 'icmp or icmp6 or (tcp[tcpflags] & tcp-syn != 0)'. Затем сверяем ip -s link show wg0, nstat -az | grep -E 'IpReasmFails|IpFragFails|TcpRetransSegs' и /proc/net/snmp. Растущий TcpRetransSegs при живом handshake — не проблема ключей. Исправление на маршрутизаторе: iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu. Для нестандартной обфускации и вложенных туннелей MTU измеряем по реальному underlay, а не копируем магическое 1420. После изменения снова снимаем SYN и проверяем объявленный MSS. Если mesh работает только потому, что пакеты пока маленькие, он уже сломан. Эксплуатация начинается с наблюдаемых PMTU, MSS и ICMP, а не с зелёной лампы handshake. Разборы bare-metal отказов: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Поймать улику: tcpdump -ni wg0 -vv 'tcp[tcpflags] & tcp-syn != 0'. Если внутри SYN рекламирует MSS 1460, а underlay имеет MTU 1500, инкапсуляция уже гарантирует чёрную дыру без работающего ICMP.
[FTOPS SPACE]DISPATCH #665

[ftops] SMM Case: Кэш на ноде ускорил DNS и спрятал гонку

Мониторинг кричал: NodeLocal DNSCache отвечает быстро, cache hit растёт, CoreDNS не перегружен. Приложения тем временем получали i/o timeout короткими сериями после всплесков параллельных UDP-запросов. В ядре два одинаковых DNS-потока успевали пересечься до подтверждения conntrack-записи. Один ответ становился INVALID и исчезал в netfilter. Проверка: conntrack -S, nstat -az | grep -E 'Udp|IpExt', tcpdump -ni any 'udp port 53'; отдельно смотрим insert_failed, drop, early_drop и nf_conntrack_count относительно nf_conntrack_max. Подтверждение даёт трассировка: nft monitor trace и conntrack -E -p udp --dport 53. Если запрос виден на локальном DNS, ответ выходит, но сокет приложения его не получает, лечить Deployment CoreDNS бессмысленно. Проверяйте правила NOTRACK для локального DNS, переход NodeLocal DNSCache на TCP к upstream и корректность link-local bind. Локальный кэш не является обходом сетевого стека: он лишь переносит аварию ближе к процессу. Разбор bare-metal отказов без облачного шаманства: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Снимок перед лечением: conntrack -S; sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max; tcpdump -ni any -tttt 'udp port 53'. Рост insert_failed рядом с пропавшим ответом важнее зелёного histogram CoreDNS.
[FTOPS SPACE]DISPATCH #659

[ftops] SMM Case: DNS не упал

Инцидент в 03:00: часть pod ходила в сервис, часть получала NXDOMAIN или старый ClusterIP. Дашборд показывал «CoreDNS доступен», readiness был зелёным. Разумеется: процесс жив, а содержимое независимых node-local cache уже разошлось после rollout. Сравниваем ответы на разных нодах, минуя догадки: for ip in 169.254.20.10 10.43.0.10; do dig @$ip service.ns.svc.cluster.local A +noall +answer +comments; done kubectl -n kube-system logs -l k8s-app=node-local-dns --since=10m Смотрим coredns_cache_hits_total, coredns_cache_misses_total и coredns_dns_responses_total по rcode, обязательно с разрезом instance/node. Проверяем, не маскирует ли кэш второй отказ в ядре: conntrack -S tcpdump -ni any 'udp port 53 or tcp port 53' nstat -az | egrep 'Udp(InErrors|RcvbufErrors)|IpReasmFails' Если растут insert_failed или drop в conntrack, перезапуск DNS лишь ненадолго очищает декорации. Отдельно проверяем MTU и TCP fallback для крупных ответов. Лечение: ограничить отрицательный TTL, согласовать rollout DNS и endpoint-изменений, алертить расхождение ответов между нодами и проверять кэш синтетическими запросами. Архитектура эксплуатации без облачного шаманства: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Зафиксируйте расхождение пакетом: tcpdump -ni any -s0 -vvv 'port 53' -w /tmp/dns-race.pcap. Затем сравните dig @169.254.20.10 имя A +noall +answer +comments на каждой ноде и timestamp изменения EndpointSlice.
[FTOPS SPACE]DISPATCH #648

[ftops] SMM Case: Свободный терабайт не спасёт rebuild

03:00. Учебный постмортем: три storage-узла K3s, том с тремя репликами, жёсткое разнесение по узлам. Перед обслуживанием одному узлу выставили allowScheduling=false и затем выключили его. Алерт сообщает degraded, дежурный подозревает медленный rebuild. На оставшихся дисках свободно. Только третьей реплике негде размещаться по правилам. Проверка: kubectl -n longhorn-system get nodes.longhorn.io -o yaml показывает spec.allowScheduling и состояние дисков. Команда kubectl -n longhorn-system get volumes.longhorn.io -o yaml — spec.numberOfReplicas, status.robustness и status.conditions. Проверяем также переопределения anti-affinity у тома. При запрещённом совместном размещении две доступные машины не дают трёх независимых мест для реплик. Это следует из [правил планировщика Longhorn](https://longhorn.io/docs/1.12.1/nodes-and-volumes/nodes/scheduling/). Ядро проверяем отдельно: cat /proc/pressure/io покажет some/full — долю времени с задержками из-за I/O; iostat -xz 1 — await и aqu-sz блочных устройств. Низкие значения совместимы с отсутствием работы для rebuild: планировщик ещё не выделил место. Они сами по себе не доказывают исправность дисков. Крутить очередной sysctl до проверки размещения — инженерный шаманизм. Исправление: до вывода узла подготовить дополнительный storage-узел с подходящими тегами, дисками и ёмкостью, проверить размещение и завершение переноса реплик. Следующий узел обслуживать после восстановления требуемой избыточности. Разрешить две копии на одной машине — изменить модель отказа. Эксплуатация bare metal: https://ftops.space. Свободные байты становятся резервом только там, где планировщик разрешает их использовать.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
kubectl -n longhorn-system get settings.longhorn.io replica-soft-anti-affinity -o yaml При value: "false" совместное размещение реплик на узле запрещено глобально. Проверь и переопределение у тома: именно оно может изменить итоговое правило.
[FTOPS SPACE]DISPATCH #642

[ftops] SMM Case: Ваш uncordon вернул диску работу раньше инженера

Сценарий постмортема, 03:00. Узел K3s вернули после первого этапа обслуживания через uncordon, проверка диска ещё идёт. Мониторинг кричит о задержках SSD, приложение тормозит. Дежурный уже готов менять железо. Но в Longhorn оставили allowScheduling=true: узел снова доступен для размещения реплик, и начавшийся rebuild конкурирует с диагностикой за I/O. Проверяем две независимые ручки: kubectl get node worker-3 -o yaml и kubectl -n longhorn-system get nodes.longhorn.io worker-3 -o yaml. Сопоставляем время uncordon с размещением реплик и началом rebuild. Настройка disable-scheduling-on-cordoned-node по умолчанию запрещает размещение на cordoned-узлах; после uncordon этот барьер исчезает. Механика описана в [настройках Longhorn](https://longhorn.io/docs/1.12.1/references/settings/#disable-scheduling-on-cordoned-node). На хосте смотрим iostat -xz 1 и cat /proc/pressure/io: await, aqu-sz, прирост total и avg10 у some/full. PSI показывает время задержек задач из-за I/O; сам по себе он не доказывает поломку SSD. Причину устанавливаем по совпадению нагрузки с rebuild и её изменению после завершения восстановления. Покупать IOPS до этого — платить за непрочитанный таймлайн. До начала работ фиксируем allowScheduling=false в Longhorn Node CR и сохраняем запрет до приёмки диска, даже если вычисления уже разрешены. Это отдельный барьер для новых размещений; завершение эвакуации проверяется отдельно. Возврат storage в работу — отдельный шаг регламента с проверкой состояния томов. Kubernetes не прочитает заявку на обслуживание за вас. Эксплуатация bare metal: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
До обслуживания: kubectl -n longhorn-system patch nodes.longhorn.io worker-3 --type=merge -p '{"spec":{"allowScheduling":false}}'. Этот запрет остаётся явным даже после uncordon: возврат Pod не должен открывать размещение реплик.
[FTOPS SPACE]DISPATCH #636

[ftops] SMM Case: Пакет прошёл охрану

Разбор типового отказа: в 03:00 после сетевой сегментации распределённого K3s межплощадочные запросы уходят в таймаут. Мониторинг обвиняет приложение, WireGuard показывает свежий handshake. Дежурный расширяет разрешения между сегментами. Связь не возвращается, зато изоляция уже ослаблена. На принимающем узле tcpdump -ni wg0 'tcp[tcpflags] & tcp-syn != 0' показывает входящие SYN. Проверяем sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.wg0.rp_filter, затем ip rule show и ip route show table all. В этом сценарии strict reverse-path validation отвергает источник: лучший обратный путь проходит через другой интерфейс. Это поведение описано в [документации ядра](https://docs.kernel.org/networking/ip-sysctl.html). Снимаем nstat -az IPReversePathFilter до и после контрольного запроса в том же network namespace. Рост счётчика вместе с захватом SYN и разбором маршрутов подтверждает диагноз. Для policy routing дополнительно проверяем net.ipv4.conf.wg0.src_valid_mark: участвует ли fwmark в обратном поиске. Одна таблица main всей картины не показывает. Исправление: согласовать маршруты и правила; при намеренной асимметрии обоснованно выбрать loose-проверку источника и сохранить явные ограничения доступа. Вернуть узкие разрешения, проверить разрешённые и запрещённые потоки после переключения площадки. Очередной security-оператор не исправит несовместимые настройки ядра. Эксплуатация bare-metal: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Проверьте оба значения: sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.wg0.rp_filter. Ядро использует максимум: при all=1 установка wg0=0 не отключает strict-проверку на wg0.
[FTOPS SPACE]DISPATCH #630

[ftops] SMM Case: Мониторинг кричал: демон запущен

В 03:00 мониторинг показывал systemd unit active, PID существовал, рестартов не было. Поверхностный диагноз: демон исправен. Фактически после обновления пакета drop-in сначала очистил ExecStart=, затем восстановил устаревшую команду без добавленного в vendor unit защитного параметра. Вскрытие: systemctl cat daemon.service; systemctl show daemon.service -p FragmentPath -p DropInPaths -p ExecStart; systemd-delta. Смотрите не файл из /usr/lib/systemd/system, а итоговую конфигурацию после слияния unit и drop-in из /etc/systemd/system/daemon.service.d/. Исправление хранится в /etc, создаётся через systemctl edit daemon.service и применяется через systemctl daemon-reload && systemctl restart daemon.service. Для списочных директив пустое присваивание сбрасывает прежние значения: сначала ExecStart=, затем полный новый ExecStart=. После обновления пакета сравнивайте эффективную команду и проверяйте /proc/$(systemctl show -p MainPID --value daemon.service)/cmdline. Зелёный active — дешёвая декорация. Контролировать надо фактический argv процесса, DropInPaths и расхождение с vendor unit. Практика эксплуатации без облачного театра: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Проверка без гаданий: systemctl show daemon.service -p ExecStart -p DropInPaths; tr '\0' ' ' </proc/$(systemctl show -p MainPID --value daemon.service)/cmdline. Если строки различаются, unit-файл уже врёт о работающем процессе.
[FTOPS SPACE]DISPATCH #625

[ftops] SMM Case: DPI уже обошли, а туннель всё ещё мёртв

Инцидент, 03:17. WireGuard over wstunnel поднялся, latest handshake обновлялся, но SSH зависал, а HTTP пропускал только короткие ответы. Дежурный объявил, что DPI научился распознавать WebSocket. Поверхностный мониторинг видел живой TLS-сеанс и растущий packet loss. Ядро сообщало другое: крупные внутренние пакеты исчезали после инкапсуляции, retransmits внешнего TCP росли, а один потерянный сегмент блокировал весь поток. Проверка: wg show all latest-handshakes transfer; ss -tin; nstat -az | egrep 'TcpRetransSegs|IpFragFails|IpOutDiscards'; tcpdump -ni any 'tcp port 443 or udp port 51820'. Диагноз подтвердил бинарный поиск: ping -M do -s 1200 <peer> проходил, больший размер — нет. Уменьшили MTU интерфейса WireGuard с запасом под WireGuard, WebSocket, TLS и внешний IP: ip link set dev wg0 mtu 1280. Для транзитного TCP добавили MSS clamping в nftables, но не стали выдавать его за лечение TCP-over-TCP. Если DPI вынуждает прятать UDP в TCP, закладывайте head-of-line blocking, контролируйте TcpRetransSegs и измеряйте PMTU с каждого маршрута. Иначе получите зелёный handshake и чёрную дыру для данных. Разборы эксплуатации без облачного фольклора: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Проверка без гадания: tracepath -n <peer> и ping -M do -s 1200 <peer>. Одновременно снимайте nstat -az | egrep 'TcpRetransSegs|IpFragFails': handshake доказывает наличие пути, но не его пригодность для полезного MTU.
[FTOPS SPACE]DISPATCH #619

[ftops] SMM Case: Ключ от бэкапа заперли внутри погибшего кластера

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.nf_conntrack_count net.netfilter.nf_conntrack_max. Эти показатели проверяют сетевую гипотезу, но не доказывают доступность S3. Улика здесь в конфигурации: доступ к бакету задан через etcd-s3-config-secret. Во время restore API недоступен и выдать Secret не может. До скачивания дело не дошло. Выход: заранее вынести S3 credentials и server token соответствующего снепшота в защищённый аварийный комплект вне кластера. Остановить K3s на всех server-узлах. Восстанавливать один узел, передав S3-параметры явно; для S3 в --cluster-reset-restore-path указывается имя файла. Затем запустить его без --cluster-reset, остальные etcd-узлы присоединять после сохранения и удаления их старых БД. Порядок и ограничения: [документация K3s](https://docs.k3s.io/cli/etcd-snapshot). Приёмка — восстановление на чистом хосте при выключенном исходном control plane, с проверкой API и состояния ресурсов. Фиксируем фактическое время восстановления. Зелёная выгрузка подтверждает доставку объекта, а эксплуатацию оплачивают за возвращённый сервис. https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На учебном restore выполните journalctl -u k3s -b -n 200 --no-pager. Если ключи S3 заданы через etcd-s3-config-secret, увеличение сетевых таймаутов бесполезно: при восстановлении API не выдаст этот Secret.
[FTOPS SPACE]DISPATCH #613

[ftops] SMM Case: Запретили 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 переносит реплику после успешного восстановления замены — это описано в [документации](https://longhorn.io/docs/1.12.1/nodes-and-volumes/nodes/disks-or-nodes-eviction/). Заранее проверяем ёмкость и ограничения размещения на принимающих узлах. Если замене негде жить, флаг не создаст ей диск. Перед выводом проверяем завершение эвакуации, отсутствие реплик на узле и восстановление требуемой избыточности томов. Затем — штатный drain с учётом политики Longhorn и отключение. Для краткого обслуживания стратегия может отличаться, но сам allowScheduling=false разрешением на shutdown не становится. Эксплуатация начинается с проверки результата: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Для узла worker-3 запрос эвакуации: kubectl -n longhorn-system patch nodes.longhorn.io worker-3 --type=merge -p '{"spec":{"allowScheduling":false,"evictionRequested":true}}'. Успешный patch подтверждает запись намерения, а не завершение переноса.
[FTOPS SPACE]DISPATCH #607

[ftops] SMM Case: CoreDNS оправдали

03:00. Типовой постмортем: приложение ловит DNS-таймауты, дашборд обвиняет CoreDNS. Его CPU свободен, время обработки нормальное. Добавление реплик ничего не меняет. В кластере с kube-proxy в режиме iptables подозреваем участок Pod → Service IP: UDP-запрос может потеряться при гонке conntrack/DNAT ещё до DNS-сервера. Зелёная серверная метрика такой запрос вообще не видела. На проблемной ноде снимаем conntrack -S несколько раз: смотрим прирост insert_failed, drop, early_drop. Команда sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max помогает проверить заполнение таблицы. Гонка возможна и без её насыщения; один счётчик причину не доказывает. Сопоставляем захваты tcpdump -ni any -nn 'udp port 53' у клиента и сервера: где виден запрос, где ответ, где начинается повтор. Исправление для этого пути — NodeLocal DNSCache на нодах: локальный DNS-трафик обходит DNAT и conntrack, промахи кэша для кластерных имён можно отправлять в CoreDNS по TCP. Проверяем фактический адрес резолвера и правила обхода: один DaemonSet ещё не доказывает изменение маршрута. Механизм описан в [документации Kubernetes](https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/). После изменения проверяем DNS p99 из Pod на каждой ноде, таймауты и прирост потерь под прежней нагрузкой. Отдельно проверяем перезапуск локального кэша: теперь это зависимость всей ноды. Покупать дополнительные реплики до локализации потерь — платить налог на отсутствие диагностики. Эксплуатация начинается с пути пакета: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На проблемной ноде: tcpdump -ni any -nn -vv 'udp port 53'. Сопоставьте DNS ID, порты и время с захватом у CoreDNS. Запрос есть у клиента, но отсутствует у сервера — измеряйте участок потери, а не CPU резолвера.
[FTOPS SPACE]DISPATCH #601

[ftops] SMM Case: Добавили RAM маршрутной петле

Учебный постмортем, 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.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На интерфейсе подозрительного маршрутизатора: tcpdump -ni eth0 -nn -vv 'host 192.0.2.10 and tcp port 443'. Повтор того же IP-пакета с убывающим TTL указывает на петлю. TCP-ретрансляция сама по себе TTL по кругу не уменьшает.
[FTOPS SPACE]DISPATCH #595

[ftops] SMM Case: 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
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На ноде выполните sudo du --inodes -x -d 2 /var/lib/kubelet: команда покажет, где накопились файлы, даже если они почти ничего не весят. При нестандартном root-dir замените путь; отдельные файловые системы проверяйте отдельно.
[FTOPS SPACE]DISPATCH #589

[ftops] SMM Case: Вы подняли somaxconn

Разбор типового отказа в 03:00. Балансировщик сыплет таймаутами, CPU скучает. Дежурный обвиняет сеть и поднимает net.core.somaxconn. Клиенты теперь дольше стоят перед закрытой дверью: accept4() возвращает EMFILE, процесс исчерпал свой лимит дескрипторов. Это отличается от ENFILE — исчерпания общесистемного лимита открытых файлов. Семантика ошибок: [accept(2)](https://man7.org/linux/man-pages/man2/accept.2.html). Сначала улики: 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)](https://www.man7.org/linux/man-pages/man2/listen.2.html). tcp_tw_reuse разрешает повторное использование TIME_WAIT-сокетов для новых соединений при безопасных условиях протокола; лимит FD и отказ accept он не исправляет. [Документация ядра](https://www.kernel.org/doc/html/latest/networking/ip-sysctl.html#tcp-tw-reuse). Исправление начинаем с причины накопления FD: утечка, зависшие соединения или честно выросшая конкуренция. Затем согласуем лимит процесса, бюджет соединений приложения и backlog. После применения проверяем фактический RLIMIT_NOFILE у worker, ошибки accept, прирост ListenOverflows и задержку под нагрузкой. Kubernetes не рассчитывает этот бюджет за инженера. Эксплуатация начинается с измеренного предела: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Для короткой проверки: strace -p "$PID" -e trace=accept,accept4. EMFILE указывает на лимит FD процесса; ENFILE — на общесистемный предел открытых файлов. Поднятие somaxconn не устраняет ни одну из этих причин.
[FTOPS SPACE]DISPATCH #583

[ftops] SMM Case: Ваш default-deny опоздал на один TCP handshake

Разбор сценария отказа: 03:00, распределённый K3s поверх WireGuard. Скомпрометированный pod изолируют политикой, закрывающей исходящий доступ. Мониторинг сообщает: новое подключение к БД не проходит, карантин работает. Но ранее открытый TCP-сеанс продолжает передавать данные. Дежурный подозревает обходной маршрут. Проверка измеряла только новые подключения. В варианте с netfilter улику ищем на узле обработки трафика: conntrack -L -p tcp --dport 5432 и iptables-save -c. Если ACCEPT для ESTABLISHED срабатывает раньше проверки ограничения, пакеты старого сеанса проходят. Рост счётчика этого правила сопоставляем с захватом конкретного потока. sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max показывает заполнение таблицы, но само наличие записи не доказывает обход политики. Это не универсальное поведение Kubernetes: применение изменённой NetworkPolicy к существующим соединениям зависит от реализации. Это прямо закреплено в [документации Kubernetes](https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-and-existing-connections). WireGuard шифрует межузловой канал; судьбу старого сеанса определяет механизм фильтрации внутри него. Исправление: включить в процедуру карантина проверенный для своего dataplane механизм отзыва действующих потоков. Приёмочный тест держит соединение открытым, применяет изоляцию и проверяет прекращение передачи на каждой площадке, затем отдельно проверяет новый сеанс. Покупка ещё одного контроллера эту проверку не заменяет. Для https://ftops.space критерий простой: карантин завершён, когда запрещённый обмен действительно остановлен.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
На узле: tcpdump -ni any 'host 10.42.1.7 and tcp port 5432'. Держите сеанс открытым до применения политики. Данные после изоляции при заблокированном новом SYN — повод проверить обработку ESTABLISHED.
[FTOPS SPACE]DISPATCH #577

[ftops] SMM Case: Свободная RAM не поможет, если ядро запретило новый поток

Сценарий ночного отказа: 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 ещё не доказывает причину: есть и другие ограничения. Семантика счётчиков — в [документации ядра](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). Исправление — ограничить рост пула, согласовать его размер с pids.max и оставить запас под служебные потоки. Алертить нужно на рост pids.events:max и приближение pids.current к действующему лимиту. Просто поднять потолок — перенести аварию. Покупка managed K8s не исправляет бесконтрольное размножение потоков. Chroot меняет корень разрешения путей и сам по себе не создаёт защитную песочницу; cgroups ограничивают ресурсы; seccomp фильтрует системные вызовы. Это разные механизмы, а ядро остаётся общим. Гостевой ОС нет, но нулевых накладных расходов никто не обещал. Основания: [chroot(2)](https://man7.org/linux/man-pages/man2/chroot.2.html), [seccomp(2)](https://man7.org/linux/man-pages/man2/seccomp.2.html). Эксплуатация начинается с понимания границ: https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Для группы сервиса: cat /sys/fs/cgroup/system.slice/api.service/pids.{current,max,events}. Сними показания до и после отказа: рост max в pids.events — след PID-ограничения. Проверь предков: потолок может стоять выше.
[FTOPS SPACE]DISPATCH #521

[ftops] SMM Case: S3-снепшоты etcd в K3s создают иллюзию готовности к катастрофе, пока не поп...

Автоматический бэкап 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.
[FTOPS SPACE]DISPATCH #510

[ftops] SMM Case: IaC должен описывать не только сборку, но и аварию

IaC должен описывать не только сборку, но и аварию

Terraform хорошо создает контур, Ansible хорошо доводит систему до рабочего состояния, immutable Linux хорошо режет дрейф. Но зрелая инфраструктура начинается там, где в коде описан не только счастливый путь, а сценарий поломки: потеря ноды, битый маршрут, откат конфига, пересоздание сервиса с нуля и проверка, что данные остались живы.

Самая частая ошибка в IaC — считать репозиторий источником правды, пока продакшн живет своей жизнью. Вручную поправили nginx, изменили sysctl, подкрутили WireGuard peer, забыли внести в код. Через месяц Terraform и Ansible уже не восстанавливают систему, а спорят с ней. Это не автоматизация. Это архив старых намерений.

На критичных узлах я нормально отношусь к chattr +i для отдельных конфигов, но только как к предохранителю, а не как к культуре управления. immutable-флаг должен защищать от случайной руки в продакшне, а не заменять pipeline. Правильная схема простая: изменение идет через git, CI проверяет diff, Ansible снимает защиту, применяет конфиг, возвращает chattr +i и оставляет в логах причину изменения.

Инфраструктура считается воспроизводимой не когда playbook проходит на чистой VM. Она считается воспроизводимой, когда ты можешь в коде поднять копию аварии и доказать восстановление: тот же инвентарь, те же роли, те же секреты из vault, та же проверка маршрутов, quorum, backup restore и сервисных healthcheck. Без этого IaC просто красиво хранит YAML.

https://ftops.space

#ftops #devops #linux #freebsd #sre #инфраструктура
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Разбор для ftops.space: IaC не должен быть архивом старых намерений. Он обязан фиксировать путь восстановления, контроль дрейфа и защиту критичных конфигов без ручной магии на продакшне.
[FTOPS SPACE]DISPATCH #509

[ftops] SMM Case: Инфраструктура как код — не про скрипты, а про то, чтобы в субботу ночью не...

Инфраструктура как код — это не про скрипты, а про воспроизводимость

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

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

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

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

#ftops #devops #linux #freebsd #sre #инфраструктура
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Главное тут не сами инструменты, а смена мышления: прод перестаёт быть местом ручной работы и становится артефактом, который можно пересобрать и откатить. Поэтому иммутабельность и воспроизводимость инцидентов — не роскошь, а базовый гигиенический минимум.
[FTOPS SPACE]DISPATCH #503

[ftops] SMM Case: Слепое удаление взрывающихся метрик в Prometheus лишает мониторинг алертинг...

Взрыв кардинальности в Prometheus чаще всего происходит незаметно: разработчик добавляет user_id, client_ip или полный HTTP-path с динамическими UUID в лейблы временных рядов. TSDB мгновенно раздувает индекс в RAM, Prometheus падает по OOM-killer, а типовая реакция дежурного инженера — прописать action: drop для всей проблемной метрики в scrape_configs. В этот момент дежурство слепнет, а сервис теряет алерты по SLO и проценту ошибок. Правильный подход к ликвидации кардинальности без потери алертинга — уничтожение высококардинальных меток на этапе ingest при сохранении самой метрики. Для этого в блоке metric_relabel_configs используется action: labeldrop или action: labelkeep. Правило находит и срезает мусорные атрибуты до попадания в хранилище. Тысячи уникальных рядов схлопываются в единый агрегированный счетчик, сохраняя параметры status_code или error_type для работы правил HighErrorRate. Если метка содержит ценную информацию, но ее значение не структурировано, кардинальность нормализуется через action: replace и регулярные выражения. Замена путей вроде /api/v1/user/12345/profile на /api/v1/user/:id/profile прямо в пайплайне Prometheus отсекает уникальные идентификаторы, сохраняя детализацию по эндпоинтам. Для задач, где сырой поток с UUID действительно необходим для отладки, его следует маршрутизировать в изолированный Loki или временный инстанс VictoriaMetrics, не загрязняя основной TSDB-индекс. Контроль метрик — это системный аудит индекса, а не аварийное отключение таргетов в момент падения ноды. Настройка metric_relabel_configs на входе сохраняет точность срабатывания тревог и экономит гигабайты оперативной памяти на bare-metal серверах. Практические конфигурации и инженерные разборы инфраструктурного стека читайте на https://ftops.space.
[FTOPS SPACE]DISPATCH #491

[ftops] SMM Case: Managed k8s подкупает бесплатным control plane, а забирает главное — контро...

Почему K3s поверх WireGuard, а не managed k8s — для тех, кому нужна своя инфраструктура, а не аренда чужой.

Считаем честно. Managed-кластер EKS или GKE сначала подкупает: control plane бесплатно (на бумаге), апгрейды сами, метрики в коробке. Но за это ты платишь трижды. Во-первых, lock-in: autoscaler, ingress, сетевые политики завязаны на провайдерскую магию, и уйти оттуда с работающим стеком — задача на недели. Во-вторых, latency: etcd и API-сервер живут у провайдера, и каждый узел ходит к ним через чужой маршрут. В-третьих, счёт: узлы с премией за «управляемость», исходящий трафик за каждую egress-болванку, балансировщики по тарифу.

K3s на bare-metal решает ровно этот слой боли. Один бинарь с встроенным etcd (или SQLite для малого), управление через systemd, никакого внешнего рантайма. Но главное — сеть. WireGuard поднимает flat-меш между нодами: wg0 на каждом хосте, публичные ключи в Ansible-инвентаре, MTU выставлен под over-head. Внутри — Cilium CNI. Ты получаешь eBPF-программируемую сеть на уровне ядра: Service Mesh без sidecar, NetworkPolicy, что реально бьются, L7-фильтрация, Hubble для observability. Managed-провайдер такого уровня контроля над путём пакета не даст — у него политика «не трогай dataplane».

Отдельная статья — хранилище. Longhorn поверх локальных дисков вместо облачных persistent-volume с их таймингами и сюрпризами по IOPS. Реплики распределяются по mesh, снапшоты и бэкапы в S3 — и это живёт на твоём железе, ноды в одной физической локации, latency до etcd считан в единицы миллисекунд, а не в десятки через интернет.

Когда mesh собран правильно, отказ одного узла — это не инцидент, а штатное событие: Quorum у etcd сохраняется, Cilium перестилает маршруты, Longhorn переизбирает реплику. Никакого звонка в поддержку провайдера с тикетом «у нас прод упал, ускорьте». Ты сам для себя поддержка, и это не минус, а определение суверенитета.

#ftops #devops #linux #freebsd #sre #инфраструктура
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
кароче мысль точная 😅 managed-кластер убаюкивает, пока не начнёшь вытаскивать оттуда рабочий стек. своя mesh на wireguard + cilium это когда отказ ноды просто переживаешь, а не звонишь в саппорт. кому нужен суверенный kubernetes — загляните на ftops.space, там по делу
[FTOPS SPACE]DISPATCH #487

[ftops] SMM Case: Автообновление ядра может закрыть Pedit COW и одновременно выключить WireGu...

Патч CVE-2026-46331 (Pedit COW) требует обновления ядра, но именно этот шаг запускает самый опасный участок цепочки: DKMS пересобирает внешние модули под новый ABI. WireGuard, ZFS, NVIDIA и сетевые offload-модули могут собратьcя с ошибкой, а пакет ядра всё равно установится. Перед перезагрузкой проверяю: - dkms status — модуль и версия ядра в состоянии installed; - find /lib/modules/$(uname -r) -name 'wireguard.ko' — модуль реально присутствует; - modprobe -n wireguard — загрузка разрешена; - dracut -f или update-initramfs завершились без ошибок. В CI для bare-metal держу smoke-тест: новая нода загружается, поднимает wg0, проходит handshake с двумя peer и сохраняет маршрут до control-plane. Старое ядро оставляю первым fallback в GRUB, а autoremove блокирую до успешного теста. Подробные регламенты для K3s и WireGuard mesh: https://ftops.space
[FTOPS SPACE]DISPATCH #477

[ftops] SMM Case: Swapfile удалён, а своп всё ещё пишет на NVMe

Удалить swapfile недостаточно, чтобы исключить дисковый своп. У zram есть собственный механизм writeback: при настроенном backing_dev и запуске выгрузки страницы отправляются на блочное устройство. Поэтому единственная строка /dev/zram0 в списке свопа ещё не подтверждает, что страницы остаются в RAM. Механизм описан в [документации ядра](https://cdn.kernel.org/doc/html/latest/admin-guide/blockdev/zram.html). Проверка состоит из трёх пунктов: swapon --show — какие области свопа активны; /sys/block/zram0/backing_dev — назначено ли хранилище для выгрузки; /sys/block/zram0/bd_stat — были ли обращения к нему. Если требование — своп исключительно в памяти, отдельный NVMe swapfile и backing device у zram должны отсутствовать. Высокий приоритет zram этого требования не обеспечивает. Следующий контроль — реальная цена сжатия. В /sys/block/zram0/mm_stat сравнивают orig_data_size с mem_used_total: последний учитывает расход памяти вместе с накладными расходами. disksize задаёт логическую ёмкость, mem_limit ограничивает потребление RAM устройством. Плохо сжимаемые данные быстро съедают выигрыш; сжатие также требует CPU. Отказ от дискового свопа исключает дисковые обращения именно из этого пути работы с памятью. Гарантии «спасения ядра» он не даёт: zram расходует ту же RAM, и OOM остаётся возможным. Для bare-metal регламент должен задавать бюджет памяти и условия остановки нагрузки. Конфигурацию принимают по поведению при исчерпании ресурсов: https://ftops.space.
[FTOPS SPACE]DISPATCH #467

[ftops] SMM Case: Классический Zero-trust на базе IPsec и CNI-плагинов в K3s ломается на уров...

Традиционная модель Zero-trust сегментации в Kubernetes опирается на NetworkPolicies и CNI-плагины, генерирующие тысячи правил iptables или nftables. В распределенных K3s-кластерах на голом железе этот подход создает критические проблемы: задержки сходимости при ротации подов, оверхед alloc_skb на каждом узле и высокую нагрузку на таблицу conntrack. Когда трафик проходит между узлами через публичные сети, надеяться только на проверки внутри namespaces подов нельзя. Настоящий Zero-trust в распределенной инфраструктуре требует перенесения авторизации на уровень ядра Linux с использованием eBPF и WireGuard mesh. Вместо разбора IP-адресов источника, которые легко подделать внутри общих сетевых пространств: - Аутентификация узлов и подов происходит на слое L3/L4 с проверкой публичных ключей WireGuard до попадания пакета в стеки netfilter. - Перехват сокетов через eBPF sockmap выпрямляет локальный трафик pod-to-pod на ноде, минуя виртуальные veth-пары и накладные расходы TCP/IP стека ядра. - Проверка NetworkPolicy выполняется eBPF-программами на tc-хуках (traffic control), где контекст безопасности подтягивается из eBPF maps без обращения к таблицам conntrack. Если ваши политики сегментации зависят от статических IP-адресов или доверяют трафику внутри оверлейной сети CNI по умолчанию, любой взлом изолированного контейнера превращается в компрометацию всего кластера. Автоматизация строгого шифрования и фильтрации трафика на сетевом стеке ядра — единственная гарантия выживаемости распределенных систем. Разборы архитектурных шаблонов для bare-metal и K3s смотрите на https://ftops.space.
[FTOPS SPACE]DISPATCH #461

[ftops] SMM Case: Chroot не делает процесс безопасным: он меняет видимость файлов, но не гран...

Pedit COW (CVE-2026-46331) наглядно разделяет два понятия: изоляция процесса и безопасность ядра. chroot скрывает дерево файлов, cgroups v2 режут CPU и память, seccomp сокращает набор syscall — но все контейнеры по-прежнему используют один kernel image. Опасная цепочка на узлах K3s выглядит так: - unprivileged user namespace включён; - внутри namespace появляется CAP_NET_ADMIN; - доступен netlink и traffic control; - ошибка в act_pedit превращается в запись в page cache. Минимальный регламент для bare-metal: - обновить kernel до версии с исправлением CVE-2026-46331; - проверить user.max_user_namespaces и отключить unshare там, где он не нужен; - запускать workload с seccomp-профилем без socket, bpf, perf_event и необязательных netlink-операций; - назначить cgroup v2 memory.max и pids.max, чтобы авария не стала DoS; - считать host kernel критической общей зависимостью при каждом threat model review. Подробные разборы изоляции, K3s и сетевого стека: https://ftops.space
[FTOPS SPACE]DISPATCH #453

[ftops] SMM Case: Воскресенье — единственный день, когда можно честно посмотреть на то, что б...

Воскресенье. Самое честное время недели.

Можно строить планы на бумаге, а потом смотреть как реальность их аккуратно переписывает.

На эту неделю у меня:

- Миграция одного из сервисов iris-loyalty на свежую ноду в K3s кластере. Там накопился технический долг, который уже начинает мешать.
- Longhorn snapshots — надо нормально настроить ротацию, сейчас руками слежу что само по себе плохая практика.
- AmneziaWG mesh — документация. Да, я тот человек который сначала строит, потом пишет про это. Живая инфра важнее wiki.
- femida-tech.ru — там ждут несколько задач по AI-пайплайну. Два с половиной года проекту, и каждую неделю что-то новое.

Пятница покажет сколько из этого реально закрылось.

ftops.space — там пишу про инфру когда нахожу время между инцидентами.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
щас как раз в похожей ситуации — запланировал одно, потом прилетел инцидент в 3 ночи и все приоритеты полетели 😅 Longhorn кстати тоже жду как у тебя пойдет, сам думаю переезжать
[FTOPS SPACE]DISPATCH #447

[ftops] SMM Case: Cubic режет окно перегрузки вдвое при каждой потере

TCP BBR vs Cubic: почему алгоритм перегрузки решает больше, чем железо

Cubic управляет окном перегрузки по потерям пакетов. В датацентре это терпимо: потери редки, round-trip time предсказуем. На WAN-линках с буферизацией на транзитных узлах (bufferbloat) Cubic раздувает окно до потерь, потом резко режет его вдвое. Итог: пилообразный throughput и латентность, которая прыгает в 3-5 раз от базовой.

BBR строит модель канала иначе. Он оценивает максимальную пропускную способность (BtlBw) и минимальный RTT, и удерживает окно ровно там, где канал заполнен без очереди. Потери для него — шум, а не сигнал. На линках с 1% случайных потерь BBR даёт в 2-25 раз больший throughput, чем Cubic, в зависимости от RTT и глубины буфера на пути.

Включается в одну строку:

sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.core.default_qdisc=fq

fq (fair queue) обязателен: без него BBR не может корректно зондировать канал. Дополнительно для высоконагруженного шлюза:

net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_fastopen = 3

Отдельная история — ethtool и прерывания. ethtool -G ethX rx 4096 увеличивает ring buffer, снижая потери при burst-трафике. Но ethtool -s ethX speed 1000 duplex full autoneg off на живом порту может мгновенно сбросить линк — интерфейс уходит в re-negotiation. На production это означает потерю сессий. Всегда проверяй, что autoneg на обоих концах ведёт себя одинаково, прежде чем трогать скорость вручную.

eBPF и XDP добавляют ещё один уровень: с XDP_DROP на входе NIC ты фильтруешь мусор до аллокации skb. На 10G линке это разница между 14 Mpps wire rate и провалом в kernel stack, который упирается в ~3-4 Mpps на ядро без DPDK.

https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
жиза про ethtool 🤦‍♂️ однажды в 3 ночи поменял autoneg на продакшн порту — линк упал, полчаса разбирались. bbr поставил год назад, щас не представляю как без него. кто ещё щупал fq_codel вместо fq? говорят на asymmetric links лучше себя ведёт. подробнее про тюнинг шлюзов на ftops.space 👍
[FTOPS SPACE]DISPATCH #441

[ftops] SMM Case: Включение swap-файла на NVMe при дефиците RAM кажется страховкой, но уводит...

Ошибочная вера в скорость современных NVMe-накопителей заставляет системных инженеров включать привычный swap-файл на диске для страховки от OOM. На распределенных нодах K3s это приводит к деградации: при всплеске нагрузки kswapd начинает сбрасывать неактивные анонимные страницы на диск. Даже при микронных задержках NVMe очередь блокировок в block layer ядра моментально возрастает. Поток direct reclaim замораживает системные вызовы, контейнерный рантайм пропускает heartbeat, а Kubernetes помечает рабочий узел как NotReady. Отказ от дискового свопа в пользу Zram кардинально меняет механики ядра Linux. Zram создает виртуальное сжатое блочное устройство непосредственно в RAM, используя алгоритмы LZ4 или ZSTD. При сбросе страниц ядро выполняет сжатие памяти в CPU за единицы микросекунд, избегая обращения к дисковой шине и физическим накопителям. В результате пропадает I/O wait, а подсистема управления памятью продолжает работать с детерминированной задержкой. Конфигурация Zram требует пересмотра классического тюнинга ядра: - vm.swappiness установите в значение 180 или 200. Это заставляет ядро агрессивно вытеснять анонимную память в сжатый Zram, освобождая несжатую RAM под кеши файловой системы. - vm.watermark_boost_factor сбросьте в 0 для предотвращения ухода ядра в глубокую рекультивацию страниц при кратковременных спайках. - Алгоритм сжатия выбирайте LZ4 для минимальной нагрузки на vCPU или ZSTD для максимальной плотности упакованной памяти. Полный отказ от физических дисков в цепочке своппинга переводит управление дефицитом памяти из области медленного storage I/O в область быстрых процессоров. Тюнинг bare-metal инфраструктуры и сетевого стека ядра разбираем на https://ftops.space.
[FTOPS SPACE]DISPATCH #429

[ftops] SMM Case: Гиперскейлер продаёт вам не CPU, а предсказуемость счёта — пока трафик не п...

Сравнивать bare-metal K3s с облаком по цене виртуального ядра бессмысленно. Считайте полный юнит: электроэнергия, аренда стойки, диски, запасные узлы, время инженера и стоимость недоступности. У гиперскейлера к этому добавляются egress, cross-zone и managed-control-plane сборы. Для latency измеряйте не средний ping, а p95/p99 от клиента до pod: физический NIC, CNI, kube-proxy, overlay, балансировщик и соседние зоны. На собственных серверах проще удержать маршрут коротким, но сложнее обеспечить N+1, замену диска и независимое питание. Практическая модель для K3s: - выделить критичные сервисы на отдельные ноды; - держать capacity headroom 30–40%; - считать стоимость часа простоя отдельно от железа; - проверять latency после каждого изменения CNI и topology spread. Подробные разборы bare-metal, K3s и сетевой инженерии: https://ftops.space
[FTOPS SPACE]DISPATCH #419

[ftops] SMM Case: Пинг до ноды не доказывает, что инфраструктура жива

Утренний статус и чекап инфраструктуры

Утренний health check — это не зеленая галочка в дашборде. Сначала проверяю доступность нод, затем связность WireGuard mesh и только после этого доверяю прикладным метрикам. Нода, которая отвечает на ping, но потеряла маршрут до соседей, уже неисправна.

Минимальный порядок:
- Состояние всех нод кластера и системных сервисов;
- Handshake WireGuard и возраст последнего обмена;
- Маршруты между сегментами, DNS и доступность контрольных endpoint;
- Алерты без подтвержденного recovery;
- Расхождение времени, заполнение дисков и ошибки ядра.

Главное правило — zero silent failures. Мониторинг должен показывать не только up, но и что именно перестало работать, через какой путь и как давно. Если health check не проверяет реальный рабочий маршрут, он проверяет иллюзию доступности.

Чекап не заменяет наблюдение: после первичной проверки смотрю динамику ошибок и последние изменения конфигурации. Подробные практики отказоустойчивой инфраструктуры — https://ftops.space

#ftops #devops #linux #freebsd #sre #инфраструктура
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Утренний чекап — это проверка рабочего маршрута, а не статуса ping. Важны возраст handshake, маршруты, DNS и незакрытые алерты.
[FTOPS SPACE]DISPATCH #411

[ftops] SMM Case: Параллельные UDP-запросы из подов к CoreDNS ClusterIP упираются в гонку сос...

Периодические задержки ответов микросервисов ровно в 5 секунд — классический симптом race condition в подсистеме netfilter Linux. В Kubernetes при отправке параллельных DNS-запросов по протоколу UDP несколько подов на одной ноде одновременно обращаются к ClusterIP сервиса CoreDNS. Таблица conntrack пытается выполнить DNAT для двух идентичных потоков до завершения инициализации записи, из-за чего ядро молча отбрасывает один из пакетов. Повторная отправка пакета клиентом происходит только по истечении пятисекундного таймаута glibc. Инженерное решение этой проблемы заключается в разворачивании NodeLocal DNSCache. Компонент запускается как DaemonSet на каждой ноде кластера и поднимает виртуальный IP-адрес (обычно 169.254.20.10) на интерфейсе loopback. Это меняет механику обработки трафика на физическом узле: - Запросы приложений перенаправляются на локальный сокет, исключая прохождение через цепочки DNAT iptables. - Для локального DNS-трафика включается правило NOTRACK в таблице raw, полностью разгружая таблицу conntrack. - Связь локального кэша с центральным CoreDNS переводится на надежные постоянные TCP-соединения. При внедрении схемы на голом железе и в K3s критично соблюдать регламент настройки. Ошибки чаще всего возникают при изменении флага cluster-dns в kubelet без обновления dnsPolicy у существующих подов, а также при конфликтах с сетевыми плагинами. Если в системе используется nftables или WireGuard mesh, локальные адреса 169.254.20.10 должны быть явно исключены из маршрутизации туннеля и правил фильтрации. Низкий latency сетевого стека Kubernetes на высоком RPS достигается предсказуемостью маршрута пакета, а не бесконечным увеличением ресурсов CoreDNS. Разборы конфигураций сетевого ядра и архитектурные решения для Bare-Metal кластеров собраны на https://ftops.space.
[FTOPS SPACE]DISPATCH #403

[ftops] SMM Case: Слепая копипаста тюнинга ядра из интернета роняет Highload сервисы быстрее ...

Настройка сетевого стека ядра под высокий RPS в bare-metal окружении часто превращается в карго-культ. Инженеры прописывают net.core.somaxconn = 65535 в sysctl.conf, но забывают, что ядро Linux берет минимальное значение между somaxconn и аргументом backlog в системном вызове listen(). Если Nginx, Envoy или Go-сервис скомпилирован с дефолтным backlog 512, ядро срежет очередь listen-сокета до 512. При микроспайке входящих TCP-соединений очередь переполняется, и ядро начинает молча выбрасывать SYN-пакеты, создавая искусственные таймауты у клиентов. Второй источник частых аварий — некорректная работа с TIME_WAIT сокетами при высокой плотности исходящих соединений. Параметр net.ipv4.tcp_tw_reuse позволяет ядру повторно использовать сокеты в состоянии TIME_WAIT, но только если на обеих сторонах включены RFC 1323 timestamps через net.ipv4.tcp_timestamps = 1. Если ради выигрыша CPU отключить tcp_timestamps, tcp_tw_reuse просто перестает работать, приводя к исчерпанию локальных портов (ephemeral port exhaustion). При этом параметр tcp_tw_recycle из ядра давно удален за порчу трафика за NAT, но до сих пор встречается в устаревших инструкциях. Даже идеальный сетевой стек бесполезен, если сервис упирается в файловые дескрипторы. Каждый сетевой сокет в Linux — это файловый дескриптор. Общий лимит sysctl fs.file-max определяет емкость всей системы, но для конкретного процесса определяющим является ulimit. В дистрибутивах с systemd параметры из limits.conf игнорируются для демонов. Без явно прописанного LimitNOFILE=1048576 в unit-файле K3s, Nginx или ingress-контроллера сервис остановит прием новых соединений с ошибкой EMFILE (Too many open files) задолго до исчерпания RAM. Правильный тюнинг ядра требует сквозного аудита: от настроек самого приложения (backlog) и лимитов systemd (LimitNOFILE) до sysctl (somaxconn, tcp_max_syn_backlog, tcp_tw_reuse) и параметров ring-буферов сетевой карты. Настройка одного параметра в отрыве от цепочки всегда приводит к падению под нагрузкой. Практические регламенты отладки bare-metal инфраструктуры и сетевого стека ядра разбираем на https://ftops.space.
[FTOPS SPACE]DISPATCH #392

[ftops] SMM Case: Замена iptables на nftables на 10G+ линках — это не про новый синтаксис, а ...

На сетевых интерфейсах 10G+ при высокоинтенсивном трафике классическая проблема фильтрации заключается не только в скорости прохождения пакета по цепочке, но и в поведении подсистемы при динамическом изменении правил. Когда автоматизированные системы защиты, IPS или сетевые контроллеры пытаются оперативно заблокировать атаки или обновить адреса, legacy-стек iptables блокирует весь пайплайн. Каждое изменение в iptables требует полного копирования монолитного массива правил из пространства пользователя в ядро через ip_tables mutex. На мультигигабитных каналах это приводит к сбросу кешей процессора, cache line bouncing между NUMA-узлами и микроскопическим задержкам, вызывающим потерю пакетов в сетевых очередях NIC. Архитектура nftables решает эту проблему за счет переноса логики в специализированную виртуальную машину ядра (nft_vm) и применения нативных структур данных: - Атомарные транзакции: обновления передаются через netlink-сообщения коммитом конкретных элементов, без перезагрузки всей таблицы и без заморозки проходящего трафика. - Поиск за O(1): вместо последовательного прогона пакета по сотням правил iptables используются встроенные сеты и мапы на базе хэш-таблиц и rbtree. - Оптимизация памяти: динамические списки IP-адресов подгружаются прямо в структуры ядра без вызова пересборки графа правил. Для высоконагруженных bare-metal маршрутизаторов и пограничных узлов K3s полный отказ от iptables в пользу нативного nftables избавляет сетевой стек от просадок производительности при постоянной смене правил фильтрации. Практические разборы оптимизации сетевого стека ядра и архитектуры устойчивых сервисов выложены на https://ftops.space.
[FTOPS SPACE]DISPATCH #382

[ftops] SMM Case: Дефолтный Kubelet ImageGC рассчитан на гигабайтные облачные ноды, а не на д...

Дефолтные настройки ImageGC в Kubernetes рассчитаны на гиперскейлеры и ноды с сотнями гигабайт памяти. На небольших VPS с диском 20-40 ГБ стандартный параметр imageGCHighThresholdPercent=85 выставляет смертельную ловушку: сборка мусора начинается только тогда, когда на диске остается 3-5 ГБ. В условиях интенсивного деплоя или роста ephemeral-storage локальная файловая система забивается быстрее, чем kubelet успевает запустить цикл очистки containerd. При достижении порога нода мгновенно получает taint DiskPressure. Kubelet начинает хаотично эвиктить поды, ломая консенсус K3s и переводя файловую систему бюджетного VPS в read-only из-за I/O-ограничений провайдера. Проблема усугубляется тем, что сборщик не трогает образы, созданные меньше чем imageMinimumGCAge назад (по умолчанию 2 минуты), а старые логи контейнеров не входят в зону ответственности ImageGC. Для стабильной работы мелких узлов дисковую гигиену нужно переводить в жесткий режим через конфигурацию K3s (/etc/rancher/k3s/config.yaml): kubelet-arg: - image-gc-high-threshold=60 - image-gc-low-threshold=45 - image-minimum-gc-age=1m - eviction-hard=nodefs.available<10%,nodefs.inodesFree<5% Дополнительно зафиксируйте SystemMaxUse=1G в journald.conf и ограничьте размер логов контейнеров через max-size в containerd. На малых объемах управление памятью строится не от пиковых нагрузок, а от физической скорости выедания диска. Разбор оптимизации Bare-Metal и K3s стека читайте на https://ftops.space.
[FTOPS SPACE]DISPATCH #372

[ftops] SMM Case: Гиперскейлеры скрывают сетевой оверхед за удобной визуализацией VPC

Гиперскейлеры продают гигагерцы и гигабайты, но умалчивают про реальную структуру сетевых задержек. В пулах EKS или GKE межзональный трафик проходит через слои виртуализации vNIC, фильтры гипервизора и оверлейные сети. Результат — устойчивый p99 latency между нодами на уровне 1.8–3.2 миллисекунд. В K3s-кластере на голом железе с прямым 10GbE/100GbE L2-фабриком и eBPF-маршрутизацией без оверлея межнодовая задержка падает до 80–150 микросекунд. Для транзакционных баз данных и распределенного кэша это разница между падением пропускной способности и стабильной работой под пиковой нагрузкой. Финансовая модель облака окончательно ломается на блочных хранилищах и межзональном egress. Гарантированные 30 000 IOPS на io2 или gp3 с высоким лимитом операций обходятся в месяц дороже, чем разовый закуп двух корпоративных U.3 NVMe накопителей с ресурсом 3 DWPD. K3s на bare-metal позволяет отдавать подам сырые диски через Local Path Provisioner или собирать распределенное хранилище на Rook-Ceph с прямой PCI-пропускной способностью. Вы убираете из бюджета наценку гиперскейлера за эмуляцию дискового контроллера и плату за внутренний сетевой трафик. Переход на bare-metal K3s требует инженерной зрелости: вы сами отвечаете за драйверы, жизненный цикл ядра Linux (включая своевременный патчинг уязвимостей масштаба Pedit COW), тюнинг sysctl и настройку WireGuard mesh для связывания площадок. Но в обмен вы получаете точное планирование ресурсов без эффекта noisy neighbors, полный контроль над NUMA-топологией процессора и предсказуемую юнит-экономику без внезапных счетов за облачный трафик. Практические схемы сборки bare-metal узлов, регламенты оптимизации сетевого стека ядра и архитектуру K3s для высоконагруженных систем мы регулярно публиуем на https://ftops.space.
[FTOPS SPACE]DISPATCH #362

[ftops] SMM Case: На 10G+ линках iptables упирается не в полосу пропускания, а в микроархитек...

На 10G+ и 40G+ сетевых интерфейсах узким местом пакетной фильтрации становится не физический кабель, а накладные расходы ядра Linux в обработке softirq. Классический iptables использует линейную цепочку проверок с сложностью O(N). Каждый пришедший пакет последовательно прогоняется через структуры модуля ip_tables.ko, что выбивает инструкционный кэш L1i и увеличивает количество промахов ветвления процессора (branch mispredictions) при росте количества правил. Nftables кардинально меняет механики netfilter. Вместо жестко зашитых цепочек ядерных модулей nftables использует встроенную в ядро виртуальную машину (nftables VM). Правила компилируются в компактный байт-код. Сопоставление IP-адресов, портов и интерфейсов происходит за один проход через хэш-таблицы и дерева O(1), а не через сплошной список. Кроме того, атомарность обновлений правил в nftables исключает глобальные блокировки таблицы фильтрации, которые в iptables приводят к кратковременным проседаниям трафика при перезагрузке фаервола. Практический эффект на трафике высокой плотности: 1. Снижение утилизации CPU: перенос 500+ правил с iptables на native nftables снижает нагрузку на ядра в режиме softirq на 30–50% при 10-гигабитном потоке мелких пакетов. 2. Отказ от эмуляторов: использование iptables-nft создает иллюзию старого синтаксиса, но трансляторы часто генерируют неоптимальный байт-код. Истинный прирост достигается только при переходе на native nftables DSL с интервальными сетами и картами действий. 3. Снижение Latency: исключение дублирующих проверок сокет-буферов сокращает задержку обработки пакета на сетевом стеке bare-metal ноды. Прежде чем уходить в сложную обвязку XDP и eBPF, оптимизируйте базовый сетевой стек ядра. Грамотно спроектированные сеты nftables закрывают потребности 10G+ каналов без выхода из штатного netfilter. Разборы оптимизации Linux kernel и Bare-Metal инфраструктуры на https://ftops.space
[FTOPS SPACE]DISPATCH #352

[ftops] SMM Case: Когда K3s нода падает по OOM, а slabtop показывает гигабайты в kmalloc-512,...

Падение ноды bare-metal кластера по OOM-killer часто списывают на утечки памяти в Go-рантайме или подсистемах K3s. Однако если в профиле памяти через slabtop главными потребителями становятся kmalloc-512 или skbuff_head_cache, вы имеете дело с сетевым исчерпанием. В условиях BGP-петель трафик начинает бесконечно циркулировать между узлами mesh-сети или бордер-маршрутизаторами, выедая системную память под буферы сокетов. Каждый зацикленный пакет порождает огромные очереди на обработку в сетевом стеке ядра Linux. Когда Ring Buffer сетевой карты переполняется, ядро выделяет новые sk_buff в оперативной памяти, что приводит к ложным срабатываниям OOM-killer на пользовательских процессах. Односторонний мониторинг показывает лишь рост системной памяти. Чтобы вскрыть аномалию, требуется синхронный двусторонний tcpdump с выводом TTL на обоих концах линка и traceroute. Анализ дампов в такой ситуации строится на трех шагах: - Фиксация падения TTL для одинаковых 5-tuple пакетов на входящем и исходящем интерфейсах. - Проверка slabtop на предмет аномального роста структур skbuff_head_cache и net_dev. - Локализация циклического маршрута через traceroute с явным указанием интерфейса источника. Лечение этой патологии лежит не в плоскости тюнинга sysctl vm.overcommit_memory или наращивания RAM. Необходимо внедрять жесткие фильтры BGP-маршрутов, выставлять blackhole-маршруты для нераспределенных подсетей и валидировать таблицы FIB ядра. Подробные регламенты диагностики и построения отказоустойчивых bare-metal сетей читайте на https://ftops.space.
[FTOPS SPACE]DISPATCH #342

[ftops] SMM Case: Пакет доходит до hub-узла AmneziaWG, но мгновенно дропается на уровне ядра ...

Попытка организовать spoke-to-spoke связность через центральный hub в AmneziaWG или WireGuard часто упирается в молчаливую потерю пакетов. Администраторы включают net.ipv4.ip_forward=1, проверяют правила nftables, но icmp-пакеты от Spoke A к Spoke B все равно исчезают внутри интерфейса awg0. Проблема кроется в архитектуре Cryptokey Routing. В отличие от классических TUN-интерфейсов, WireGuard связывает IP-адрес назначения не просто с таблицей маршрутизации ядра, а с конкретным публичным ключом пира. Когда Spoke A отправляет пакет в сторону Spoke B (10.8.0.3) через Hub, ядро на Hub должно расшифровать входящий пакет от Spoke A, а затем заново зашифровать его ключом Spoke B. Для этого в секции Peer для Spoke B на Hub должен строго числиться AllowedIPs = 10.8.0.3/32. Если указать обобщенную подсеть или допустить пересечение префиксов между несколькими пирами, ядро привяжет маршрут к последнему инициализированному пиру. В итоге входящий трафик от Spoke A успешно расшифровывается, но этап повторного шифрования для Spoke B сбрасывается интерфейсом, так как адрес назначения не проходит внутренний валидатор криптографического сопоставления. Для стабильного mesh-трафика на базе AmneziaWG на стороне hub требуется комбинация из явных /32 записей для каждого клиента в AllowedIPs, разрешенной пересылки sysctl и правильной настройки MTU с учетом заголовков обфускации. Подробный разбор сетевого стека и конфигураций опубликован на https://ftops.space.
[FTOPS SPACE]DISPATCH #332

[ftops] SMM Case: Восстановление etcd в K3s из S3 на голом железе ломается не на этапе скачив...

Автоматический бэкап etcd в S3 создаёт опасную иллюзию защищенности, которая рушится при первом реальном инциденте в HA-кластере K3s. Когда вы запускаете процедуру восстановления на одном из мастеров, встроенный etcd пытается накатить снепшот поверх текущей структуры Raft. Если остальные управляющие узлы продолжают работать или сохранили старые данные в локальном хранилище, кластер мгновенно рассинхронизируется и блокирует операции записи. Рабочий регламент аварийного восстановления требует жесткой технической последовательности: - Полная остановка службы k3s на всех control-plane узлах кластера. - Очистка каталога /var/lib/rancher/k3s/server/db/etcd на всех ведомых мастерах для уничтожения старого состояния Raft. - Запуск процедуры cluster-reset на первичном узле с флагами --etcd-s3-enabled, --etcd-s3-bucket и указанием конкретного файла через --cluster-reset-restore-path или --etcd-s3-snapshot-name. - Проверка запуска одиночного кворума и последовательное переприсоединение остальных серверов через сброс их локальной базы. Отдельная точка отказа — учетные данные S3 и node-token. Если восстановление выполняется на с нуля развернутый нод, K3s не сможет прочитать настройки S3 из неинициализированной базы. Все ключи доступа, эндпоинты и параметры bucket должны быть явно прописаны в файле конфигурации config.yaml до момента выполнения команды сброса, иначе старт завершится ошибкой авторизации API. Разборы сетевых инцидентов, регламенты сборки отказоустойчивых bare-metal инфраструктур и сценарии DR регулярно выходят в проекте https://ftops.space.
[FTOPS SPACE]DISPATCH #268

[ftops] SMM Case: Обычный kubectl drain не защищает дисковую подсистему при техобслуживании у...

Стандартная команда kubectl cordon или drain изолирует узел только с точки зрения планера Kubernetes. Для распределенного хранилища Longhorn это пустой звук: его собственный контроллер ориентируется на кастомные ресурсы node.longhorn.io. Если запустить процедуру обслуживания сервера без предварительной блокировки сторедж-слоя, можно получить дисковый шторм и непредсказуемый сплит-брейн реплик. Корректный протокол планового вывода bare-metal узла требует строгого порядка действий: 1. Перевести allowScheduling в false в CRD Longhorn для целевого узла. 2. Включить флаг evictionRequested, чтобы реплики плавно перетекли на другие физические диски до остановки подов. 3. Дождаться перехода всех Volume в состояние Healthy и только после этого выполнять kubectl drain. В условиях K3s кластеров на собственном железе игнорирование этого порядка приводит к тому, что при перезагрузке узла система начинает синхронизировать гигабайты данных поверх не полностью остановленного I/O. Это особенно критично при срочной накатке патчей безопасности ядра Linux, когда окно обслуживания строго ограничено. Практические регламенты по управлению отказоустойчивостью распределенных хранилищ и сетевых мешей разбираем в блоге https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
Сами поймали шторм репликации, когда обычный дрейн утащил за собой живой том Longhorn. С тех пор изменение CRD перед выключением железа зашито в автоматический плейбук на ftops.space.
[FTOPS SPACE]DISPATCH #262

[ftops] SMM Case: On-call не про героизм. Про то, чтобы система сама себя починила, пока ты спишь....

On-call дежурство — не героизм, а инженерный процесс

Спать спокойно не потому что ничего не ломается. А потому что система знает что делать, когда ломается.

Подробнее о культуре надёжности: https://ftops.space
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
rollback-таймер это реально база, удивительно что до сих пор не везде 😅 сам сколько раз засыпал с мыслью "а вдруг правило не то поставил"
[FTOPS SPACE]DISPATCH #175

[ftops] SMM Case: Изоляция подов через базовые Kubernetes NetworkPolicy в распределенном bare...

Большинство реализаций Zero-Trust в bare-metal Kubernetes кластерах ломаются на стыке CNI и оверлейной сети. Когда ноды распределены по разным дата-центрам и связываются через WireGuard, стандартный механизм NetworkPolicy на базе iptables с трафиком внутри туннеля работает по остаточному принципу. Метаданные источника теряются, conntrack переполняется при частой ротации подов, а компрометация одного узла открывает доступ ко всему оверлею. Настоящая сетевая микросегментация требует переноса контрольной плоскости безопасности прямо в сетевой стек ядра. Использование eBPF позволяет отбросить громоздкий netfilter и привязывать правила не к нестабильным IP-адресам, а к криптографической идентичности пода (Identity-Aware Security). Пакет проверяется еще на уровне eBPF-программы до того, как ядро потратит ресурсы на аллокацию sk_buff или обработку таблицы маршрутизации. Чтобы zero-trust не превратился в декоративный конфиг, соблюдайте базовые регламенты: - Отключайте дефолтный ингресс в namespace и вводите явную политику Default Deny для всех подов. - Переводите CNI на eBPF datapath с валидацией L7-трафика без зависимости от сетевых интерфейсов ноды. - Аудируйте попытки несанкционированного межсервисного взаимодействия через eBPF-события в реальном времени, а не по логам фаервола. Подробные схемы строгой сегментации и развертывания безопасных K3s-кластеров на собственном железе вы найдете на https://ftops.space.
[СОПРОВОДИТЕЛЬНЫЙ АНАЛИЗ ПРАКТИКА]
После того как conntrack съел всю память на ноде из-за туннелированного трафика, сразу перевели сегментацию на eBPF. Разбор конфигов выложили на https://ftops.space.