Оновлення пакетів — це місце, де добрі наміри проходять аудит реальністю. Одна хвилина — «проста установка оновлень безпеки», наступна — ви вже пояснюєте, чому SSH не приймає ключі і чому балансувальник навантаження почав виконувати інтерпретативний танець.
Виправлення не в тому, щоб «ніколи не оновлювати». Виправлення — це стратегія, яка ставиться до оновлень як до управління змінами для живої системи: спостерігати, передбачати, обмежувати радіус ураження, мати план відкату, а потім виконувати. Якщо це звучить як мова SRE — добре. Продакшн не цікавиться вашими почуттями; його цікавить ваш план відкату.
Що фактично ламається під час оновлень пакетів
Більшість невдач при оновленнях — це не «пакетний менеджер поганий». Це передбачувані побічні ефекти того, як Linux-системи працюють у продакшні: сервіси перезапускаються, залежності змінюються ролі, семантика конфігурацій змінюється, а старі припущення голосно помирають.
Шаблон поломок №1: неявні перезапуски
Багато пакетів поставляються з maintainer-скриптами, які перезапускають сервіси (systemd-юніти, init-скрипти, postinst-хуки). Це зручно на ноутбуку. На проді бази даних — це розмова про кар’єру.
І «перезапуск» не завжди явний. Деякі оновлення змінюють ротацію логів, торкаються файлів, які відслідковує systemd, тригерять socket-activation або змінюють визначення юнітів. Ваш сервіс може відскочити, навіть якщо ніхто не вводив systemctl restart.
Шаблон поломок №2: реальність ABI та libc
Деякі оновлення соціально прийнятно вирішувати перезавантаженням. Оновлення ядра. Оновлення glibc. Оновлення OpenSSL, залежно від того, як ваш процес його завантажує. Це не «гарячі латки і забути», якщо ви не побудували навколо цього повну стратегію.
Коли змінюється libc, довгоживучі процеси можуть зберігати старі відображення і працювати нормально… поки не виконають fork, dlopen або не потраплять у кодову гілку, що тепер очікує іншу версію символу. Це тип помилки, який чекає пікових навантажень, щоб з’явитися у вигляді таємниці.
Шаблон поломок №3: злиття конфігів і безконтрольні припущення
Debian-подібні підказки щодо змін у /etc існують не даремно. Якщо ви автоматично погоджуєте дефолти від пакувальника, ви можете знищити свої налаштування. Якщо ви завжди зберігаєте локальні конфіги, ви можете пропустити нові обов’язкові директиви й тихо погіршити безпеку чи функціональність.
Шаблон поломок №4: залежності «допомагають» вам
Пакетні менеджери — це розв’язувачі залежностей. Вони також можуть стати руйнівниками залежностей. Ви запросили нову версію python3-foo; він вирішив, що це означає видалення бібліотеки, яка потрібна агенту моніторингу, бо на папері ніхто більше від неї не залежить. На папері. Не у вашому продакшн-зоопарку.
Шаблон поломок №5: дрейф репозиторіїв
Непослідовності зеркал, змішані репозиторії, застарілі кеші, зафіксовані версії та сторонні репозиторії з креативною упаковкою — тихі вбивці. Ви думаєте, що застосовуєте «останні оновлення безпеки», але насправді робите часткове оновлення в суміжних несумісних множинах.
Жарт №1: Часткове оновлення схоже на те, як робити половину кореневого каналу — технічно ви почали, але вам не сподобається фінал.
Шаблон поломок №6: несподіванки з файловою системою та сховищем
Оновлення пишуть на диск. Багато. Якщо ваш корінь майже заповнений, ви впадете посеред транзакції й опинитеся у напівналаштованому чистилищі. Якщо ви на thin-provisioned сховищі, снапшоти можуть заповнити пул. Якщо ваш IO вже напружений, скрипти dpkg/rpm стануть новими злодіями затримок.
Як інженер зі сховищ, скажу прямо: багато «неуспішних оновлень пакетів» — це насправді «ми вичерпали IO-бюджет» під іншим костюмом.
Цікаві факти та контекст (бо історія повторюється)
- Факт 1: Debianівський
dpkgз’явився раніше заapt.aptстав дружнім резолвером;dpkgзалишився грубим інструментом, який фактично розпаковує пакети і запускає maintainer-скрипти. - Факт 2: RPM-транзакції проектувалися бути узгодженими, але scriptlet-скрипти (pre/post install) — це довільний код. Транзакції атомарні-ish; scriptlet-и — «хай щастить-ish».
- Факт 3: Ідея розділення «оновлення безпеки» від «оновлення функцій» сформувала моделі дистрибутивів для підприємств; саме тому існують стабільні гілки релізів і робочі процеси для виправлень.
- Факт 4: Існує live-патчинг ядра (kpatch/kGraft/livepatch), але це не усуває перезавантаження назавжди — складні зміни, драйвери та userland все одно хочуть контрольований цикл рестартів.
- Факт 5: Systemd змінив операційне відчуття оновлень: файли юнітів, drop-in-и, daemon-reload і socket-activation внесли нові способи, як «ніби нічого не змінилося» може змінитися.
- Факт 6: Міма «петси проти скотини» стала популярною, бо ручні оновлення не масштабуються; безпечні для флоту оновлення — це проблема оркестрації, а не проблема героя.
- Факт 7: Практика канаркових релізів походить із ширшого інженерії надійності, але вона ідеально мапується на оновлення пакетів: перевірте на репрезентативній підмножині перед тим, як підпалити весь флот.
- Факт 8: Відкат на основі снапшотів став мейнстрімом в операціях не тому, що снапшоти сексуальні, а тому, що вони перетворюють «панічну діагностику» на «відкотитися й розслідувати». Btrfs, ZFS і LVM всі грають за цими правилами по-різному.
Одна перефразована ідея, варта нагадування на стікері: Несподіванки — це провал підготовки
від Gene Kranz (mission operations): несправності — не сюрприз; сюрприз — це провал підготовки.
Обов’язкові принципи для безпечних оновлень
1) Ставтеся до оновлень як до деплою
Якщо в організації є CI/CD для коду додатка, а для ОС діє «оновлюємо по принципу YOLO», у вас є прогалина надійності розміром з дата-центр. ОС — частина продукту.
Робіть оновлення спостережуваними, поетапними й відкатними. Якщо ви не можете відкотитися — ви не оновлюєте, ви граєтеся в азартні ігри.
2) Визначте намір оновлення: безпека, виправлення чи функція
«Запустити оновлення» — це не намір. Наміри: застосувати критичні патчі безпеки без великих оновлень версій, або перейти з мінорного релізу X на Y, або уніфікувати серію ядер.
Намір визначає вибір репозиторіїв, фіксацію версій, політику перезавантажень і обсяг тестування. Тільки безпекові оновлення все одно можуть перезапустити сервіси. Оновлення функцій можуть змінити семантику конфігів. Плануйте відповідно.
3) Обмежуйте радіус ураження канарками й хвилями
Обирайте канарки репрезентативно: та сама роль, та сама форма трафіку, ті самі критичні залежності, той самий дивний агент, про який усі забувають. Потім розгортайте хвилями, розмір яких відповідає вашій толерантності до болю.
4) Розділяйте «встановлення» й «активацію»
Встановлення пакетів — це одне. Активація їх (перезапуск сервісів, reload, reboot) — інше. Ваша стратегія має роз’єднувати це де можливо:
- Встановлюйте під час робочих годин, якщо потрібно, але перезапускайте під час контрольованого вікна.
- Дозволяйте ядрам бути встановленими, але перезавантажуйте лише тоді, коли ви вирішите.
- Використовуйте планування перезапусків процесів для бібліотек, які цього вимагають.
5) Завжди майте історію відкату, що відповідає вашій реалізації сховища
Відкат — це не одна техніка. Це меню:
- Відкат через снапшоти файлової системи (Btrfs subvol snapshots, ZFS snapshots, LVM snapshots) для швидкого «undo».
- Пониження версій пакетів використовуючи кешовані пакети або зафіксовані версії.
- Відкат на рівні образу (immutable images, golden AMIs, перезбірка контейнерного хоста).
Обирайте те, що ви реально зможете виконати о 03:00 з тремтячими руками.
6) Не дозволяйте пакетному менеджеру імпровізувати
Фіксуйте версії, коли потрібна стабільність. Блокуйте критичні пакети. Заморожуйте сторонні репозиторії, якщо у вас немає тестового пайплайну для них. Контроль — це весь сенс.
7) Вимірюйте вплив: важливо не «скоєно встановлення», а «чи завдало це шкоди»
Після оновлень перевіряйте здоров’я: чутливість сервісів, рівні помилок, насичення, відставання реплікації, повідомлення ядра. Логи встановлення можуть бути чистими, а ваші системи тихо деградувати.
Жарт №2: Єдине, що гірше за провалене оновлення, — це успішне оновлення, яке повільно ламає продакшн — мов фільм жахів із кращими графіками доступності.
План швидкої діагностики (перший/другий/третій)
Це план на випадок, коли «ми оновили пакети» і щось пішло не так. У вас немає часу на філософську діагностику. Потрібно швидко знайти вузьке горлечко.
Перший: підтвердити, що змінилося і чи було перезапущено
- Виявте нещодавно оновлені пакети, версію ядра та чи перезапускалися сервіси.
- Перевірте журнали транзакцій dpkg/rpm на предмет помилок і підказок.
- Підтвердіть часову кореляцію: «проблема почалася відразу після оновлення» корисна лише коли позначки часу збігаються.
Другий: перевірити сигнали здоров’я системи (CPU, пам’ять, диск, мережа)
- CPU steal, черга виконання, насичення.
- Тиск пам’яті та OOM kills.
- Диск заповнений, вичерпання inode, IO wait, здоров’я RAID/ZFS пулу.
- Мережеві помилки, проблеми DNS, правила фаєрвола, змінені пакетами.
Третій: ізолювати компонент, що не працює, та вирішити — відкат чи виправлення на місці
- Це один сервіс чи багато? Один хост чи весь флот?
- Чи безпечний і швидкий відкат? Якщо так — відкотіть і стабілізуйте. Потім аналізуйте.
- Якщо відкат ризикований, пом’якшуйте: вимкніть нову функцію, зафіксуйте версію, перезапустіть у контрольованому порядку, переключіться на фейловер.
Правило прийняття рішень, яке мені подобається
Якщо вплив на клієнтів активний і у вас є відомий добрий шлях відкату, який завершується за хвилини — ви відкотитесь спочатку і будете дебажити потім. Геройська відладка під час інциденту — це спосіб заробити репутацію і втратити сон.
Практичні завдання з командами: що ви бачите, що це означає, яке рішення
Це реальні кроки. Не теорія. Кожне завдання містить команду, приклад виводу, що це означає та рішення, яке ви приймаєте.
Задача 1: Визначити, що змінилося нещодавно (Debian/Ubuntu)
cr0x@server:~$ grep -E " upgrade | install " /var/log/dpkg.log | tail -n 8
2026-02-04 01:10:22 upgrade openssl:amd64 3.0.2-0ubuntu1.12 3.0.2-0ubuntu1.13
2026-02-04 01:10:24 upgrade libssl3:amd64 3.0.2-0ubuntu1.12 3.0.2-0ubuntu1.13
2026-02-04 01:10:31 upgrade nginx-core:amd64 1.24.0-1ubuntu0.2 1.24.0-1ubuntu0.3
2026-02-04 01:10:32 upgrade nginx:amd64 1.24.0-1ubuntu0.2 1.24.0-1ubuntu0.3
2026-02-04 01:10:41 upgrade systemd 255.4-1ubuntu8.2 255.4-1ubuntu8.3
Що це означає: У вас є хронологія оновлень. Зверніть увагу на зміни бібліотек (libssl3) і пакетів сервісів (nginx), а також на зміни менеджера системи (systemd).
Рішення: Якщо інцидент співпадає з оновленням бібліотеки або systemd, пріоритезуйте процеси, що використовують цю бібліотеку, і перевірте перезапуски/перезавантаження.
Задача 2: Визначити, що змінилося нещодавно (RHEL/Rocky/Alma/Fedora)
cr0x@server:~$ sudo dnf history list | head
ID | Command line | Date and time | Action(s) | Altered
--------------------------------------------------------------------------------
42 | upgrade -y | 2026-02-04 01:05 | Upgrade | 18
41 | install tcpdump -y | 2026-01-20 10:12 | Install | 1
Що це означає: Існує ID транзакції. Ви можете її інспектувати або скасувати.
Рішення: Якщо оновлення корелює, перевірте транзакцію 42 і будьте готові відкочувати конкретні пакети або всю транзакцію.
Задача 3: Проінспектувати транзакцію DNF, щоб побачити, що саме змінилося
cr0x@server:~$ sudo dnf history info 42
Transaction ID : 42
Begin time : 2026-02-04 01:05:11
End time : 2026-02-04 01:06:02
Packages Altered:
Upgraded openssl-libs-3.0.7-30.el9_3.x86_64 @baseos
to openssl-libs-3.0.7-31.el9_3.x86_64 @baseos
Upgraded nginx-1:1.22.1-5.el9.x86_64 @appstream
to nginx-1:1.22.1-6.el9.x86_64 @appstream
Що це означає: Змінені базові бібліотеки криптографії та nginx. Це зміни з великим радіусом ураження, бо багато речей лінкуються з OpenSSL.
Рішення: Заплануйте контрольований перезапуск сервісів, які використовують OpenSSL (або заплануйте перезавантаження за політикою), і перевірте сумісність конфігурації nginx.
Задача 4: Передбачити оновлення перед виконанням (APT)
cr0x@server:~$ sudo apt-get -s dist-upgrade
Reading package lists... Done
Building dependency tree... Done
Calculating upgrade... Done
The following packages will be upgraded:
libc6 libssl3 nginx nginx-core openssl systemd
5 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Що це означає: libc6 і systemd в наборі. Це не «швидкий патч», це «плануйте перезапуски і, можливо, перезавантаження».
Рішення: Якщо це критичний хост, ви або (a) відкладете, (b) прогонуєте на канарках, або (c) заплануєте вікно обслуговування.
Задача 5: Передбачити оновлення перед виконанням (DNF)
cr0x@server:~$ sudo dnf upgrade --assumeno
Last metadata expiration check: 0:12:41 ago on 2026-02-04T00:52:21Z.
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Upgrading:
nginx x86_64 1:1.22.1-6.el9 appstream 40 k
openssl-libs x86_64 1:3.0.7-31.el9_3 baseos 1.5 M
Transaction Summary
================================================================================
Upgrade 2 Packages
Total download size: 1.6 M
Is this ok [y/N]: N
Що це означає: Чіткий список того, що зміниться і з якого репозиторію.
Рішення: Якщо ви бачите несподівані репозиторії (наприклад EPEL або репо вендора), які тягнуть базові пакети — зупиніться і виправте політику репозиторіїв перш ніж продовжувати.
Задача 6: Подивитися, які сервіси були перезапущені нещодавно (журнал systemd)
cr0x@server:~$ sudo journalctl --since "2026-02-04 00:55" -u nginx -u ssh -u postgresql --no-pager | tail -n 12
Feb 04 01:10:33 server systemd[1]: Stopping nginx - high performance web server...
Feb 04 01:10:33 server systemd[1]: nginx.service: Deactivated successfully.
Feb 04 01:10:33 server systemd[1]: Started nginx - high performance web server.
Feb 04 01:10:42 server systemd[1]: Reloading OpenBSD Secure Shell server daemon...
Feb 04 01:10:42 server sshd[1240]: Received SIGHUP; restarting.
Що це означає: nginx був перезапущений (не лише перезавантажений), sshd перезавантажився через reload. Це може обірвати з’єднання, змінити набори шифрів або виявити несумісності конфігурації.
Рішення: Якщо хост частина пулу, дренуйте його перед оновленнями; якщо це одиночний сервер, вам потрібна жорсткіша політика перезапусків (або вікно обслуговування).
Задача 7: Перевірити очікувані рішення щодо файлів конфігурації (Debian-family)
cr0x@server:~$ sudo dpkg --audit
The following packages have been unpacked but not yet configured:
nginx
The following packages have been configured but have not had their triggers run:
libc-bin
Що це означає: Ви посеред оновлення. Система в неконсистентному стані, поки ви не завершите конфігурацію/тригери.
Рішення: Завершіть транзакцію перед діагностикою симптомів додатків. Запустіть sudo dpkg --configure -a і усувайте підказки свідомо.
Задача 8: Безпечно завершити зламаний dpkg-процес
cr0x@server:~$ sudo dpkg --configure -a
Setting up nginx (1.24.0-1ubuntu0.3) ...
Installing new version of config file /etc/nginx/nginx.conf ...
Processing triggers for libc-bin (2.39-0ubuntu8.3) ...
Що це означає: Файл конфігурації був замінений або злитий, тригери libc виконано. Це може змінити поведінку під час виконання.
Рішення: Негайно порівняйте старий конфіг nginx (з резервних копій або з системи управління конфігурацією) і перевірте синтаксис nginx перед тим, як повернути трафік.
Задача 9: Перевірити конфігурацію сервісу перед перезапуском
cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Що це означає: Конфіг nginx парсується і базові перевірки проходять. Це не повний інтеграційний тест, але запобігає найгрубішим відмовам.
Рішення: Якщо тест падає — не перезапускайте. Виправте конфіг або відкотіть пакет/конфіг перед тим, як торкатися робочого процесу.
Задача 10: Перевірити, чи потрібен перезавантаження (Debian-family)
cr0x@server:~$ test -f /var/run/reboot-required && echo "reboot required" || echo "no reboot flag"
reboot required
Що це означає: Змінено ядро або критичні компоненти userland. Ви зараз у стані «нові біти на диску, старі в пам’яті».
Рішення: Заплануйте перезавантаження у наступному вікні обслуговування або переключіть навантаження, якщо хост критичний.
Задача 11: Підтвердити, яке ядро запущене в порівнянні з встановленим
cr0x@server:~$ uname -r
6.5.0-21-generic
cr0x@server:~$ dpkg -l | awk '/linux-image-[0-9]/{print $2, $3}' | tail -n 3
linux-image-6.5.0-21-generic 6.5.0-21.21
linux-image-6.5.0-22-generic 6.5.0-22.22
linux-image-generic 6.5.0.22.22
Що це означає: Ви запущені на 6.5.0-21, але 6.5.0-22 встановлено. Перезавантаження очікується.
Рішення: Якщо вам потрібна відповідність політиці безпеки — перезавантажуйте. Якщо вам потрібен аптайм — перезавантажуйте після дренування/фейловера. Виберіть відповідально.
Задача 12: Утримувати/зафіксувати критичні пакети, щоб уникнути несподіваних змін (APT)
cr0x@server:~$ sudo apt-mark hold nginx nginx-core
nginx set on hold.
nginx-core set on hold.
Що це означає: Ці пакети не будуть оновлюватися, поки їх явно не знімуть з утримання.
Рішення: Використовуйте утримання для критичних крайових сервісів, коли потрібно поетапне розгортання. Не тримайте вічно; ви відсуваєте ризик, а не видаляєте його.
Задача 13: Заблокувати версію пакета (DNF versionlock)
cr0x@server:~$ sudo dnf install -y 'dnf-command(versionlock)'
Last metadata expiration check: 0:03:19 ago on 2026-02-04T01:02:11Z.
Dependencies resolved.
Installed:
python3-dnf-plugins-core-4.3.0-13.el9.noarch
Complete!
cr0x@server:~$ sudo dnf versionlock add nginx
Adding versionlock on: nginx-1:1.22.1-6.el9.*
Що це означає: nginx зафіксовано на поточний NEVRA-патерн.
Рішення: Зафіксуйте в продакшні, коли ви не готові приймати зміни поведінки. Розблокуйте лише після валідації на канарці.
Задача 14: Відкотити транзакцію DNF (коли можна)
cr0x@server:~$ sudo dnf history undo 42
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Downgrading:
nginx x86_64 1:1.22.1-5.el9 @appstream 1.9 M
openssl-libs x86_64 1:3.0.7-30.el9_3 @baseos 1.5 M
Transaction Summary
================================================================================
Downgrade 2 Packages
Is this ok [y/N]: y
Complete!
Що це означає: Ви скасували транзакцію. Це один із небагатьох «він просто працює» варіантів відкату в Linux, коли репозиторії все ще містять старі версії.
Рішення: Якщо відкат швидко відновлює сервіс — зупиніть розгортання, зафіксуйте версії і налагоджуйте в стейджингу.
Задача 15: Зробити снапшот перед оновленням (приклад LVM)
cr0x@server:~$ sudo lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
root vg0 -wi-ao---- 80.00g
cr0x@server:~$ sudo lvcreate -s -n root_preupgrade -L 8G /dev/vg0/root
Logical volume "root_preupgrade" created.
Що це означає: Ви створили снапшот з 8G COW-простору. Якщо записи перевищать його, снапшот стане недійсним.
Рішення: Переконайтеся, що простір снапшота відповідає очікуваному обсягу записів (кеші пакетів, логи, база даних). На навантажених хостах LVM-снапшоти можуть бути крихкими — віддавайте перевагу відкатам на рівні образу або фейловеру.
Задача 16: Зробити снапшот перед оновленням (приклад ZFS)
cr0x@server:~$ sudo zfs list
NAME USED AVAIL REFER MOUNTPOINT
rpool/ROOT 12G 220G 96K /rpool/ROOT
rpool/ROOT/ubuntu 12G 220G 11G /
cr0x@server:~$ sudo zfs snapshot rpool/ROOT/ubuntu@preupgrade-2026-02-04
Що це означає: Снапшот миттєвий. Відкат також швидкий, але будьте обережні з сервісами, що постійно записують.
Рішення: Для оновлень ОС ZFS-snapshot-и — золото. Для томів з великим потоком записів координуйте уважно і моніторте простір пулу.
Задача 17: Перевірити місце на диску та вичерпання інодів перед оновленням
cr0x@server:~$ df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg0-root 80G 74G 2.1G 98% /
cr0x@server:~$ df -i /
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/mapper/vg0-root 5242880 5241002 1878 100% /
Що це означає: У вас вичерпані іноди. Навіть якщо байти лишаються, створення файлів зазнає фіаско. dpkg/rpm впаде посеред оновлення.
Рішення: Зупиніться. Почистіть (старі логи, кеш, тимчасові файли), потім оновлюйте. Якщо оновите зараз — опинитеся в режимі відновлення.
Задача 18: Виявити пакети, що змінили unit-файли і потребують daemon-reload
cr0x@server:~$ systemctl status nginx | sed -n '1,8p'
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2026-02-04 01:10:33 UTC; 2min ago
Docs: man:nginx(8)
Що це означає: Ви бачите, де лежить unit-файл і чи сервіс активний. Якщо unit-файли змінилися, systemd може потребувати daemon-reload, і перезапуски могли статись.
Рішення: Після оновлень, що торкаються systemd-юнітів, виконайте systemctl daemon-reload у контрольованому вікні і перевірте, що drop-in-и все ще застосовуються.
Три корпоративні міні-історії з передової
Міні-історія 1: Інцидент, спричинений хибним припущенням
Вони припустили, що «оновлення безпеки не змінюють поведінку». Це тепла ковдра, поки не загориться.
Інфраструктурна команда розгорнула оновлення OpenSSL на наборі API-шлюзів у звичайний робочий день. Вони вже робили це раніше. В них була автоматизація. Були графіки. Не було правила, що каже «оновлення крипто-бібліотек означає координовані перезапуски і перевірку TLS-термінації».
Саме оновлення пройшло добре. Потім сервіс перезапустився (post-install-скрипти, стандартна поведінка), і частина клієнтів почала отримувати помилки TLS handshake. Симптом спочатку виглядав як мережевий флап: переривчасті відмови, без чіткого регіонального патерну. Сапорт ескалувався. На викличному робили захоплення пакетів. Було огидно.
Корінь проблеми не в «OpenSSL зламав TLS». Корінь — дрейф конфігурацій у поєднанні зі стрімкішими дефолтами: одна сторона покладалася на застарілі шифри; оновлений стек перестав їх підтримувати. Стара поведінка існувала, бо конфіг шлюзу тихо відрізнявся між кластерами місяцями.
Виправлення не було героїчною відладкою. Виправлення — відкат на ураженій групі канарок, нормалізація TLS-конфігів через управління конфігурацією, потім повторне розгортання з валідацією. Справжній урок: якщо «тільки безпека» торкається автентифікації, крипто чи ідентичності — ставтеся до цього як до оновлення функцій у бронежилеті безпеки.
Міні-історія 2: Оптимізація, що обернулася проти
Платформна команда хотіла пришвидшити оновлення. Вони проводили часті патчі по сотнях віртуалок. Хтось помітив, що кеші пакетів великі, і подумав: «чистимо агресивно, щоб заощадити місце і прискорити».
Вони додали нічну задачу, що чистила кеші: архіви APT, кеші DNF, старі ядра — усе. Використання диска виглядало чудово. Дашборди похитнулися в зелене. Усі тихо віталися, бо ніхто не хоче публічно святкувати очистку диску.
Через два тижні погане оновлення з’явилося у сторонньому репозиторії і спричинило краш ядра агента. Відкат мав бути простим: пониження пакета й усе ок. Але старі файли пакетів були видалені, репо вже просунувся далі, і дзеркало не зберігало попередньої збірки.
Тепер відкат вимагав шукати старі RPM/DEB, тягнути їх із артефактного сховища, яке не зовсім їх містило, і вручну розповсюджувати під тиском. Зрештою стабілізувалися, зафіксувавши і замінивши репо, але рахунок за радіус ураження вже був сплачений.
Вони не перестали чистити кеші. Вони перестали робити це бездумно. Вони зберігли обмежений кеш останніх відомо хороших пакетів і дзеркалили критичні репозиторії локально. Оптимізація чудова, якщо вона не видаляє ваші аварійні виходи.
Міні-історія 3: Нудна практика, що врятувала день
Фінансова компанія мала нудну політику: кожна хвиля оновлень ОС вимагала снапшоту (або образу) плюс період прогону на канарці. Без винятків. Інженери скаржилися. Продукт нарікав. Це було, чесно кажучи, негарно.
Однієї ночі звичайне оновлення включало тонку зміну в клієнтській бібліотеці бази даних, яку використовував внутрішній батч-сервіс. Батч-сервіс мало моніторився, бо «він працює лише вночі». Ви вже здогадуєтесь, куди це рухається.
Канарки прогнали батч першими і показали підвищений рівень помилок при зв’язку з базою. Не повний збій, але достатньо, щоб запахло паленим. Оскільки канарки були строго ізольовані, лише частина задач впала. Відкат був миттєвий: відновлення зі снапшоту, фіксація бібліотеки, повторний запуск.
Тим часом основний флот ще не оновлювався. Зарплата не пропустила термін. Нікому не довелося писати листа з вибаченнями. Практика не виглядала розумною; вона виглядала бюрократичною. А потім вона врятувала день, бо була нудною й правильною.
Чеклісти / покроковий план
План A: Стандартне безпечне оновлення для флоту сервісів (рекомендується)
- Класифікуйте зміну. Тільки безпека в межах стабільного релізу? Ядро? libc? systemd? Залучено стороннє репо?
- Виберіть набір канарок. Та сама роль, та сама конфігурація, реальний трафік. Якщо не можете спрямувати реальний трафік — відтворіть його.
- Перевірки перед польотом. Місце на диску + inode-и, здоров’я пулу, відставання реплікації і базовий рівень помилок.
- Створіть точку відкату. Снапшот або посилання на імідж. Перевірте, що ви справді можете відкотитися.
- Симулюйте оновлення. Використайте
-sна APT або--assumenoна DNF. Інспектуйте репозиторії та стрибки версій. - Встановіть пакети. Тримайте перезапуски сервісів контрольованими. Перед цим дренуйте ноду з балансувальника навантаження, якщо це застосовно.
- Активуйте навмисно. Перезапускайте сервіси в правильному порядку. Перезавантажуйте, якщо політика ядра/libc цього вимагає.
- Проведіть валідацію. Синтетичні перевірки плюс реальні метрики: латентність, помилки, насичення, глибина черг, TLS-handshake-и, DNS.
- Пропитайте. Дайте час під реальним навантаженням. Деякі помилки — бомби уповільненої дії (витоки, повторні узгодження, cron-завдання).
- Розгортайте хвилями. Розширюйте до 5%, 25%, 50%, потім решти. Зупиніться при першій аномалії, яка пахне системною проблемою.
- Замкніть цикл. Занотуйте, що змінилося, що ви спостерігали і які пакети викликали перезапуски.
План B: Один критичний хост (болюча реальність)
- Визначте «максимальний бюджет простою». Якщо він близький до нуля — ваше реальне рішення це надмірність, а не хитрі оновлення.
- Зробіть снапшот і бекап. Снапшот — не бекап. Зробіть обидва, якщо можете.
- Вимкніть unattended upgrades. Потрібна одна зміна за раз, виконана людиною, з годинником і планом.
- Оновлюйте лише те, що потрібно. Віддавайте перевагу цілеспрямованим оновленням безпеки над широкими dist-upgrade.
- Перезапускайте один сервіс за раз. Перевіряйте після кожного. Якщо робите reboot — один раз, а не п’ять.
План C: Майже іммутабельні хости (краще, коли можливо)
- Збирайте новий образ з оновленими пакетами в CI.
- Запускайте тестовий набір + smoke-тести.
- Деплойте канаркові інстанси з нового образу.
- Поступово переміщуйте трафік.
- Відкотитися шляхом завершення канарок і повернення трафіку, а не пониженням у місці.
За замовчуванням я б ввів такі оперативні політики
- Критичні репозиторії дзеркаляться локально або принаймні кешуються з ретеншном.
- Оновлення ядра встановлюються в будь-який час; перезавантаження плануються і відстежуються.
- Пакети, що впливають на автентифікацію/крипто/ssh/dns, вважаються високим ризиком.
- Кожна хвиля оновлень має вимірювану умову успіху (не «без пейджів»).
- Кожен флот має канаркове кільце та механізм відкату, протестований щоквартально.
Поширені помилки: симптом → корінь → виправлення
1) Симптом: «apt upgrade» зависає на підказці в автоматизації
Корінь: dpkg чекає інтерактивного рішення щодо файлу конфігурації або політики перезапуску сервісу.
Виправлення: Не приглушуйте підказки сліпо. Попередньо задайте рішення або використовуйте політику: керуйте конфігураціями через CM; використовуйте noninteractive режим з явними опціями dpkg лише коли розумієте наслідки.
2) Симптом: SSH-сесії обриваються під час патчінгу
Корінь: перезавантаження/reload sshd, спричинене скриптами пакетів, або оновлення залежності, що спричинило перезапуск юнітів systemd.
Виправлення: Використовуйте консоль/серіальний доступ для оновлень. Дренуйте хости перед оновленням. Розгляньте needrestart (Debian/Ubuntu) для управління усвідомленістю перезапусків і плануйте рестарти навмисно.
3) Симптом: Сервіс не стартує після оновлення; конфіг здається «незмінним»
Корінь: Змінилася схема конфігу сервісу або дефолти; ваш старий конфіг тепер не проходить валідацію.
Виправлення: Запускайте нативні тести конфігурації (nginx -t, sshd -t, named-checkconf тощо) перед рестартом. Порівняйте паковані зміни конфігів. Відкатуйте за потреби.
4) Симптом: Випадкові сегфолти після оновлення libc/OpenSSL, але пізніше
Корінь: Довгоживучі процеси зберігають старі відображення; проблеми з’являються при fork/dlopen або в рідких кодових гілках.
Виправлення: Плануйте координовані перезапуски уражених демонів або перезавантаження. Відстежуйте «процеси, що використовують видалені бібліотеки» і перезапускайте їх.
5) Симптом: Пакетний менеджер повідомляє «no space left on device» посеред оновлення
Корінь: Корінь файлової системи заповнений, вичерпано inode-и або простір COW снапшоту вичерпано.
Виправлення: Спочатку звільніть місце й inode-и; збільшіть простір снапшоту або видаліть його; потім знову виконайте конфігурацію (dpkg --configure -a / повторіть транзакцію). Уникайте тонких меж на корінних розділах.
6) Симптом: DNF/YUM прагне видалити половину системи
Корінь: Змішані репозиторії, невідповідність модульних стрімів або застарілі залежності з відключеного репо.
Виправлення: Зупиніться і виправте консистентність репозиторіїв. Зафіксуйте стріми. Дзеркальте репозиторії. Не приймайте транзакцію, яка видаляє критичні runtime-пакети.
7) Симптом: Після оновлення CPU нормальний, але спалахи латентності
Корінь: IO wait через скрипти пакетів, ротацію логів, тригери БД або проблеми файлової системи, які виявилися новою поведінкою.
Виправлення: Перегляньте IO-статистику й здоров’я сховища. Переносьте оновлення у вікна з низьким IO, обмежуйте швидкість або перемикайте трафік під час оновлень.
8) Симптом: «Все оновлено», але сканери вразливостей все ще скаржаться
Корінь: Запущене ядро старе; чекає перезавантаження. Або сканери орієнтуються на сирі версії, ігноруючи backport-и.
Виправлення: Підтвердіть запущені версії (uname -r). Встановіть політику перезавантажень. Для плутанини через backport-и узгодьте політику сканера з вендорною errata, а не з сирими рядками версій.
Питання та відповіді
1) Чи варто запускати unattended upgrades на продакшн-серверах?
Не на нічому станіфул чи орієнтованому на клієнта, якщо ви не інженерно підготувалися: канарки, автоматичні відкат-и та контроль безпечних рестартів. Для невеликих безстанних пулів за балансувальником це може бути прийнятно з жорсткими запобіжниками.
2) Чи «лише оновлення безпеки» насправді безпечніше?
Зазвичай безпечніше, ніж широкі оновлення. Але оновлення крипто, автентифікації, DNS, ядра, systemd і базових рантаймів все одно можуть змінити поведінку. Тож ставте їх у категорію високого ризику навіть коли вони марковані як security.
3) Як запобігти перезапускам сервісів під час оновлень пакетів?
Ви можете зменшити несподівані перезапуски, але не усунути їх повністю. На Debian-подібних системах можна керувати поведінкою перезапусків політиками та дисциплінованими вікнами змін. Оперативно надійніший підхід: дренувати хост, оновити, а потім навмисно рестартнути.
4) Який найнадійніший метод відкату?
Для in-place оновлень: відкат через снапшот файлової системи найшвидший, якщо ваше сховище це підтримує і ви його протестували. Для флотів: заміна інстансів на відомі хороші образи чистіша. Пониження пакетів працює, поки репозиторії містять старі збірки.
5) Чи треба перезавантажувати після кожного оновлення ядра?
Якщо хочете застосувати патч безпеки — так, зрештою. Ви можете групувати перезавантаження. Встановлюйте ядра як тільки вони приходять, а потім перезавантажуйте за розкладом після дренування/фейловера.
6) Як дізнатися, які процеси потребують перезапуску після оновлення бібліотеки?
Шукайте процеси, що використовують видалені або замінені бібліотеки (інструменти залежать від дистрибутива), і ставте оновлення glibc/OpenSSL як сигнал до перезапуску ключових сервісів. Якщо не можете впевнено перерахувати — перезавантажтесь у вікні.
7) Чому оновлення іноді ламають лише одну зону доступності?
Дрейф репозиторіїв, затримка зеркал або тонкий дрейф конфігурацій. Якщо одна зона підтягує трохи іншу збірку або має старий конфіг — побачите асиметричні відмови. Дзеркальте локально і забезпечуйте консистентність конфігів.
8) У чому різниця між «upgrade» і «dist-upgrade» на Debian/Ubuntu?
upgrade консервативний: оновлює пакети без видалення або додавання залежностей, коли це було б потрібно. dist-upgrade (або full-upgrade) може додавати/видаляти пакети для вирішення залежностей. Консервативний безпечніший; повний іноді необхідний.
9) Як часто ми повинні патчити?
Достатньо часто, щоб кожен цикл патчів був нудним. Щомісяця — звично, щотижня для вищого ризику інтернет-орієнтованих флотів, і позачергово для критичних вразливостей. Справжня мета — передбачуваність: менші дельти, менше сюрпризів.
10) Чи слід назавжди фіксувати версії в продакшні?
Ні. Фіксація — інструмент для стаджингу, а не стиль життя. Використовуйте її, щоб виграти час для валідації, потім рухайтеся далі по контрольованих хвилях. Постійні фіксації стають копалинами, що вибухають під час наступної великої міграції.
Висновок: наступні кроки, які можна зробити цього тижня
Якщо ваша поточна стратегія оновлень — «запустити оновлення і сподіватися», вам не потрібна додаткова надія. Вам потрібні запобіжні засоби.
- Визначте намір оновлення для кожного середовища: лише безпека проти повного оновлення, політика ядра, каденція перезавантажень.
- Організуйте канаркове кільце, яке отримує оновлення першим і прогрівається під реальним трафіком.
- Реалізуйте відкат: снапшоти для in-place систем або відкат образів для флотів. Тестуйте його, а не лише документуйте.
- Контролюйте репозиторії: видаліть несподівані сторонні джерела, додайте дзеркала/кеші з ретеншеном і зафіксуйте критичні стріми пакетів.
- Операціоналізуйте валідацію: тести конфігурацій, перевірки здоров’я і пост-апґрейд чекліст, що включає «що перезапустилося?»
Зробіть це — і оновлення перестануть бути релігійним ритуалом. Вони стануть тим, чим мали бути від початку: рутинною зміною з відомим радіусом ураження, вимірюваним результатом і чистим виходом, коли щось йде не так.