Инцидент в 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 Смотрим corednscachehitstotal, corednscachemissestotal и corednsdnsresponsestotal по rcode, обязательно с разрезом instance/node. Проверяем, не маскирует ли кэш второй отказ в ядре: conntrack -S tcpdump -ni any 'udp port 53 or tcp port 53' nstat -az \| egrep 'Udp(InErrors\|RcvbufErrors)\|IpReasmFails' Если растут insertfailed или drop в conntrack, перезапуск DNS лишь ненадолго очищает декорации. Отдельно проверяем MTU и TCP fallback для крупных ответов. Лечение: ограничить отрицательный TTL, согласовать ro...
Инцидент в 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 Смотрим corednscachehitstotal, corednscachemissestotal и corednsdnsresponsestotal по rcode, обязательно с разрезом instance/node. Проверяем, не маскирует ли кэш второй отказ в ядре: conntrack -S tcpdump -ni any 'udp port 53 or tcp port 53' nstat -az \| egrep 'Udp(InErrors\|RcvbufErrors)\|IpReasmFails' Если растут insertfailed или drop в conntrack, перезапуск DNS лишь ненадолго очищает декорации. Отдельно проверяем MTU и TCP fallback для крупных ответов. Лечение: ограничить отрицательный TTL, согласовать rollout DNS и endpoint-изменений, алертить расхождение ответов между нодами и проверять кэш синтетическими запросами. Архитектура эксплуатации без облачного шаманства: https://ftops.space
Мониторинг кричал: 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'; отдельно смотрим insertfailed, drop, earlydrop и nfconntrackcount относительно nfconntrackmax. Подтверждение даёт трассировка: nft monitor trace и conntrack -E -p udp --dport 53. Если запрос виден на локальном DNS, ответ выходит, но сокет приложения его не получает, лечить Deployment CoreDNS бессмысленно. Проверяйте правила NOTRACK для локального DNS, переход NodeLocal DNSCache на TCP к upstream и корректность link-local bind. Локальный кэш не является обходом сетевого стека: он лишь переносит аварию ближе к процессу. Разбор bare-metal отказов без облачно...
Мониторинг кричал: 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'; отдельно смотрим insertfailed, drop, earlydrop и nfconntrackcount относительно nfconntrackmax. Подтверждение даёт трассировка: 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
Инцидент в 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 (tcptcpflags & 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. Если m...
Инцидент в 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 (tcptcpflags & 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
Managed Kubernetes был зеленым. Кластер уже разваливался
Мониторинг провайдера показывал healthy control plane, пока pod-to-pod трафик внутри WireGuard терял крупные пакеты. Причина оказалась не в Kubernetes: MTU оверлея не совпал с реальным маршрутом, MSS не зажимался, conntrack подошел к пределу. Облачная панель показывала норму, потому что ядро и сеть были спрятаны за SLA.
На bare metal с K3s расследование короче. Cilium дает наблюдаемость datapath и управляемую маршрутизацию, WireGuard оставляет межузловой трафик под нашим ключом, а счетчики ядра показывают правду без согласования с поддержкой. etcd размещается рядом с control plane, поэтому его latency определяется нашей топологией, а не соседями в чужом облаке.
Longhorn тоже не магия: реплики требуют предсказуемой сети и дисковой задержки. Если p99 etcd растет одновременно с retransmits и очередями диска, лечить надо физический контур, а не перезапускать pod. K3s не отменяет эксплуатацию — он возвращает оператору причинно-след...
Мониторинг провайдера показывал healthy control plane, пока pod-to-pod трафик внутри WireGuard терял крупные пакеты. Причина оказалась не в Kubernetes: MTU оверлея не совпал с реальным маршрутом, MSS не зажимался, conntrack подошел к пределу. Облачная панель показывала норму, потому что ядро и сеть были спрятаны за SLA.
На bare metal с K3s расследование короче. Cilium дает наблюдаемость datapath и управляемую маршрутизацию, WireGuard оставляет межузловой трафик под нашим ключом, а счетчики ядра показывают правду без согласования с поддержкой. etcd размещается рядом с control plane, поэтому его latency определяется нашей топологией, а не соседями в чужом облаке.
Longhorn тоже не магия: реплики требуют предсказуемой сети и дисковой задержки. Если p99 etcd растет одновременно с retransmits и очередями диска, лечить надо физический контур, а не перезапускать pod. K3s не отменяет эксплуатацию — он возвращает оператору причинно-след...
Managed Kubernetes был зеленым. Кластер уже разваливался
Мониторинг провайдера показывал healthy control plane, пока pod-to-pod трафик внутри WireGuard терял крупные пакеты. Причина оказалась не в Kubernetes: MTU оверлея не совпал с реальным маршрутом, MSS не зажимался, conntrack подошел к пределу. Облачная панель показывала норму, потому что ядро и сеть были спрятаны за SLA.
На bare metal с K3s расследование короче. Cilium дает наблюдаемость datapath и управляемую маршрутизацию, WireGuard оставляет межузловой трафик под нашим ключом, а счетчики ядра показывают правду без согласования с поддержкой. etcd размещается рядом с control plane, поэтому его latency определяется нашей топологией, а не соседями в чужом облаке.
Longhorn тоже не магия: реплики требуют предсказуемой сети и дисковой задержки. Если p99 etcd растет одновременно с retransmits и очередями диска, лечить надо физический контур, а не перезапускать pod. K3s не отменяет эксплуатацию — он возвращает оператору причинно-следственную связь.
Managed k8s продает снятие ответственности, но вместе с ней забирает контроль. Суверенная инфраструктура начинается там, где сеть, ключи, диски и журнал etcd принадлежат одной команде.
https://ftops.space
#ftops #devops #linux #freebsd #sre #инфраструктура
Мониторинг провайдера показывал healthy control plane, пока pod-to-pod трафик внутри WireGuard терял крупные пакеты. Причина оказалась не в Kubernetes: MTU оверлея не совпал с реальным маршрутом, MSS не зажимался, conntrack подошел к пределу. Облачная панель показывала норму, потому что ядро и сеть были спрятаны за SLA.
На bare metal с K3s расследование короче. Cilium дает наблюдаемость datapath и управляемую маршрутизацию, WireGuard оставляет межузловой трафик под нашим ключом, а счетчики ядра показывают правду без согласования с поддержкой. etcd размещается рядом с control plane, поэтому его latency определяется нашей топологией, а не соседями в чужом облаке.
Longhorn тоже не магия: реплики требуют предсказуемой сети и дисковой задержки. Если p99 etcd растет одновременно с retransmits и очередями диска, лечить надо физический контур, а не перезапускать pod. K3s не отменяет эксплуатацию — он возвращает оператору причинно-следственную связь.
Managed k8s продает снятие ответственности, но вместе с ней забирает контроль. Суверенная инфраструктура начинается там, где сеть, ключи, диски и журнал etcd принадлежат одной команде.
https://ftops.space
#ftops #devops #linux #freebsd #sre #инфраструктура
Инцидент: процесс запустили в 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 сбросить; включить nonewprivs; seccomp строить по фактическому syscall-профилю и завершать процесс на нарушении. Свежая история с Pedit COW снова показывает цену разрешённой поверхности ядра: уязвимый syscall нельзя обезвредить красивым каталогом. Виртуал...
Инцидент: процесс запустили в 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 сбросить; включить nonewprivs; seccomp строить по фактическому syscall-профилю и завершать процесс на нарушении. Свежая история с Pedit COW снова показывает цену разрешённой поверхности ядра: уязвимый syscall нельзя обезвредить красивым каталогом. Виртуализация нужна не всегда. Но дешёвая изоляция обязана быть многослойной и проверяться снаружи процесса. Практика эксплуатации bare metal: https://ftops.space
03:00. Сценарий отказа: после перехода на Cilium новые соединения сыплются таймаутами. Мониторинг обвиняет приложение, дежурный готовит рестарт. На хосте sysctl net.netfilter.nfconntrackcount net.netfilter.nfconntrackmax показывает запас. Ложный вывод: таблица соединений здорова. Проверили только 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. Почему вообще уходят от iptables? Он тоже работает в ядре. Выигрыш Cilium — в другом месте принятия решения: при socket LB backend выбирается через cgroup-хук уже на connect(...
03:00. Сценарий отказа: после перехода на Cilium новые соединения сыплются таймаутами. Мониторинг обвиняет приложение, дежурный готовит рестарт. На хосте sysctl net.netfilter.nfconntrackcount net.netfilter.nfconntrackmax показывает запас. Ложный вывод: таблица соединений здорова. Проверили только 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. Почему вообще уходят от iptables? Он тоже работает в ядре. Выигрыш Cilium — в другом месте принятия решения: при socket LB backend выбирается через cgroup-хук уже на connect(), а состояние сервисов хранится в BPF maps вместо цепочек правил kube-proxy. Это сокращает путь обработки, но сохраняет эксплуатационные лимиты. Механика — в описании kube-proxy replacement. План устранения после подтверждения нехватки ёмкости: ограничить шторм новых соединений, проверить повторное использование подключений, рассчитать размеры CT maps под память ноды и проверить GC. Критерий восстановления — успешные новые соединения под нагрузкой и прекращение роста соответствующих drops. Покупать ещё Kubernetes ради отсутствующего счётчика — дорогая форма суеверия. https://ftops.space
docs.cilium.io
Troubleshooting — Cilium 1.20.1 documentation
Учебный постмортем, 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 — это описано в документации ядра. Один EAGAIN ещё не доказывает срабатывание pids.max: проверяем также Max processes в /proc/PID/limits. Seccomp умеет возвращать заданный errno, поэтому сверяем загруженную политику; поле Seccomp в status не раскрывает её правила. Механиз...
Учебный постмортем, 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 — это описано в документации ядра. Один EAGAIN ещё не доказывает срабатывание pids.max: проверяем также Max processes в /proc/PID/limits. Seccomp умеет возвращать заданный errno, поэтому сверяем загруженную политику; поле Seccomp в status не раскрывает её правила. Механизм описан в seccomp(2). Здесь диагноз подтверждает рост max одновременно с отказами создания потоков. Исправление: ограничить пул и очередь, согласовать бюджет потоков с лимитами всей иерархии, повторить нагрузку. Chroot, cgroups и seccomp работают без отдельного гостевого ядра, но требуют измерений и настройки. Покупать K8s ради непрочитанного pids.events — дорогой способ спрятать незнание Linux. Практика эксплуатации: https://ftops.space.
03:00. Учебный постмортем: панель объявила OOM по exit 137, дежурный предложил поднять memory limit. Но 137 совместим с SIGKILL и сам по себе не устанавливает причину. Проверяем journalctl -k --since '20 min ago', журнал kubelet и прирост oomkill в 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 SERVERIP с клиента и отдельная трассировка обратно. ...
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: сначала доказательства, потом дополнительные гигабайты.
ZFS не тормозил. Его просто не измеряли
Мониторинг кричал о задержках диска на FreeBSD-шлюзе. Железо было исправно, ошибок в пуле не было. Настоящая причина сидела выше: ARC разросся под рабочей нагрузкой, полезные метаданные начали вытесняться, а jails синхронно получили паузы на повторном чтении с накопителей.
Криминалистика начинается не с покупки NVMe. Сначала смотрят zpool status -v, zpool iostat -v 1 и sysctl kstat.zfs.misc.arcstats. Если размер ARC, промахи и состав кэша не сопоставлены с реальным профилем I/O, любой график latency рассказывает только половину истории.
FreeBSD остается эталоном для сетевых шлюзов и надежного хранения не из-за UNIX-ностальгии. ZFS, jails и прозрачные системные счетчики дают оператору главное: предсказуемость отказа. Но стабильность появляется только там, где ARC ограничен осознанно, пул регулярно проверяется, а деградацию замечают до того, как она становится аварией.
Облако продает лишнюю память как лекарство от незнания. На своем железе диаг...
Мониторинг кричал о задержках диска на FreeBSD-шлюзе. Железо было исправно, ошибок в пуле не было. Настоящая причина сидела выше: ARC разросся под рабочей нагрузкой, полезные метаданные начали вытесняться, а jails синхронно получили паузы на повторном чтении с накопителей.
Криминалистика начинается не с покупки NVMe. Сначала смотрят zpool status -v, zpool iostat -v 1 и sysctl kstat.zfs.misc.arcstats. Если размер ARC, промахи и состав кэша не сопоставлены с реальным профилем I/O, любой график latency рассказывает только половину истории.
FreeBSD остается эталоном для сетевых шлюзов и надежного хранения не из-за UNIX-ностальгии. ZFS, jails и прозрачные системные счетчики дают оператору главное: предсказуемость отказа. Но стабильность появляется только там, где ARC ограничен осознанно, пул регулярно проверяется, а деградацию замечают до того, как она становится аварией.
Облако продает лишнюю память как лекарство от незнания. На своем железе диаг...
ZFS не тормозил. Его просто не измеряли
Мониторинг кричал о задержках диска на FreeBSD-шлюзе. Железо было исправно, ошибок в пуле не было. Настоящая причина сидела выше: ARC разросся под рабочей нагрузкой, полезные метаданные начали вытесняться, а jails синхронно получили паузы на повторном чтении с накопителей.
Криминалистика начинается не с покупки NVMe. Сначала смотрят zpool status -v, zpool iostat -v 1 и sysctl kstat.zfs.misc.arcstats. Если размер ARC, промахи и состав кэша не сопоставлены с реальным профилем I/O, любой график latency рассказывает только половину истории.
FreeBSD остается эталоном для сетевых шлюзов и надежного хранения не из-за UNIX-ностальгии. ZFS, jails и прозрачные системные счетчики дают оператору главное: предсказуемость отказа. Но стабильность появляется только там, где ARC ограничен осознанно, пул регулярно проверяется, а деградацию замечают до того, как она становится аварией.
Облако продает лишнюю память как лекарство от незнания. На своем железе диагноз дешевле: измерить кэш, проверить пул, отделить задержку ZFS от задержки устройства. Неизмеренная память не является запасом надежности.
https://ftops.space
#ftops #devops #linux #freebsd #sre #инфраструктура
Мониторинг кричал о задержках диска на FreeBSD-шлюзе. Железо было исправно, ошибок в пуле не было. Настоящая причина сидела выше: ARC разросся под рабочей нагрузкой, полезные метаданные начали вытесняться, а jails синхронно получили паузы на повторном чтении с накопителей.
Криминалистика начинается не с покупки NVMe. Сначала смотрят zpool status -v, zpool iostat -v 1 и sysctl kstat.zfs.misc.arcstats. Если размер ARC, промахи и состав кэша не сопоставлены с реальным профилем I/O, любой график latency рассказывает только половину истории.
FreeBSD остается эталоном для сетевых шлюзов и надежного хранения не из-за UNIX-ностальгии. ZFS, jails и прозрачные системные счетчики дают оператору главное: предсказуемость отказа. Но стабильность появляется только там, где ARC ограничен осознанно, пул регулярно проверяется, а деградацию замечают до того, как она становится аварией.
Облако продает лишнюю память как лекарство от незнания. На своем железе диагноз дешевле: измерить кэш, проверить пул, отделить задержку ZFS от задержки устройства. Неизмеренная память не является запасом надежности.
https://ftops.space
#ftops #devops #linux #freebsd #sre #инфраструктура
Мониторинг кричал: 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 'etcdserverhasleader\|etcddiskwalfsyncdurationseconds'. На остальных server-нодах при остановленном K3s архивировали и удалили из рабочего пути /var/lib/rancher/k3s/server/db, затем присоединили их заново. Ст...
Мониторинг кричал: 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 'etcdserverhasleader\|etcddiskwalfsyncdurationseconds'. На остальных server-нодах при остановленном K3s архивировали и удалили из рабочего пути /var/lib/rancher/k3s/server/db, затем присоединили их заново. Старые member ID нельзя пускать в новый quorum. Снепшот в бакете — лишь сырьё. DR существует только после регулярного restore-test, отдельного хранения token и записанного порядка запуска узлов. Практика bare-metal эксплуатации: https://ftops.space
Разбор аварии: active, но мертв
В 14:07 мониторинг увидел живой frr.service и четыре BGP-сессии в состоянии Established. Пользователи в это время получали таймауты. Дежурный перезапустил FRR, затем сетевой стек. Ничего не изменилось: процесс был исправен, а маршрут — нет.
Один транзитный провайдер принял утечку более специфичного префикса, второй предпочел этот маршрут и вернул трафик первому. Получилась межоператорская петля. Пакеты ходили между двумя AS до обнуления TTL, пока systemctl is-active продолжал печатать active. Он не врал: он отвечал на бесполезный вопрос о состоянии PID.
Криминалистика началась с mtr и tcpdump, а не с рестарта. Повторяющиеся адреса транзитов показали петлю, ICMP Time Exceeded подтвердил смерть по TTL, а сравнение received-routes и advertised-routes нашло более специфичный префикс. Счетчики ip -s link были чистыми: ядро передавало пакеты ровно туда, куда велела таблица маршрутизации.
После инцидента проверку сервиса заменили проверкой функции: внешний ...
В 14:07 мониторинг увидел живой frr.service и четыре BGP-сессии в состоянии Established. Пользователи в это время получали таймауты. Дежурный перезапустил FRR, затем сетевой стек. Ничего не изменилось: процесс был исправен, а маршрут — нет.
Один транзитный провайдер принял утечку более специфичного префикса, второй предпочел этот маршрут и вернул трафик первому. Получилась межоператорская петля. Пакеты ходили между двумя AS до обнуления TTL, пока systemctl is-active продолжал печатать active. Он не врал: он отвечал на бесполезный вопрос о состоянии PID.
Криминалистика началась с mtr и tcpdump, а не с рестарта. Повторяющиеся адреса транзитов показали петлю, ICMP Time Exceeded подтвердил смерть по TTL, а сравнение received-routes и advertised-routes нашло более специфичный префикс. Счетчики ip -s link были чистыми: ядро передавало пакеты ровно туда, куда велела таблица маршрутизации.
После инцидента проверку сервиса заменили проверкой функции: внешний ...