Ви не «змінили багато». Ви застосували оновлення безпеки, підняли мінорну версію, поміняли сертифікат або прошили пакет прошивки «затверджений вендором». Тепер половина флоту не завантажується, вузли Kubernetes у стані NotReady, а канал on-call нагадує блендер.
Аварії через оновлення здаються особистими, бо їх легко уникнути заднім числом і неможливо — у моменті. Виправлення рідко буває «не патчити». Виправлення — навчитися, де саме оновлення ламаються, як виявити це швидко, і як проєктувати розгортання так, щоб один поганий патч не міг вивести з ладу все.
Чому оновлення виводять системи з ладу (навіть «безпечні»)
Ми робимо вигляд, що оновлення — це лінійний процес: застосував патч, перезапустив сервіс, рушили далі. Продакшен не лінійний. Це купа зв’язаних систем з таймаутами, кешами, імпліцитними контрактами та «тимчасовими» обхідними шляхами, що стали постійними десь під час попереднього інциденту.
Аварія через оновлення зазвичай — одне з трьох:
- Дрейф сумісності: патч коректний, але ваше середовище відрізняється від того, на якому його тестували. Інше ядро, інша libc, інші прапори, інша прошивка диска, інша поведінка проксі.
- Операційне зв’язування: патч викликає рестарт, а рестарт запускає каскад. Пули з’єднань висихають, кеші холодніють, лідери переобираються, шарди перебалансовуються, а автоскейлер «допомагає», створюючи ще більше навантаження.
- Взаємодія зі станом: код змінює спосіб читання або запису стану. Міграції схем, перестроювання індексів, зміни парсингу конфігів, ланцюжки сертифікатів, feature-flag, формати серіалізації. У стаджингу це працює, бо там немає 18 місяців брудного стану.
До того ж, найнебезпечніша фраза в патчингу — «minor release». SemVer не рятує вас від операційної реальності. «Мала» зміна, яка зсуває кількість потоків або змінює поведінку DNS, може стати великою аварією, якщо ваша система була приточена до старої поведінки.
Цитата для стікера (приблизна думка): ідея з епохи Аполло—Гіна Кранца: «твердо і компетентно» — це стандарт; ви не повинні дивуватися власним системам. Одна фраза — інженерія надійності.
І незручна правда: аварії через патчі — не тільки «помилки вендора». Більшість — це «наші помилки», бо ми розкидали патч по занадто великому продакшену, занадто швидко, без аварійного виходу.
Факти та контекст: патчі ламають системи завжди
Шість–десять коротких фактів, бо історія повторюється, а ми продовжуємо дивуватися:
- Windows «Patch Tuesday» (почався 2003 року) існує частково щоб зробити патчинг передбачуваним; передбачуваність — це механізм контролю аварій.
- Черв’як Морріса 1988 року не лише розповсюдив шкідливе ПЗ — він змусив індустрію серйозніше ставитися до координованого патчингу і інцидент-реакції.
- Оновлення бібліотек SSL/TLS мають тривалу історію ламання клієнтів через суворіший парсинг, застарілі шифри або зміну валідації ланцюгів — покращення безпеки можуть бути регресією доступності.
- Оновлення ядра часто змінюють драйвери й таймінги. «Та сама конфігурація» не означає «та сама поведінка», коли еволюціонують scheduler і мережевий стек.
- DNS регулярно стає жертвою патчів: поведінка резолверів, правила кешування і search domain можуть змінитися й тихо направити трафік у нікуди.
- Зміни trust store у Java та екосистемі CA спричиняли реальні аварії, коли сертифікати, що раніше валідувалися, раптом перестали.
- Оновлення базових контейнерних образів можуть зламати сумісність glibc, набори CA або навіть поведінку shell. «Це лише базовий образ» — відомі останні слова.
- Прошивки сховища та мікрокод часто змінюють характеристики латентності. Навіть «успішні» оновлення можуть змістити профіль продуктивності достатньо, щоб спричинити таймаути і каскади.
Тут є закономірність: патчинг — це не лише зміна коректності; це поведінкова зміна. Продакшен-аварії зазвичай — поведінкові.
Жарт #1: Патч сказав «downtime не потрібен». Він не вказав для кого.
Реальні режими відмов: де патчі справді шкодять
1) Ребути, перезапуски і стадо, про яке ви забули
Багато аварій спричинені не новим бінарником — ними спричинений акт заміни. Перезапуск сервісу може:
- Впасти in-flight запити й викликати повтори.
- Інвалідовувати кеші, підвищивши навантаження на БД або об’єктні сховища.
- Скинути пули з’єднань, змусивши проходити повторну автентифікацію, TLS-рукопотискання та налаштування сесій.
- Переобрати лідерів і перебалансувати партиції (Kafka, etcd, Redis Cluster тощо).
Якщо ви патчите флот «рівномірно», ви все ще можете синхронізувати перезапуски настільки, щоб спричинити синхронізований біль. Ось чому мають значення jitter-розгортання і суворі обмеження одночасності.
2) Зміни значень за замовчуванням: тихий вбивця
У нотатках патча — «покращена продуктивність». Насправді ви отримали інші значення за замовчуванням: більше потоків, більші буфери, суворіші таймаути, інша поведінка резолвера DNS, інші налаштування GC, нова реалізація HTTP/2 або інша стратегія повторів.
Значення за замовчуванням фактично частина вашої продакшен-конфігурації, але ви не версіонували їх. Коли вони змінюються — ви успадковуєте зсув.
3) Парсинг конфігів і поведінка середовища
Оновлення, що «покращують валідацію», можуть відхиляти конфігури, які раніше приймалися. Звичні приклади:
- Зміни парсингу YAML (відступи, приведення типів).
- Перейменовані або застарілі ключі конфігурації.
- Суворіша валідація ланцюга сертифікатів.
- Змінена семантика: булеве, яке раніше значило «увімкнути», тепер означає «увімкнути експериментальний режим».
Якщо у вас немає лінтера конфігів у CI під точну версію, яку ви деплоїте, ви граєте в кості з кожним оновленням.
4) Сховище, файлові системи та сюрпризи в просторі ядра
Як інженер збереження даних скажу прямо: оновлення ламають не лише аплікації; вони можуть зламати підлогу, на якій стоять аплікації.
- Взаємодія ядра та файлових систем: нове ядро змінює планувальник IO, поведінку writeback або дивні властивості драйверів. З’являються спайки латентності, таймаути спрацьовують, і «аварія додатку» виявляється інцидентом сховища.
- Оновлення прошивки: диск може пройти SMART, але розподіл латентності зміниться. На хвостах латентності вмирає доступність.
- Multipath та правила udev: патч змінює імена або порядок виявлення, і ваші маунти не повертаються. Системи завантажуються в emergency mode.
5) Ламається екосистема залежностей
Навіть якщо ваш додаток стабільний, під ним може зрушити екосистема: OpenSSL, libc, CA bundle, пакети Python, JVM, Node, sidecar, service mesh, модулі ядра.
Найнебезпечніша залежність — та, про яку ви не знали, наприклад жорстко закодоване припущення, що резолвер повертає IPv4 першим, або що TCP backlog за замовчуванням «достатній».
6) Зміни в оперуванні спостережуваністю: ви втрачаєте очі під час збою
Оновлення може зламати логування (права доступу), метрики (несумісність sidecar), трасування (агент падає) або синхронізацію часу (ntpd/chronyd зміни конфігів). Система падає, і ваша здатність пояснити чому — також.
Три корпоративні міні-історії з шахти патчів
Міні-історія 1: Аварія через неправильне припущення
Середнього розміру SaaS-компанія мала мульти-регіональну конфігурацію з active-active трафіком. Вони патчили набір edge-нoдів — реверс-проксі і TLS-термінатори — після оновлення бібліотеки. План розгортання: «25% на регіон, потім далі». Звучало розумно. Люди пішли додому раніше.
Трафік не впав одразу. Стало дивно. Невеликий, але зростаючий відсоток клієнтів почав отримувати помилки TLS handshake. Підтримка отримувала тікети: «працює у Wi‑Fi, падає на мобільному», «працює з офісу, не працює з дому». Інженери дивились на графіки і бачили повільне зростання 5xx на edge — не достатньо, щоб спрацював головний алерт. Той тип відмови, що змушує сумніватися у дашбордах.
Неправильне припущення було тонким: команда вважала, що всі шляхи клієнтів погоджують однакову TLS-поведінку. Насправді частина клієнтів використовувала старі trust store Android, а деякі корпоративні middlebox-и робили TLS-інспекцію з крихкою поведінкою. Оновлена TLS-бібліотека посилила валідацію ланцюга сертифікатів і більше не терпіла порядок ланцюга, який раніше приймали деякі клієнти. Ланцюг сертифікатів був технічно валідним, але світ сповнений «достатньо валідних» реалізацій.
Виправлення було не лише «відкотити патч». Потрібно було скоригувати порядок подачі ланцюга і забезпечити коректний проміжний сертифікат у суміснішому вигляді. Також вони зрозуміли, що «TLS success rate по сімейству клієнтів» — не декоративна метрика; це метрика доступності. В постмортемі з’явився новий canary: не лише підмножина серверів, але й підмножина клієнтів, протестована синтетичними пробами з різними TLS-стеками.
Вони пізніше визнали найгірше: staging і pre-prod були занадто чистими. Ніяких дивних middlebox-ів. Ніяких древніх клієнтів. Патч не зламав їхній світ. Він зламав реальний.
Міні-історія 2: Оптимізація, що відкотилася проти вас
Команда data platform підтримувала великий кластер PostgreSQL і флот API-сервісів. Щоб пришвидшити деплої і зменшити «податок перезапуску», вони увімкнули нову опцію в runtime сервісу: агресивніше повторне використання з’єднань і більший пул за замовчуванням. Це прийшло з innocuous dependency bump.
Патч розгорнувся плавно. Латентність навіть покращилась першу годину. Потім база почала хитатись. Не жорсткий крах — гірше. Стрибкоподібне CPU, зростання lock waits та випадкові таймаути запитів. On-call бачили помилки в API, але графіки БД нагадували кардіограму. Класична серцево-судинна система розподілених систем.
«Оптимізація» збільшила кількість одночасно активних з’єднань на під. Під навантаженням API перестав скидати з’єднання і натомість утримував більше з’єднань довше. Накладні витрати на з’єднання в PostgreSQL і контенція на блокування зросли, що збільшило латентність запитів, що спричинило повтори в аплікації, що збільшило навантаження ще далі. Чітке позитивне зворотне коло.
Першим інстинктом команди було збільшити ресурс БД. Це зробило гірше, бо реальне обмеження було не в raw CPU, а в контенції і чергах. Фактичне виправлення було нудним: зменшити пули з’єднань, впровадити server-side statement timeouts і додати backpressure на рівні API. Також змінили захисні механізми rollout: будь-який патч, що впливає на поведінку з’єднань, має йти через canary з відтворенням навантаження і спостереженням SLO на БД.
Урок: покращення продуктивності, що змінюють конкуренцію, по суті створюють нову систему. Тестуйте їх як нову систему — canary, cap blast radius і чекайте дивних ефектів.
Міні-історія 3: Нудна, але правильна практика, що врятувала ситуацію
Регульоване підприємство вело внутрішню Kubernetes-платформу й багато stateful робочих навантажень. Їхня програма патчування була дуже нудна: суворі вікна змін, обов’язкові canary, і правило, що при оновленні кожного вузла один повний fault domain лишається недоторканим до валідації. Люди скаржилися на «процес». Звісно, вони скаржилися.
Вони запланували оновлення ядра, що містило зміну у storage-драйвері. Canary-вузли оновилися і перезавантажилися. За кілька хвилин їхні дашборди латентності сховища показали поганий хвіст: p99 IO latency стрибнула, і частина під-ів почала таймаутити записи. Нічого ще не вибухнуло; просто «погано».
Оскільки процес вимагав canary і утримання недоторканого fault domain, у них був безпечний осередок, куди можна було перемістити навантаження. Вони cordon-нули canary-вузли, віддренували їх і перемістили stateful-под-и на незачеплені вузли. Наслідок залишився обмеженим: незначні brownout-и, жодного повного інциденту, жодних втрат даних.
Потім вони зробили нудну річ: зупинили rollout і подали тикет вендору з конкретними доказами — версією драйвера, версією ядра, гістограмами латентності і dmesg-сніпетами. Вендор підтвердив регресію, викликану певною прошивкою HBA. Підприємство не було героїчним; воно було дисциплінованим.
Ось така історія, яку ви хочете: коли вас трохи дратує контроль змін, бо він не дозволив мати яскравий інцидент.
План швидкої діагностики: що перевірити першим/другим/третім
Це «у вас є п’ять хвилин до того, як керівництво приєднається до бриджу» план. Мета — не бути ідеальним; мета — визначити клас вузького місця і зупинити кровотечу.
Перше: припиніть погіршувати ситуацію
- Заморозьте розгортання: зупиніть подальше поширення патча. Якщо ви використовуєте автоматизацію, вимкніть джоб і підтвердіть, що він зупинився.
- Обмежте повтори: якщо у вас є глобальний тумблер для retry-штормів або circuit breakers, використайте його.
- Збережіть один відомо робочий острів: не дозволяйте останній здоровій сегменту «вилікуватись» в той же стан відмови.
Друге: класифікуйте відмову трьома питаннями
- На рівні завантаження чи сервісу? Якщо вузли не завантажуються — ви в зоні ядро/драйвер/файлова система. Якщо сервіси запущені, але падають — це аплікація/конфіг/залежність/трафік.
- Локалізовано чи системно? Одна AZ? Одна версія? Один профіль апаратного забезпечення? Одна когорта клієнтів? Локалізовані відмови вказують на патерни rollout-ів, гетерогенність або часткові оновлення.
- Латентність чи коректність? Стрибки латентності викликають таймаути і каскади; помилки коректності викликають миттєві відмови. Міри пом’якшення різні.
Третє: швидко знайдіть вузьке місце
Запустіть щільний цикл: візьміть один збійний інстанс і один здоровий, і порівняйте. Шукайте різницю, яка має значення: версії пакетів, ядро, конфіг, env vars, сховища сертифікатів, DNS, маршрути, маунти й IO латентність.
Якщо ви не можете пояснити, чому один хост працює, а інший — ні, ви ще не з’ясовуєте проблему — ви прогулюєтесь по визначним місцям.
Практичні завдання: команди, виводи та рішення (12+)
Це практичні завдання, які можна виконати під час аварії від оновлення. Кожне містить команду, реалістичний фрагмент виводу, що це означає, і рішення, яке потрібно прийняти.
Завдання 1: Підтвердити, що насправді змінилося (diff версій пакетів)
cr0x@server:~$ apt-cache policy openssl | sed -n '1,12p'
openssl:
Installed: 3.0.2-0ubuntu1.12
Candidate: 3.0.2-0ubuntu1.12
Version table:
*** 3.0.2-0ubuntu1.12 500
500 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages
100 /var/lib/dpkg/status
3.0.2-0ubuntu1.10 500
500 http://archive.ubuntu.com/ubuntu jammy-security/main amd64 Packages
Значення: Ви на конкретному білді; можна зв’язати поведінку з ним. Якщо canary на .12 і здорові вузли на .10, у вас є головний підозрюваний.
Рішення: Якщо кореляція співпадає з відмовами, призупиніть rollout і розгляньте фіксацію або відкат пакета.
Завдання 2: Визначити версію ядра та час останнього завантаження (перевірка регресії на рівні завантаження)
cr0x@server:~$ uname -r
6.5.0-21-generic
cr0x@server:~$ who -b
system boot 2026-01-22 02:14
Значення: Підтверджує поточне ядро та чи не перезавантажився вузол недавно в рамках патча.
Рішення: Якщо відмови почалися після ребута на новому ядрі — розглядайте це як регресію ядра/драйвера; пріоритетний відкат на попереднє ядро або перезавантаження в відоме робоче середовище.
Завдання 3: Швидко знайти невдачі unit-ів (вигляд systemd)
cr0x@server:~$ systemctl --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
● myapp.service loaded failed failed MyApp API Service
● node-exporter.service loaded failed failed Prometheus Node Exporter
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
Значення: Швидкий список того, що впало. Якщо агенти спостереження теж не працюють, чекайте сліпих зон.
Рішення: Відновіть «очі» (метрики/логи) якомога раніше або компенсуйте прямими командами на хості.
Завдання 4: Прочитати останні 200 рядків логу для unit-а (шукати помилки парсингу/конфігу)
cr0x@server:~$ journalctl -u myapp.service -n 200 --no-pager
Jan 22 02:16:03 server myapp[1842]: FATAL: invalid config: unknown key "http.keepalive_timeout_ms"
Jan 22 02:16:03 server systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE
Jan 22 02:16:03 server systemd[1]: myapp.service: Failed with result 'exit-code'.
Значення: Оновлення посилило схему конфігурації; старий ключ більше не підтримується.
Рішення: Відкотіть конфіг або бінар, щоб відновити сумісність; не робіть «гарячі» правки по флоту без розуміння версійної різниці.
Завдання 5: Порівняти зв’язування бінарників/бібліотек (несумісність залежностей)
cr0x@server:~$ ldd /usr/local/bin/myapp | egrep 'ssl|crypto|not found'
libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007f4e9b2b0000)
libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007f4e9ae20000)
Значення: Підтверджує, проти якої мажор-версії OpenSSL ви зібрані і чи нічого не відсутнє.
Рішення: Якщо є «not found», відновіть відсутню бібліотеку або пересоберіть сумісний білд; відкат краще за імпровізацію.
Завдання 6: Перевірити резолв DNS і конфіг резолвера (поширена післяпатчна несправність)
cr0x@server:~$ resolvectl status | sed -n '1,25p'
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Current DNS Server: 10.10.0.53
DNS Servers: 10.10.0.53 10.10.0.54
DNS Domain: corp.internal
Link 2 (eth0)
Current Scopes: DNS
Protocols: +DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Значення: Показує, який резолвер активний і чи ввімкнено systemd-resolved. Патчі можуть змінити режими або перезаписати /etc/resolv.conf.
Рішення: Якщо DNS-сервер змінився або search domain зникли, відновіть налаштування резолвера і перезапустіть постраждалі сервіси перед тим, як шукати «рандомні» таймаути.
Завдання 7: Перевірити TLS з хоста (ланцюг сертифікатів і handshake)
cr0x@server:~$ openssl s_client -connect api.internal:443 -servername api.internal -brief
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN = api.internal
Verification: OK
Значення: Handshake працює з цього хоста з цією збіркою OpenSSL.
Рішення: Якщо це падає тільки на оновлених хостах, підозрюйте зміни CA bundle/trust store або суворішу валідацію; розгляньте фіксацію версії CA bundle або перевипуск ланцюга.
Завдання 8: Перевірити дрейф часу (TLS та auth-шляхи люблять неправильний час)
cr0x@server:~$ timedatectl
Local time: Thu 2026-01-22 02:21:44 UTC
Universal time: Thu 2026-01-22 02:21:44 UTC
RTC time: Thu 2026-01-22 02:21:45
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: no
NTP service: active
RTC in local TZ: no
Значення: NTP-сервіс активний, але годинник не синхронізований. Після оновлень служби часу можуть мовчки відмовляти або змінити провайдера.
Рішення: Виправте синхронізацію часу перед дебагом auth/TLS. Невідсинхронізований годинник перетворює валідні сертифікати в «прострочені».
Завдання 9: Знайти IO-латентність і насичення (регресії сховища)
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0-21-generic (server) 01/22/2026 _x86_64_ (16 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
8.12 0.00 3.44 9.87 0.00 78.57
Device r/s w/s rkB/s wkB/s await %util
nvme0n1 12.0 180.0 640.0 9216.0 38.20 92.10
Значення: Високий %util і високий await вказують, що пристрій насичений і запити чекають.
Рішення: Якщо це почалося після оновлення ядра/прошивки, розглядайте як регресію сховища. Мітигуйте переміщенням навантаження, зменшенням write amplification або відкатом оновлення.
Завдання 10: Перевірити стан маунтів і помилки файлової системи (завантаження та runtime)
cr0x@server:~$ mount | egrep ' /data | /var/lib '
/dev/mapper/vg0-data on /data type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k)
cr0x@server:~$ dmesg -T | tail -n 6
[Thu Jan 22 02:20:11 2026] XFS (dm-2): Metadata corruption detected at xfs_inode_buf_verify+0x1a/0x70
[Thu Jan 22 02:20:11 2026] XFS (dm-2): Unmount and run xfs_repair
Значення: Маунт існує, але ядро повідомляє про корупцію метаданих. Іноді оновлення оголює латентну корупцію; інколи драйвер пише сміття.
Рішення: Зупиніть сервіс, який пише в цю файлову систему. Виведіть систему з ротації. Плануйте ремонт з rescue mode; не продовжуйте писати.
Завдання 11: Перевірити мережеві шляхи і MTU (післяпатчеві втрата пакетів реальна)
cr0x@server:~$ ip -br link show eth0
eth0 UP 00:16:3e:2b:8c:11 <BROADCAST,MULTICAST,UP,LOWER_UP>
cr0x@server:~$ ip link show eth0 | grep mtu
mtu 9000 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
cr0x@server:~$ ping -M do -s 8972 -c 2 10.10.0.1
PING 10.10.0.1 (10.10.0.1) 8972(9000) bytes of data.
ping: local error: message too long, mtu=1500
Значення: Інтерфейс каже MTU 9000, але шлях поводиться як 1500. Патч міг змінити NIC offload, VLAN-конфіг або маршрут.
Рішення: Поверніть MTU до значення, яке підтримує шлях, або виправте мережеву конфігурацію. Несумісність MTU викликає дивні таймаути і часткові відмови.
Завдання 12: Перевірити стан вузлів Kubernetes і версійну різницю (rolling node updates)
cr0x@server:~$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE KERNEL-VERSION
node-01 Ready worker 91d v1.29.3 10.20.1.11 Ubuntu 22.04.4 LTS 6.5.0-21-generic
node-02 NotReady worker 91d v1.29.3 10.20.1.12 Ubuntu 22.04.4 LTS 6.5.0-21-generic
node-03 Ready worker 91d v1.29.3 10.20.1.13 Ubuntu 22.04.4 LTS 6.2.0-39-generic
Значення: Node-02 в NotReady і має те ж ядро, що node-01; node-03 на старішому ядрі. Версійна різниця може бути вашою контрольною групою.
Рішення: Якщо NotReady корелює з новим ядром — cordon/drain уражених вузлів і призупиньте OS-роллоут вузлів.
Завдання 13: З’ясувати, чому Kubernetes-вузол NotReady (kubelet/container runtime)
cr0x@server:~$ kubectl describe node node-02 | sed -n '1,80p'
Conditions:
Type Status LastHeartbeatTime Reason Message
Ready False Thu, 22 Jan 2026 02:24:11 +0000 KubeletNotReady container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready
Значення: Вузол NotReady, бо мережевий плагін (CNI) не може ініціалізуватись — часто через зміни iptables/nftables, модулі ядра або дрейф конфігів runtime.
Рішення: Перевірте CNI-поди, бекенд iptables і модулі ядра. Якщо винуватець — оновлення, відкотіть образ вузла або зафіксуйте режим iptables.
Завдання 14: Підтвердити бекенд iptables (nft vs legacy) після оновлення
cr0x@server:~$ update-alternatives --display iptables | sed -n '1,25p'
iptables - auto mode
link best version is /usr/sbin/iptables-nft
link currently points to /usr/sbin/iptables-nft
link iptables is /usr/sbin/iptables
slave iptables-restore is /usr/sbin/iptables-restore
/usr/sbin/iptables-legacy - priority 10
/usr/sbin/iptables-nft - priority 20
Значення: Система використовує nft-бекенд. Деякі CNІ або скрипти досі припускають поведінку legacy iptables.
Рішення: Якщо CNI зламався після оновлення — тимчасово перемкніть на legacy або оновіть компоненти CNI; оберіть фікс з мінімальним blast radius спочатку.
Завдання 15: Перевірити активні з’єднання і retry-шторм (чи самі ми себе прокляли?)
cr0x@server:~$ ss -s
Total: 3812 (kernel 0)
TCP: 3421 (estab 2902, closed 331, orphaned 2, timewait 331)
Transport Total IP IPv6
RAW 0 0 0
UDP 26 19 7
TCP 3090 2879 211
INET 3116 2898 218
FRAG 0 0 0
Значення: Тисячі встановлених з’єднань. Якщо це більше звичайного і timewait зростає, ви можете бути в зоні ампліфікації повторів.
Рішення: Застосуйте rate limits/circuit breakers, зменшіть retry-клієнтів і розгляньте виведення частини потужності, щоб відновити стабільність (так, іноді менше — краще).
Жарт #2: Якщо ви не можете відтворити проблему, вітаю — ви побудували розподілену систему. Решта з нас досі дебагує вашу.
Поширені помилки: симптом → корінна причина → виправлення
1) Симптом: «Все вгору, але латентність подвоїлась і таймаути стрибають»
Корінна причина: Патч змінив планувальник IO, мережевий стек або поведінку з’єднань; хвостова латентність зросла, спрацювали таймаути і повтори.
Виправлення: Визначте вузьке місце (iostat, CPU steal, мережеві падіння). Негайно зменшіть конкуренцію і повтори. Відкотіть зміну, якщо розподіл латентності вийшов за межі SLO.
2) Симптом: «Лише деякі клієнти падають (мобільні, корпоративні мережі, певні регіони)»
Корінна причина: Оновлення TLS/бібліотеки посилило валідацію, змінило пріоритет шифрів або подачу ланцюга сертифікатів; регресія сумісності.
Виправлення: Тестуйте різноманітні клієнтські стеки. Скиньте порядок подачі сертифікатів, перевипустіть сертифікати або зафіксуйте сумісні налаштування. Канаріруйте на реальних клієнтських когортах через синтетичні тести.
3) Симптом: «Вузли не завантажуються після дня патчінгу»
Корінна причина: Оновлення ядра/драйверів + регресія сховища або мережевого драйвера; або відсутній модуль в initramfs; або зміни імен у fstab/пристроях.
Виправлення: Завантажте попереднє ядро з GRUB або використайте rescue mode, щоб виправити initramfs/модулі. Стабілізуйте, відкотивши образ вузла; потім досліджуйте сумісність драйверів/прошивки.
4) Симптом: «Вузли Kubernetes стають NotReady під час OS-оновлення»
Корінна причина: Несумісність runtime чи CNI, перемикання бекенду iptables, зміни модулів ядра (overlay, br_netfilter) або регресія MTU.
Виправлення: Порівняйте робочі і невдачні вузли за iptables-бекендом, модулями ядра і логами CNI. Відкотіть образ вузла або зафіксуйте режим iptables; лише потім робіть виправлений golden image.
5) Симптом: «Сервіс не стартує після оновлення; логи: ‘unknown key’ або помилка схеми»
Корінна причина: Зміни в схемі конфігурації; валідація посилилась; раніше терпимий конфіг тепер відкидається.
Виправлення: Версіонуйте конфіг і валідируйте його в CI проти цільової версії. Під час інциденту — відкотіть попередній бінар або видаліть/перейменуйте проблемний ключ.
6) Симптом: «Помилки БД після патча аплікації; зростання з’єднань»
Корінна причина: Змінився пул з’єднань за замовчуванням або логіка повторів ампліфікувала навантаження; БД стала спільною жертвою.
Виправлення: Обмежте конкуренцію, зменшіть розмір пулів, встановіть server-side timeouts і додайте backpressure. Відкотіть зміну, що торкнулась поведінки з’єднань.
7) Симптом: «Метрики зникли саме коли все пішло не так»
Корінна причина: Оновлення агента або експортеру несумісне з ядром/userspace; змінились права; systemd-hardening увімкнувся.
Виправлення: Відновіть мінімальну спостережуваність першочергово: поверніть node-метрики і логи. Використовуйте пряму інспекцію хоста, поки агенти відсутні.
8) Симптом: «Падає лише на одній моделі апаратури»
Корінна причина: Взаємодія прошивки і драйвера, відмінності мікрокоду або зміни дефолтів NIC offload.
Виправлення: Сегментуйте rollout за класом апаратури. Підтримуйте матрицю сумісності. Не комбінуйте оновлення прошивки з OS-оновленнями, якщо не любите складні головоломки.
Контрольні списки / покроковий план
Чеклист A: Перед тим, як патчити (нудні контролі, що запобігають світовим аваріям)
- Визначте upfront blast radius. Максимальний % флоту, максимум % по AZ, максимум % по сервісному рівню. Запишіть це. Застосовуйте автоматично.
- Створіть canary, що має реальне представництво. Той самий трафік, та сама форма даних, ті самі залежності, той самий клас апаратури. Якщо ваш canary — «самотня VM», то це не canary; це приманка.
- Вимагайте шлях відкату. Відкат образу, пониження пакета, вимкнення feature flag, відкат конфігу, fallback ядра. Якщо відкат вимагає героїки — у вас немає відкату.
- Фіксуйте те, що не повинно дрейфити. CA bundle, libc, JVM, критичні бібліотеки. Ви можете їх оновлювати — але свідомо, а не випадково.
- Перевірте безпечність рестарту. Навантажтеся тестами рестарту, а не лише steady-state. Слідкуйте за churn-ом з’єднань, часом прогріву кешів і виборами лідерів.
- Захистіть БД і сховище. Встановіть guardrails: max connections, ліміти черг, IO budgets. Патчі часто ламають шлях, переводячи тиск вниз по стеку.
- Слідкуйте за хвостовою латентністю, а не за середнім. Ви не пейджите за p50. Ваші клієнти теж ні; вони просто йдуть.
- Валідуйте конфіг у CI проти цільової версії. «Запускається в staging» — не контракт. Це рекомендація.
Чеклист B: Під час аварії оновлення (спочатку ізоляція, потім лікування)
- Заморозьте зміни і зупиніть автоматичний rollout. Підтвердіть зупинку.
- Визначте межу між зламаним і здоровим. Версія, регіон, апарат, node group, когорта клієнтів.
- Візьміть по одному невдалому і одному робочому вузлу. Порівняйте: версії, конфіги, ядро, резолвер, маршрути, маунти, CA bundle.
- Прийміть швидке рішення: рухатись вперед чи відкотити. Якщо ви не розумієте режим відмови за 15–30 хвилин — відкат зазвичай дешевший.
- Зменшіть навантаження під час дебагу. Вимкніть агресивні повтори, відкиньте некритичний трафік і зупиніть batch job-и, що підсилюють IO.
- Збережіть докази. Збережіть логи, списки пакетів і інформацію про версії з уражених вузлів перед їх відновленням.
Чеклист C: Після інциденту (зробіть повторення дорожчим, ніж патч)
- Напишіть постмортем, що називає провал контролю. «Баг у патчі» — не корінна причина. Корінна причина — чому це дійшло до великого продакшену.
- Додайте автоматичний gate. Перевірка метрик canary, виявлення версіонних різниць, валідація конфігів, diff залежностей, перевірка модулів ядра.
- Сегментуйте флот. Класи апаратури, OS-образи і критичні рівні. Один рівномірний rollout — одна рівномірна аварія.
- Практикуйте відкат. Якщо відкат використовується лише в аваріях, він зламається в аваріях.
- Відстежуйте інциденти, пов’язані з оновленнями, як метрику надійності. Не щоб карати команди — щоб побачити, чи працюють ваші контролі.
Поширені запитання
1) Чи варто відкладати всі патчі, щоб уникнути аварій?
Ні. Відкладення патчів міняє ризик доступності на ризик безпеки, і рахунок приходить із відсотками. Патчте, але інженеруйте розгортання так, щоб один поганий патч не міг вивести все з ладу.
2) Коли відкат — правильне рішення?
Коли blast radius росте і у вас немає чіткого режиму відмови. Відкат купує час і відновлює сервіс, поки ви досліджуєте. Рушити вперед варто, коли ви розумієте фікс і можете деплоїти його безпечно.
3) Який один найбільший предиктор аварії через патч?
Неконтрольована одночасність у rollout-і та поведінці рестарту. Відправляти в занадто велику частину флоту одночасно перетворює «баг» на «інцидент». Відправляти при цьому ще й рестарти залежностей — перетворює «інцидент» в «аварію».
4) Як зробити canary значущим?
Дайте йому реальний трафік і реальні шляхи залежностей. Включайте представницьку клієнтську поведінку (TLS-стеки, DNS, проксі), а не тільки серверне навантаження. Canary має мати змогу впасти так само, як продакшен.
5) Чи потрібно інакше ставитись до прошивки сховища?
Так. Прошивки можуть змінити розподіл латентності, не «ламаючи» нічого. Трактуйте їх як зміни, що впливають на продуктивність: canary на тому ж апаратному класі, слідкування за хвостовою латентністю і план відкату або принаймні «зупинки та ізоляції».
6) Чому оновлення часто викликають retry-шторм?
Бо рестарти і часткові відмови створюють таймаути, а таймаути викликають повтори. Повтори посилюють навантаження саме тоді, коли доступність зменшується. Якщо не обмежити повтори і конкуренцію, ваша надійність стане функцією найгіршої клієнтської поведінки.
7) Як уникнути ламання схеми конфігурації після апгрейдів?
Валідуйте конфіг у CI з точною цільовою версією і підтримуйте backward/forward сумісність, коли можливо. Під час rollout-ів не вводьте конфіг, що розуміє лише нова версія, поки всі вузли не оновлені — або загортуйте це за feature flag.
8) Ми використовуємо Kubernetes. Який найбезпечніший шаблон патчування вузлів?
Використовуйте golden node image, оновлюйте невеликими node pool-ами, cordon/drain з суворими disruption budget-ами і тримайте один fault domain недоторканим, поки canary не пройде. Уникайте змішування OS-оновлень з CNI/runtime змінами в одному вікні.
9) Як зрозуміти, це латентність сховища чи аплікації?
Дивіться IO wait, device await/%util і помилки файлової системи. Якщо iowait і await ростуть разом з таймаутами в кількох сервісах — часто спільне вузьке місце в сховищі. Якщо IO чистий — рухайтесь вгору по стеку: DNS, TLS, пули з’єднань, CPU, блокування.
10) Які метрики мають гейтити rollout?
Мінімум: error rate, сигнали насичення (CPU steal, IO await, depth черг), хвостова латентність (p95/p99) та здоров’я залежностей (латентність БД, hit ratio кешу, успішність DNS). Гейтьте за дельтами, а не за абсолютними числами.
Наступні кроки, які справді зменшують blast radius
Якщо ви хочете менше аварій від оновлень, перестаньте ставитися до патчування як до фонової задачі і почніть розглядати його як окрему продакшен-систему. Контрольна площина для оновлень — canary, gate-и, відкат, сегментація, спостережуваність — це те, що не дозволяє одному поганому патчу стати світовою подією.
Зробіть три речі цього тижня:
- Примусьте ліміти одночасності розгортань (на сервіс, на AZ, на клас апаратури) і зробіть їх важкими для обходу.
- Доведіть, що відкат працює, попрактикувавшись на некритичному сервісі і записавши точні кроки runbook-а.
- Додайте один швидкий gate, який слідкує за хвостовою латентністю і здоров’ям залежностей на canary перед рухом далі.
Ви не запобігнете кожному поганому патчу. Ви можете запобігти тому, щоб він забрав усе з собою. Це і є робота.