В 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 — дешёвая де...
В 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
Разбор типового отказа: в 03:00 после сетевой сегментации распределённого K3s межплощадочные запросы уходят в таймаут. Мониторинг обвиняет приложение, WireGuard показывает свежий handshake. Дежурный расширяет разрешения между сегментами. Связь не возвращается, зато изоляция уже ослаблена. На принимающем узле tcpdump -ni wg0 'tcptcpflags & tcp-syn !\= 0' показывает входящие SYN. Проверяем sysctl net.ipv4.conf.all.rpfilter net.ipv4.conf.wg0.rpfilter, затем ip rule show и ip route show table all. В этом сценарии strict reverse-path validation отвергает источник: лучший обратный путь проходит через другой интерфейс. Это поведение описано в документации ядра. Снимаем nstat -az IPReversePathFilter до и после контрольного запроса в том же network namespace. Рост счётчика вместе с захватом SYN и разбором маршрутов подтверждает диагноз. Для policy routing дополнительно проверяем net.ipv4.conf.wg0.srcvalidmark: участвует ли fwmark в обра...
Разбор типового отказа: в 03:00 после сетевой сегментации распределённого K3s межплощадочные запросы уходят в таймаут. Мониторинг обвиняет приложение, WireGuard показывает свежий handshake. Дежурный расширяет разрешения между сегментами. Связь не возвращается, зато изоляция уже ослаблена. На принимающем узле tcpdump -ni wg0 'tcptcpflags & tcp-syn !\= 0' показывает входящие SYN. Проверяем sysctl net.ipv4.conf.all.rpfilter net.ipv4.conf.wg0.rpfilter, затем ip rule show и ip route show table all. В этом сценарии strict reverse-path validation отвергает источник: лучший обратный путь проходит через другой интерфейс. Это поведение описано в документации ядра. Снимаем nstat -az IPReversePathFilter до и после контрольного запроса в том же network namespace. Рост счётчика вместе с захватом SYN и разбором маршрутов подтверждает диагноз. Для policy routing дополнительно проверяем net.ipv4.conf.wg0.srcvalidmark: участвует ли fwmark в обратном поиске. Одна таблица main всей картины не показывает. Исправление: согласовать маршруты и правила; при намеренной асимметрии обоснованно выбрать loose-проверку источника и сохранить явные ограничения доступа. Вернуть узкие разрешения, проверить разрешённые и запрещённые потоки после переключения площадки. Очередной security-оператор не исправит несовместимые настройки ядра. Эксплуатация bare-metal: https://ftops.space.
Сценарий постмортема, 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. На хосте смотрим iostat -xz 1 и cat /proc/pressure/io: await, aqu-sz, прирост total и avg10 у some/full. PSI показывает время задержек задач из-за I/O; сам по себе он не док...
Сценарий постмортема, 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. На хосте смотрим 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.
Longhorn
Longhorn | Settings
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. Ядро проверяем отдельно: cat /proc/pressure/io покажет some/full — долю времени с задержками из-за I/O; iostat -xz 1 — await и aqu-sz блочны...
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. Ядро проверяем отдельно: cat /proc/pressure/io покажет some/full — долю времени с задержками из-за I/O; iostat -xz 1 — await и aqu-sz блочных устройств. Низкие значения совместимы с отсутствием работы для rebuild: планировщик ещё не выделил место. Они сами по себе не доказывают исправность дисков. Крутить очередной sysctl до проверки размещения — инженерный шаманизм. Исправление: до вывода узла подготовить дополнительный storage-узел с подходящими тегами, дисками и ёмкостью, проверить размещение и завершение переноса реплик. Следующий узел обслуживать после восстановления требуемой избыточности. Разрешить две копии на одной машине — изменить модель отказа. Эксплуатация bare metal: https://ftops.space. Свободные байты становятся резервом только там, где планировщик разрешает их использовать.
Longhorn
Longhorn | Scheduling
03:00. Модель аварии: небольшой VPS, rollout, DiskPressure. CPU свободен, мониторинг показывает остаток диска, дежурный обвиняет containerd. Но при imageGCHighThresholdPercent\=85 и evictionHard imagefs.available<15% между стартом уборки и порогом давления практически нет запаса. Загрузка и распаковка нового образа пересекают черту. Порог давления — ещё не гарантия немедленного выселения: kubelet сначала пытается вернуть ресурс. Механика eviction. Снимаем показания: df -h /var/lib/rancher/k3s/agent/containerd и df -i /var/lib/rancher/k3s/agent/containerd. Проверяем байты и свободные inode файловой системы: ядро учитывает их независимо. kubectl describe node NODE покажет DiskPressure и события, sudo journalctl -u k3s --since '30 min ago' — ход уборки; на агенте смотрим k3s-agent. Метрики nodefilesystemavailbytes и nodefilesystemfilesfree сопоставляем с нужной точкой монтирования, а не со средним сво...
03:00. Модель аварии: небольшой VPS, rollout, DiskPressure. CPU свободен, мониторинг показывает остаток диска, дежурный обвиняет containerd. Но при imageGCHighThresholdPercent\=85 и evictionHard imagefs.available<15% между стартом уборки и порогом давления практически нет запаса. Загрузка и распаковка нового образа пересекают черту. Порог давления — ещё не гарантия немедленного выселения: kubelet сначала пытается вернуть ресурс. Механика eviction. Снимаем показания: df -h /var/lib/rancher/k3s/agent/containerd и df -i /var/lib/rancher/k3s/agent/containerd. Проверяем байты и свободные inode файловой системы: ядро учитывает их независимо. kubectl describe node NODE покажет DiskPressure и события, sudo journalctl -u k3s --since '30 min ago' — ход уборки; на агенте смотрим k3s-agent. Метрики nodefilesystemavailbytes и nodefilesystemfilesfree сопоставляем с нужной точкой монтирования, а не со средним свободным местом по серверу. Развязка: сборщик удаляет неиспользуемые образы, а текущие контейнеры ещё держат старую версию. Снижать high/low, например до 70/60, имеет смысл после замера пика rollout: нужны место под загрузку, распаковку и одновременное существование версий. Это пример настройки, не универсальный рецепт. Если удаляемых образов нет, никакой порог не создаст свободные блоки. Правила ImageGC. Профилактика: алерт на остаток байтов, inode и скорость заполнения до порога eviction; проверка фактической конфигурации kubelet; бюджет диска под пик обновления. Kubernetes на дешёвом VPS не отменяет арифметику ёмкости. Автоматизация без запаса превращает экономию в ночное дежурство. https://ftops.space
Kubernetes
Node-pressure Eviction
Node-pressure eviction is the process by which the kubelet proactively terminates pods to reclaim resource on nodes.
The kubelet monitors resources like memory, disk space, and filesystem inodes on your cluster's nodes. When one or more of these resources…
The kubelet monitors resources like memory, disk space, and filesystem inodes on your cluster's nodes. When one or more of these resources…
Инцидент в 03:00: часть 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(...