Немає нічого, що більше кричить «професійна інженерна культура», ніж хост у лабораторії, який завантажується в аварійному шеллі за п’ять хвилин до викатки релізу. Або CI-раннер, який починає втрачати збірки, бо закінчилися іноди, а не диск. Це не цікаві збої — це запобіжні збої, зазвичай спричинені неакуратною інсталяцією та ще менш акуратною ментальною моделлю.
CentOS Stream 10 добре підходить для лабораторій і CI, бо він достатньо близький до RHEL, щоб навчити вас тим самим експлуатаційним урокам, але при цьому зміни з’являються раніше — саме те, що треба при валідації пайплайнів, драйверів, поведінки ядра та власних припущень.
Що таке CentOS Stream 10 насправді (і чому він вам потрібен)
CentOS Stream — це не «безкоштовний RHEL». Це дистрибутив з безперервною доставкою, який розташовується між Fedora та RHEL у потоці розробки. Практично це означає: зміни сюди потрапляють першими, перед тим як їх зафіксують у наступному мінорному релізі RHEL. Для лабораторій і CI це корисно: ви можете зловити майбутні ABI-зміни, зрушення в інструментарії та пакувальні особливості ще до того, як вони дістануться ваших платних флітів — або флітів ваших клієнтів.
Тут є пастка: люди встановлюють Stream і ставляться до нього як до спокійної довготривалої корпоративної ОС. Не робіть так. Ставтеся до нього як до контрольованого, продакшн-подібного канарки. Якщо вам потрібне щось, що ви ігноруєте три роки, використайте інше і будьте чесні щодо цього.
Коли CentOS Stream 10 — правильний вибір
- Ви збираєте RPM або модулі ядра та хочете раннє попередження про зміни buildroot.
- Ваш CI потребує поведінки, схожої на RHEL: systemd, SELinux, firewalld, NetworkManager і той самий загальний інструментарій.
- Ви хочете валідувати ролі Ansible і базові-настроювання під «наступний RHEL».
- Ви запускаєте KVM/libvirt або хости для контейнерів і потребуєте відносно стабільної бази, але можете терпіти швидші оновлення, ніж у класичному ентерпрайзі.
Коли це неправильний вибір
- Ваша лабораторія насправді — тіньове продакшн-середовище без контролю змін.
- Ви не можете часто патчити або у вас немає тестових воріт.
- Ваш «CI-раннер» — це «пет» VM, в який люди заходять по SSH і змінюють його вручну.
Факти та історія, що мають операційне значення
Ось конкретні контексти, які дійсно впливають на рішення, а не факти для світської бесіди на конференції:
- CentOS Stream був представлений як rolling preview RHEL, що змінило стару модель, коли CentOS Linux перебудовувався після релізів RHEL. Це змінює ваш профіль ризику: ви ближчі до передової черги змін.
- Раніше клон RHEL був стандартним вибором «безкоштовного корпоративного Linux», що виховало покоління команд ставитися до перебудов як до ідентичних. Stream ламає це припущення за замовчуванням.
- systemd вже давно є init-системою для сімейства RHEL, і саме в Stream ви побачите деякі зміни за замовчуванням сервісів першими (таймаути, залежності, опції жорсткого захисту).
- NetworkManager у більшості реальних розгортань уже не опціональний, бо інструменти, поведінка cloud-init і сучасне іменування NIC очікують його. Боротьба з ним — марна трата часу.
- SELinux у режимі «Enforcing» — це стандарт у адекватних середовищах, і екосистема RHEL витратила десятиліття на роботу над цим. Вимикати його досі популярно — переважно серед тих, хто не має чергувань.
- Anaconda історично потужна, але її легко неправильно налаштувати, особливо в частині кастомного розбивання диска і розташування завантажувача. «Я майже впевнений, що вибрав правильний диск» — це не стратегія зберігання.
- DNF замінив YUM як користувацький пакетний менеджер вже роки тому, і поведінка метаданих репо (і кешування) має значення, коли CI тягне сотні пакетів на день.
- cgroups v2 став стандартом у сучасних системах, схожих на RHEL, що змінює поведінку контейнерів і обмеження ресурсів порівняно зі старими флітами, які ще пам’ятають v1.
- Podman (rootless) — перший класний інструмент для контейнерів у сімействі RHEL, і він кращий за замовчуванням для багатьох CI-настроювань, ніж «просто запускати Docker як root і сподіватися».
Цілі дизайну для лабораторій і CI (виберіть сторону)
До того як запускати інсталятор ISO, вирішіть, за що ви оптимізуєте. Лабораторії і CI — це не одне й те саме, але вони мають спільну вимогу: передбачуваність відмов.
Мета 1: Відтворюваність важливіша за хитру інженерію
Для CI-раннерів я хочу образ, який можна відтворити з нуля і привести до потрібного стану автоматизацією менше ніж за годину. Якщо ви не можете швидко його перебудувати, ви будете зберігати його «на всякий випадок», і так утворюється хост, який став «особливим» після минулої людської зміни.
Мета 2: Зберігання повинно виходити з ледь помітною відмовою
CI-навантаження жорсткі до зберігання: багато дрібних файлів, високий обіг, кеші ростуть до межі і лог-файли, що не зупиняються. Ваша схема має робити помилку «диск заповнений» гучною й локалізованою, а не тихою і глобальною.
Мета 3: За замовчуванням безпека повинна залишатися увімкненою
Не вимикайте SELinux, бо одного разу збірка впала. Виправте маркування. Не чистіть файрвол, бо ваш тест-раннер не дістає до порту. Відкрийте порт. Якщо лабораторія у вас на плоскому мережевому сегменті, найменша загроза — не голлівудські хакери, а «тимчасова» служба іншої команди, що слухає на 0.0.0.0.
Сухе зіткнення з реальністю: хост у лабораторії без обмежень — це просто продакшн, тільки ніхто в цьому не зізнається. Так виникають «неочікувані» відмови, що насправді є «неочікуваною відповідальністю».
Шлях інсталяції: від ISO до першого завантаження без драми
Stream 10 можна встановлювати інтерактивно або через Kickstart. Для лабораторій і CI перевага за Kickstart, бо він перетворює племінні знання на файл. Інтерактивні інсталяції підходять для одноразових тестових VM, але саме вони перетворюють «стандартну збірку» на п’ять різних.
Виберіть відповідний профіль інсталяції
Для CI-раннерів і безголових серверів лабораторії: встановлюйте мінімальне середовище плюс потрібні пакети. GUI-збіри зручні, поки ви не змушені патчити 50 хостів і не усвідомлюєте, що тягнете десктоп-стек як кулю з ланцюгом.
UEFI проти BIOS: просто оберіть UEFI, якщо нема причин інакше
Сучасні сервери та VM мають бути UEFI. Це нудно, узгоджено, і інструменти дозріли. BIOS/legacy — для сумісності зі старими гіпервізорами або вбудованою технікою, яку ви не можете замінити.
Позиція щодо Kickstart
Kickstart для лабораторій/CI має робити такі речі:
- Явно фіксувати диск інсталяції (не покладатися на «перший диск» у порядку).
- Визначати розділи й LVM-томи з обґрунтованими розмірами та правилами росту.
- Створити адміністративного користувача з SSH-ключами (і заблокувати парольний SSH).
- Увімкнути SELinux в режимі enforcing і firewalld.
- Встановити часовий пояс, NTP і стабільну схему імен хостів.
- За потреби зареєструвати внутрішні репозиторії/дзеркала, якщо трафік CI великий.
Жарт #1: Ставтеся до «Далі, Далі, Готово» як до зарядженої зброї. Один клік може навчити ваш завантажувач нових, цікавинських дисків.
Схема зберігання: розділи, LVM і домени відмов
Зберігання — це те місце, де більшість інсталяцій для лабораторій/CI стають ледачими. Потім зберігання стає вузьким місцем, і всі звинувачують «мережу», бо приємніше жалітися на щось непомітне.
Як виглядає хороша схема
Для одномісного диску в VM або невеликого bare-metal вузла розумна за замовчуванням схема:
- UEFI system partition (ESP): маленький, фіксований.
- /boot: фіксований розмір, ext4.
- LVM PV для всього решта.
- Окремі LV для / (root), /var і, за потреби, /var/lib/containers або /var/lib/libvirt.
Чому розділяти /var? Бо CI записує в /var, ніби платять за байт. Логи, кеші пакетів, шари контейнерів, артефакти збірок і тимчасові файли люблять /var. Якщо /var заповниться і він на тому ж файловому сховищі, що й /, ви не отримаєте просто «диск заповнений» — отримаєте «система не може записувати стан». Це зовсім інша одиниця болю.
Ext4 проти XFS
XFS поширений у RHEL-подібних середовищах і добре поводиться з великими файлами та паралельними IO. Ext4 усе ще цілком гідний вибір для /boot і іноді для менших томів. Реальне правило: не вигадуйте. Використовуйте те, що очікує ваш інструментарій, і те, що ваша команда може відновити о 3 ранку.
LVM thin: будьте обережні
LVM thin provisioning може виглядати як вільний простір. Це не вільний простір. Це обіцянка вашому майбутньому «я», що ви будете моніторити використання пулу й реагувати до 100%. Thin-пули хороші у віртуалізованих лабораторіях, де зрозуміла overcommit. Вони катастрофічні, коли їх ніхто не спостерігає.
Swap: оберіть політику, а не інтуїцію
Для CI-раннерів із піками пам’яті трохи swap може запобігти вбиванню build job ядром. Для хостів, чутливих до затримки, занадто багато swap може приховати дефіцит пам’яті, поки продуктивність не стане «таємничо повільною». Якщо не впевнені: тримайте помірний swap і покладіться на моніторинг для налаштування.
Мережевий базис: передбачувані IP і DNS
CI-раннери, що падають через флап DNS — це не героїчна історія. Це провал базових речей.
Статична адресація проти DHCP
Для ефермерних CI-раннерів, які створюються і знищуються автоматично, DHCP підходить, якщо ваш DHCP і DNS надійні й інтегровані. Для довготривалих лабораторних хостів і bare-metal статичні IP зменшують сюрпризи. Якщо ви робите статичні IP, робіть це через профілі NetworkManager, а не правкою випадкових файлів вручну і надією, що згадаєте, що робили.
Імена хостів і search-домени
Оберіть схему найменування, яка переживе перевстановлення. Наприклад: роль + сайт + індекс. Не кодуйте секрети або внутрішні питання в іменах. Також тримайте search-домени мінімальними. Надто широкі search-домени викликають дивні затримки й непередбачуване резолювання, коли внутрішній DNS не в порядку.
Базові налаштування безпеки: SELinux, firewalld і SSH
Контролі безпеки — це не лише про безпеку. Вони про операційну передбачуваність. SELinux і firewalld змушують вас явно вказувати, що роблять ваші сервіси. Це полегшує розуміння систем.
SELinux: тримайте в режимі enforcing
Enforcing ловить неправильне маркування, погані налаштування і «на моєму лаптопі працювало» запуски контейнерів. Якщо щось ламається, ваша перша реакція має бути: прочитати AVC denials і виправити маркування або політику. Ваша остання реакція має бути: setenforce 0.
firewalld: визначайте зони і відкривайте тільки необхідне
CI-хости зазвичай потребують вхідного SSH і, можливо, вхідного прометей-скрепінгу. Вони не потребують світу, що дістає до випадкових ефемерних портів. Якщо ви запускаєте зеркало реєстру або кеш артефактів — це інше; відкривайте порти навмисно і документуйте це.
SSH: ключі, не паролі
Вимкніть парольну аутентифікацію, якщо можете. Якщо не можете, щонайменше обмежте її внутрішніми мережами і вимагайте сильні паролі. CI-раннери не мають бути місцем, де брутфорс паролів отримує плацдарм.
Цитата, яку варто тримати поряд з терміналом: Надія — не стратегія.
— Gene Kranz
CI/runtime вибір: Podman, контейнери і віртуалізація
Для лабораторій і CI зазвичай обирають один із трьох підходів:
- Збірки на хості: встановлювати toolchain на самому хості. Швидко, але з часом розпадається і стає «сніжинкою».
- Збірки в контейнерах: ізолювати середовища збірки за допомогою Podman. Відтворювано, простіше очищення, хороший дефолт.
- Збірки у VM: повна ОС на джоб через libvirt/KVM. Важчі, але ближчі до реальної поведінки розгортання.
Мій упереджений погляд: контейнерні збірки для більшості пайплайнів, VM-збірки для роботи з ядром/драйверами і «потрібно тестувати завантаження та системні сервіси», а збірки на хості — лише коли це справді необхідно (наприклад деякі апаратно-зв’язані тулчейни).
Практичні завдання з командами (і що вирішувати за результатами)
Це не іграшкові команди. Це те, що ви запускаєте в перший день і знову коли щось здається неправильним. Кожне завдання включає: команду, приклад виводу, що це означає і що далі вирішувати.
Завдання 1: Підтвердити, що ви встановили те, що думаєте
cr0x@server:~$ cat /etc/os-release
NAME="CentOS Stream"
VERSION="10"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="10"
PLATFORM_ID="platform:el10"
PRETTY_NAME="CentOS Stream 10"
Значення: Ви на Stream 10, і ідентифікатор платформи — EL10-подібний. Якщо тут інше, ваш pipeline образів бреше.
Рішення: Якщо це не те, що ви очікуєте, зупиніться і виправте джерело збірки. Не «продовжуйте так».
Завдання 2: Перевірити ядро і режим завантаження (UEFI проти legacy)
cr0x@server:~$ uname -r
6.12.0-0.el10.x86_64
cr0x@server:~$ test -d /sys/firmware/efi && echo UEFI || echo BIOS
UEFI
Значення: Версія ядра вказує, що ви дебагатимете. Режим завантаження важливий для grub, behavior secure boot і як розбито диски.
Рішення: Стандартизувати на UEFI для нових збірок, якщо немає обмежень платформи для BIOS.
Завдання 3: Ідентифікувати диски і впевнитися, що ви розбили потрібний
cr0x@server:~$ lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL
NAME SIZE TYPE FSTYPE MOUNTPOINTS MODEL
sda 200G disk QEMU HARDDISK
├─sda1 600M part vfat /boot/efi
├─sda2 1G part ext4 /boot
└─sda3 198.4G part LVM2_member
├─cs-root 40G lvm xfs /
├─cs-var 80G lvm xfs /var
└─cs-home 20G lvm xfs /home
Значення: Ви бачите карту розділів і що змонтовано. Якщо ви бачите, що ваш диск даних тримає /boot, у вас вже поганий день.
Рішення: Якщо використано неправильний диск, перевстановіть. Спроба «поправити пізніше» зазвичай обходиться дорожче за чисту перебудову.
Завдання 4: Перевірити ємність файлової системи та запас інодів
cr0x@server:~$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/cs-root xfs 40G 3.2G 37G 8% /
/dev/mapper/cs-var xfs 80G 12G 68G 15% /var
/dev/sda2 ext4 1020M 238M 713M 26% /boot
cr0x@server:~$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/mapper/cs-var 41943040 92321 41850719 1% /var
Значення: Простір і доступність інодів. CI може втратити іноди задовго до закінчення місця на диску, особливо в екосистемах мов, які люблять дрібні файли.
Рішення: Якщо /var малий або використання інодів швидко зростає, виділіть більше під /var зараз. Майбутній ви не зробить цього спокійно.
Завдання 5: Перевірити здоров’я LVM і вільні екстенти для росту
cr0x@server:~$ vgs
VG #PV #LV #SN Attr VSize VFree
cs 1 3 0 wz--n- 198.38g 58.38g
cr0x@server:~$ lvs -a -o lv_name,vg_name,lv_size,lv_attr,data_percent,metadata_percent
LV VG LSize Attr Data% Meta%
root cs 40.00g -wi-ao----
var cs 80.00g -wi-ao----
home cs 20.00g -wi-ao----
Значення: У вас є вільне місце у VG, щоб розширити /var коли CI виросте зубами. Якщо ви бачите VFree = 0, ви розміряли його до краю.
Рішення: Залишайте запас у VG. «Ми використали весь диск» — це не досягнення; це майбутній інцидент.
Завдання 6: Підтвердити каденцію оновлень і стан репозиторіїв
cr0x@server:~$ dnf repolist
repo id repo name
baseos CentOS Stream 10 - BaseOS
appstream CentOS Stream 10 - AppStream
cr0x@server:~$ dnf check-update
Last metadata expiration check: 0:12:17 ago on Tue 06 Feb 2026 09:10:44 AM UTC.
kernel.x86_64 6.12.2-0.el10 baseos
Значення: Репозиторії доступні, метадані актуальні і є оновлення. У Stream оновлення — це частина угоди.
Рішення: Якщо метадані сильно застарілі або repolist пустий, виправте DNS/proxy/дзеркала перш ніж довіряти хосту для CI.
Завдання 7: Перевірити синхронізацію часу (CI не любить зсуви)
cr0x@server:~$ timedatectl
Local time: Tue 2026-02-06 09:23:18 UTC
Universal time: Tue 2026-02-06 09:23:18 UTC
RTC time: Tue 2026-02-06 09:23:18
Time zone: UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
cr0x@server:~$ chronyc tracking
Reference ID : 0A0B0C0D (ntp1.example)
Stratum : 3
Last offset : -0.000021 seconds
RMS offset : 0.000112 seconds
Значення: Годинник синхронізований. Підписи токенів, TLS, часові мітки артефактів і розподілені збірки всі ламаються дурними способами при зсуві часу.
Рішення: Якщо NTP не активний, виправте це перш ніж дебагати «випадкові» TLS-помилки.
Завдання 8: Інспектувати мережеву конфігурацію через NetworkManager
cr0x@server:~$ nmcli -t -f NAME,DEVICE,TYPE,STATE con show --active
Wired connection 1:ens192:802-3-ethernet:activated
cr0x@server:~$ nmcli dev show ens192 | egrep 'IP4.ADDRESS|IP4.GATEWAY|IP4.DNS'
IP4.ADDRESS[1]: 10.20.30.40/24
IP4.GATEWAY: 10.20.30.1
IP4.DNS[1]: 10.20.30.10
Значення: У вас активний профіль з’єднання і адекватні IP/DNS. Якщо CI не може резолвити репозиторії, тут починайте.
Рішення: Якщо DNS вказує кудись дивно (наприклад на домашній роутер), виправляйте. Не «обходьте» це через /etc/hosts.
Завдання 9: Перевірити режим SELinux і останні відмови
cr0x@server:~$ getenforce
Enforcing
cr0x@server:~$ sudo ausearch -m avc -ts recent | tail -n 5
type=AVC msg=audit(1738833941.112:842): avc: denied { name_connect } for pid=2213 comm="podman" dest=53 scontext=system_u:system_r:container_t:s0 tcontext=system_u:object_r:dns_port_t:s0 tclass=tcp_socket permissive=0
Значення: SELinux у режимі enforcing і є AVC denial, пов’язаний з контейнером, який намагається дістатися DNS. Це не «SELinux просто дратує»; це сигнал про маркування/політику та правила контейнерної мережі.
Рішення: Дослідіть контекст і потрібну політику; не вимикайте SELinux глобально. Виправляйте корінь проблеми (політика контейнера, маркування порту DNS або конфігурацію рантайму контейнера).
Завдання 10: Перевірити стан firewalld і відкриті порти
cr0x@server:~$ sudo systemctl status firewalld --no-pager
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-02-06 09:02:11 UTC; 22min ago
cr0x@server:~$ sudo firewall-cmd --get-active-zones
public
interfaces: ens192
cr0x@server:~$ sudo firewall-cmd --list-services
ssh
Значення: Фаєрвол увімкнений, інтерфейс у зоні public, відкрито тільки SSH. Хороша база.
Рішення: Якщо вам потрібен node_exporter, додайте порт/сервіс явно. Якщо бачите «services: dhcpv6-client samba cockpit whatever», почистіть це.
Завдання 11: Перевірити тиск ресурсів системи (CPU, пам’ять, IO) швидко
cr0x@server:~$ uptime
09:27:51 up 1:12, 1 user, load average: 0.26, 0.18, 0.09
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 15Gi 1.8Gi 11Gi 170Mi 2.4Gi 13Gi
Swap: 4.0Gi 0B 4.0Gi
Значення: Навантаження низьке, пам’ять здорова, swap не використовується. Якщо CI jobs повільні, зараз це, ймовірно, не через голий CPU.
Рішення: Якщо навантаження високе і доступної пам’яті мало, вирішіть: додати RAM, зменшити конкурентність або ізолювати «галасливі» задачі.
Завдання 12: Помітити вузькі місця IO і стрибки затримки
cr0x@server:~$ iostat -xz 1 3
Linux 6.12.0-0.el10.x86_64 (runner01) 02/06/2026 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.10 0.00 3.20 8.60 0.00 76.10
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
sda 8.00 320.0 0.00 0.00 6.20 40.00 45.00 2048.0 2.00 4.26 18.40 45.51 0.92 68.00
Значення: iowait немаленький, write await доволі високий, і використання диска високе. Класичний профіль CI-раннера: багато записів, метадантичний обіг і кеші.
Рішення: Розгляньте швидше сховище, відокремлення дисків для збірок/робочих просторів або переміщення кешів у tmpfs/ramdisk вибірково (з лімітами). Також зменшіть кількість одночасних задач на вузол.
Завдання 13: Підтвердити, що journald/збереження логів не з’їсть /var
cr0x@server:~$ sudo journalctl --disk-usage
Archived and active journals take up 1.2G in the file system.
cr0x@server:~$ sudo grep -E 'SystemMaxUse|RuntimeMaxUse' /etc/systemd/journald.conf
#SystemMaxUse=
#RuntimeMaxUse=
Значення: Журнали вже займають місце, і немає явного ліміту. На галасливих CI-ноди це росте, доки не вдарить в ліміт файлової системи.
Рішення: Встановіть SystemMaxUse (і, можливо, SystemMaxFileSize) у розумний ліміт відповідно до розміру /var.
Завдання 14: Перевірити розташування сховища контейнерів і його ріст
cr0x@server:~$ sudo podman info --format '{{.Store.GraphRoot}}'
/var/lib/containers/storage
cr0x@server:~$ sudo du -sh /var/lib/containers/storage
6.4G /var/lib/containers/storage
Значення: Шари контейнерів живуть під /var. Ось чому розмір /var має значення.
Рішення: Якщо ви запускаєте важкі контейнерні збірки, розгляньте розташування сховища контейнерів на власному LV (або виділеному диску), щоб уникнути голодування системного стану.
Завдання 15: Перевірити cgroups v2 і сумісність контейнерів
cr0x@server:~$ stat -fc %T /sys/fs/cgroup/
cgroup2fs
Значення: Ви на cgroups v2. Деякі старі інструменти контейнерів і агенти моніторингу ще припускають семантику v1.
Рішення: Переконайтеся, що ваше CI-пЗ підтримує cgroups v2. Якщо ні — оновіть інструменти, ніж понижувати поведінку ОС, хіба що немає вибору.
Завдання 16: Перевірити готовність до віртуалізації (якщо ви запускаєте KVM/libvirt)
cr0x@server:~$ lscpu | egrep 'Virtualization|Vendor ID|Model name'
Vendor ID: GenuineIntel
Model name: Intel(R) Xeon(R) CPU
Virtualization: VT-x
cr0x@server:~$ lsmod | egrep 'kvm|kvm_intel'
kvm_intel 503808 0
kvm 1490944 1 kvm_intel
Значення: CPU підтримує віртуалізацію і модулі KVM завантажені.
Рішення: Якщо віртуалізація недоступна, не витрачайте час на дебаг libvirt. Виправте налаштування BIOS або оберіть інший хост/профіль гіпервізора.
Плейбук для швидкої діагностики
Це плейбук, який я хочу бачити на стіні поряд із CI-кластером. Коли збірки повільні або інсталяції нестабільні, не «шукати» — йти найкоротшим шляхом до вузького місця.
По-перше: доведіть, що це не DNS/доступ до репо
- Перевірте резолюцію DNS і доступність репо/дзеркал. Помилки CI часто виглядають як «install package failed», але корінь — ім’я або проксі.
- Підтвердіть синхронізацію часу. TLS-помилки і проблеми з метаданими репо можуть бути через зсув часу.
cr0x@server:~$ getent hosts mirror.internal
10.20.30.50 mirror.internal
cr0x@server:~$ chronyc tracking | head
Reference ID : 0A0B0C0D (ntp1.example)
Рішення: Якщо DNS повільний або нестабільний, виправляйте це перш ніж торкатись чогось іншого. Ви не можете оптимізувати систему, яка не знаходить свої залежності.
По-друге: перевірте тиск на зберігання і затримки IO
- Диск повний? Іноди вичерпані? Thin pool заповнений? Це проявляється як «випадкові помилки».
- IO latency (await) високий? Ось чому збірки повільні.
cr0x@server:~$ df -hT | sed -n '1,6p'
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/cs-root xfs 40G 3.2G 37G 8% /
/dev/mapper/cs-var xfs 80G 78G 2.0G 98% /var
cr0x@server:~$ iostat -xz 1 2 | tail -n 5
sda 9.00 360.0 0.00 0.00 8.10 40.00 60.00 2600.0 1.00 1.64 25.90 43.33 1.40 85.00
Рішення: Якщо /var зайнятий на 98%, зупиніться. Очистіть кеші/логи або розширте LV. Якщо disk await високий, зменшіть конкурентність або апгрейдьте сховище.
По-третє: перевірте CPU, пам’ять і контенцію планувальника
- Високе навантаження з низьким IO wait? Ймовірна насиченість CPU.
- Мало доступної пам’яті зі swap-активністю? Тиск пам’яті або неконтрольовані задачі.
- Високий steal time? Контенція у гіпервізора; ваш VM хост перескуплений.
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 1123456 81234 2234560 0 0 5 80 150 300 12 3 77 8 0
3 1 0 123456 40000 900000 0 0 0 2000 500 1200 40 10 10 40 0
Рішення: Якщо st (steal) ненульовий і постійний, справжній вузький місце upstream. Ескалюйте до команди віртуалізації або перемістіть раннери.
Типові помилки: симптом → корінна причина → виправлення
1) Симптом: CI jobs раптово падають із «No space left on device», але df показує вільне місце
Корінна причина: Вичерпані іноди (занадто багато дрібних файлів) або заповнений інший том (часто /var або /tmp).
Виправлення: Перевірте df -i і використання за точками монтування. Збільшіть інод-контингент шляхом зміни/пересоздання файлової системи (довгостроково) і зменшіть обіг файлів (прибирання, політика збереження артефактів). Розділіть /var на ранній стадії.
2) Симптом: Зборки повільні лише на деяких раннерах
Корінна причина: Різниця в затримках зберігання (різні рівні дисків) або steal time на перескуплених гіпервізорах.
Виправлення: Порівняйте iostat -xz і vmstat між раннерами. Стандартизуйте бекенд дисків. Не змішуйте «швидкі» і «повільні» ноди в одному пулі, якщо ваш шедулер не знає топологію.
3) Симптом: Після оновлення сервіс не стартує; логи говорять про permission denied
Корінна причина: SELinux denial після зміни шляху, нового порту або жорсткішої одиниці сервісу.
Виправлення: Використайте ausearch -m avc, щоб знайти відмови, потім виправте маркування з restorecon або налаштуйте політику. Не вимикайте SELinux глобально.
4) Симптом: Хост завантажується в dracut emergency shell після перезавантаження
Корінна причина: Неправильний UUID у fstab, відсутні драйвери в initramfs або зміни порядку дисків у шаблоні VM.
Виправлення: Завантажтеся в rescue, перевірте blkid і /etc/fstab, при потребі перебудуйте initramfs. Віддавайте перевагу монтуванню за UUID і стабільним іменам пристроїв.
5) Симптом: DNF повільний, «metadata download» зависає
Корінна причина: Проблеми DNS, проксі MTU або проблеми вибору дзеркал.
Виправлення: Валідируйте DNS (getent hosts), перевірте MTU і віддавайте перевагу внутрішнім дзеркалам для CI-важких середовищ.
6) Симптом: Контейнерні збірки падають після оновлення ОС, а збірки на хості працюють
Корінна причина: Питання cgroups v2, обмеження rootless мережі або зміни SELinux-політик, що впливають на зберігання контейнерів.
Виправлення: Підтвердіть cgroups (stat -fc %T /sys/fs/cgroup), перевірте podman info, перегляньте AVC denials і оновіть контейнерний інструментарій/образи.
7) Симптом: SSH працює з деяких підмереж, але не з інших
Корінна причина: Призначення зони firewalld або невідповідність згори мережевих ACL.
Виправлення: Перевірте активні зони і інтерфейси, потім встановіть явні правила. Не вимикайте firewalld через складність мережі.
Три корпоративні міні-історії (про те, чим не хваляться)
Міні-історія 1: Інцидент через хибне припущення
Компанія мала акуратний CI-кластер: дюжина VM, кілька кешів збірок і щотижневе вікно патчів, яке всі ігнорували, поки щось не зламалося. Вони вирішили перейти з клона RHEL на CentOS Stream для «ранньої сумісності». Звучить відповідально.
Хибне припущення було непомітним: вони думали, що Stream поводитиметься як їхній старий rebuild в одному конкретному відношенні — стабільність репозиторіїв. Їхній pipeline почав тягнути оновлення вдень, бо хтось залишив запланований dnf -y update таймер на раннерах. Одного дня апдейт тулчейна зайшов, версія компілятора змінилася на мінор, і частина збірок почала давати трохи інші артефакти. Спочатку нічого явно не падало. Але перевірка чексуми показала різницю, і релізний процес зупинився.
Команди сперечалися про «недетерміновані збірки» і «можливо кеш корумпований». Жодне з них. Це були раннери, що оновилися посеред потоку. Болісна частина була не в виправленні; болісна частина — усвідомлення, що у них немає політики, коли і як оновлюється CI-інфраструктура.
Вони відновилися, заморозивши оновлення в робочий час, будуючи золоті образи щотижня і прокочуючи їх через staging CI-пул перед основним. Stream не був лиходієм. Лиходій — віра, що оновлення робляться за нагадуванням.
Міні-історія 2: Оптимізація, яка зіграла злий жарт
Ще одна організація мала хитрий план зберігання: вони використовували LVM thin provisioning для робочих просторів CI, бо це дозволяло «виділяти» величезні томи без купівлі додаткового диска. На папері елегантно. В реальності thin pool ділився занадто багатьма ентузіастичними проєктами.
Вони також «оптимізували», піднімаючи конкурентність задач. Збірки стали швидшими — поки не перестали бути такими. Одного ранку кілька раннерів почали падати з помилками файлової системи. Thin pool досяг 100% використання даних. Thin provisioning не падає ввічливо; воно падає як пастка. Записи зависають, файлові системи панікують, і всі раптом дізнаються, що таке «metadata percent».
Термінове виправлення було непривабливим: зупинити все, видалити кеші і розширити базове сховище. Довгострокове виправлення було нудним: налаштувати моніторинг використання thin pool, ввести квоти по проєкту і перестати oversubscribe сховище без guardrails.
Вони залишили thin provisioning, але тільки там, де було сповіщення і чітка відповідальність. Оптимізація не була неправильною. Вона була передчасною, немоніторною і продавалась як «безкоштовна ємність», що є найдорожчою брехнею у зберіганні.
Міні-історія 3: Нудна, але правильна практика, що врятувала ситуацію
Третя команда отримала репутацію «повільних», бо наполягала на Kickstart-збірках і строгому pipeline базових образів. Розробники хотіли свободу підправляти раннери вручну. SRE казали «ні» і викликали невдоволення на зборах.
Потім оновлення ядра в лабораторії виявило регресію, що впливала на певний NIC-драйвер під великим навантаженням. Кілька раннерів почали втрачати мережеві з’єднання під час завантаження артефактів. Схоже на випадкову непостійність — саме те, що витрачає тижні.
Оскільки команда мала pipeline золотих образів, вони могли відкотитися до попереднього відомо-гарного ядра по всьому фліту контрольовано. І головне — вони могли відтворити проблему, піднімаючи тестові раннери з обох образів і порівнювати поведінку під однаковим навантаженням. Ніякої археології. Ніякого «хто що змінив». Просто контрольований експеримент.
Postmortem був майже розчаровано спокійним. Їхня нудна практика — ім’ідж-орієнтовані образи, контрольовані оновлення та staging-пул — перетворила потенційний багатокомандний скандал на невеликий інцидент. Вони відправили реліз вчасно. Ніхто не писав драматичних Slack-повідомлень. Це перемога.
Жарт #2: Найкращий CI-раннер схожий на хорошу сантехніку — ніхто його не помічає, доки хтось не вирішить «оптимізувати».
Чеклісти / покроковий план
Покроковий план інсталяції (інтерактивно або через Kickstart)
- Визначте роль: CI-раннер, гіпервізор лабораторії або універсальний тест-хост. Це визначає зберігання і підбір пакетів.
- Обрати завантаження UEFI (якщо немає обмежень) і підтвердити налаштування прошивки VM перед інсталяцією.
- Виберіть мінімальну інсталяцію плюс потрібні пакети; уникайте GUI, якщо нема явної потреби.
- Схема зберігання:
- Створіть ESP і фіксовані розділи /boot.
- Створіть LVM PV і VG із запасом.
- Створіть окремий LV для /var, розмір під логи + контейнери + кеші.
- Мережа: налаштуйте через NetworkManager, переконайтеся, що DNS вказує на надійний резолвер.
- Час: встановіть часовий пояс UTC для серверних флітів; увімкніть NTP.
- Користувачі: створіть адміністратора; за можливості обмежте SSH ключами.
- Безпека: тримайте SELinux в enforcing; тримайте firewalld увімкненим.
- Політика оновлень: визначте каденцію патчів і чи самостійно оновлюються раннери. Моя порада: без авто-оновлень на раннерах без воріт.
- Snapshot/золотий образ: зніміть базовий образ лише після проходження валідаційних команд.
Пост-інсталяційний чекліст (запустіть перед додаванням у CI-пул)
- Ідентичність ОС правильна:
/etc/os-release - Режим завантаження правильний: перевірка UEFI
- Розбивка диска правильна:
lsblk,df -hT,df -i - Є запас у LVM:
vgs - Репозиторії здорові:
dnf repolist,dnf check-update - Синхронізація часу:
timedatectl,chronyc tracking - Мережа правильна: вивід
nmcliзбігається з очікуваними IP/DNS - SELinux в enforcing:
getenforce; немає несподіваного AVC-спаму - firewalld увімкнений і мінімальний:
firewall-cmd - Базова перевірка продуктивності:
iostat,vmstatпід пробною збіркою
Операційний чекліст (щотижня)
- Застосовуйте оновлення у контрольоване вікно; прокочуйте через staging-пул перш ніж у основний.
- Перевіряйте тенденції росту /var; обмежуйте journald; чистіть шари контейнерів.
- Перевіряйте NTP; слідкуйте за дрейфом часу на VM.
- Переглядайте AVC denials; вирішуйте повторювані належним чином.
- Переконайтеся, що конкурентність CI відповідає ємності диска, а не бажанням.
FAQ
1) Чи стабільний CentOS Stream 10 для CI?
Так, якщо ваш CI сконструйований так, щоб витримувати зміни: staged rollouts, відтворювані образи і політика патчів. Якщо ваші раннери обслуговуються вручну як «пет», Stream швидко це виявить.
2) Чи варто використовувати Stream 10 у продакшні?
Іноді так, але не робіть це за замовчуванням. Для продакшну питання не «чи може це працювати», а «чи є у вас дисципліна для управління швидшим рухом оновлень?» Багато організацій цього не мають.
3) Мінімальна інсталяція чи повна серверна?
Мінімальна. Додавайте тільки необхідне. Кожен зайвий пакет — це площа поверхні для оновлень і потенційних конфліктів у CI.
4) Чи справді потрібен окремий /var?
Якщо ви запускаєте CI-навантаження — так. /var — місце зустрічі стану системи і високого обігу CI-сміття. Відокремлення — недорога страховка.
5) XFS чи ext4 для CI-раннерів?
XFS — надійний дефолт для / і /var у RHEL-подібних системах. Тримайте ext4 для /boot. Не вводьте екзотичні файлові системи, якщо ваша команда не має плану відновлення і досвіду.
6) Чи варто відключати SELinux, щоб полегшити збірки контейнерів?
Ні. Використовуйте журнали AVC, щоб виправити маркування/політику. Вимкнення SELinux обмінює вирішувану конфігураційну проблему на постійний ризик і непослідовну поведінку між середовищами.
7) Як зупинити дрейф раннерів з часом?
Золоті образи + управління конфігурацією. Перебудовуйте раннери регулярно. Якщо раннер «особливий», він також недовірливий.
8) Мої DNF інсталяції повільні в CI. Як найкраще виправити?
Використовуйте внутрішнє дзеркало або кеш-проксі і виправляйте DNS. Потім настройте кешування DNF. CI підсилює неефективності пакетного менеджера у реальні гроші та час.
9) Контейнери чи VM для CI джобів?
Контейнери — для більшості збірок і тестів. VM — коли потрібно тестувати поведінку при завантаженні, взаємодію з ядром або системні сервіси в реалістичному середовищі.
10) Яке найпоширеніше вузьке місце на CI-хостах на базі Stream?
Зберігання. Зокрема: заповнення /var, розростання шарів контейнерів і затримки IO під навантаженням. CPU зазвичай на другому місці.
Висновок: наступні кроки, що справді зменшують pager noise
CentOS Stream 10 — це правильний різновид дискомфорту для лабораторій і CI: він штовхає вас до дисциплінованих інсталяцій, чіткої політики оновлень і інфраструктури, що переносить зміни. Якщо ви встановите його як хобі-ОС, він поводитиметься відповідно. Якщо встановите його як продакшн, він стане гострим раннім попередженням про «наступний RHEL».
Практичні наступні кроки:
- Напишіть (або виправте) ваш Kickstart так, щоб вибір диска, розмір /var і налаштування безпеки були явними.
- Підніміть staging CI-пул, що патчиться першим; просувайте в основний пул тільки після дня чистих прогонів.
- Обмежте journald, чистіть зберігання контейнерів і моніторьте використання /var та інодів.
- Впровадьте плейбук швидкої діагностики і зробіть його стандартною відповіддю на «CI повільний».
- Визначте політику оновлень письмово. Потім забезпечте її автоматизацією, а не добрими намірами.