CI/CD: інтеграція, доставка, розгортання
Зміст
Уяви команду з десяти розробників, де кожен два тижні пише свою фічу у власній гілці й ні з ким не зливається. За два тижні всі одночасно намагаються влити код у спільну гілку — і починається те, що індустрія назвала інтеграційним пеклом (integration hell): конфлікти злиття на пів дня, «а в мене локально працювало», білд, який не збирається, тести, які ніхто не запускав, і ніхто не знає, чия саме зміна все зламала. Реліз, який планували на п'ятницю, з'їжджає на наступний тиждень. CI/CD — це відповідь індустрії на цей біль: не героїчно інтегруватися раз на спринт, а робити це маленькими порціями щодня й одразу автоматично перевіряти.
Для AQA ця тема — не «щось про девопсів». Пайплайн (pipeline) — це середовище, у якому живуть твої автотести: вони запускаються там на кожен коміт, там падають з незрозумілих причин, там стають гейтом, що блокує реліз. На співбесіді junior/middle AQA майже гарантовано питають «чим CI відрізняється від CD», «що таке пайплайн» і «де в ньому QA» — і плутанина тут одразу видає рівень. Тож розберемо механізм, а не визначення з вікіпедії.
«Інтеграційне пекло» і навіщо CI
Чому інтеграція взагалі болить? Бо що довше дві гілки розходяться, то більше між ними накопичується прихованих несумісностей: конфлікти в одних файлах, мовчазні логічні конфлікти в різних (мій код і твій код окремо коректні, а разом ламають фічу), розбіжність залежностей. Складність інтеграції росте не лінійно, а різко — і вибухає саме тоді, коли часу вже немає.
Безперервна інтеграція (continuous integration, CI) розвертає цю логіку: якщо інтегруватися боляче — роби це якнайчастіше, доки порція змін маленька. Кожен розробник щодня (а то й кілька разів на день) зливає свою роботу у спільну магістраль (trunk), і на кожне таке злиття автоматика збирає проєкт і ганяє тести. Дрібний конфлікт видно й лагодиться за хвилини, а не за пів дня наприкінці спринту.
Ключова думка, яку люблять питати на співбесіді: CI — це передусім практика (дисципліна команди), а не інструмент. Можна поставити Jenkins чи GitHub Actions і не мати ніякого CI, якщо всі сидять по своїх гілках тижнями. І навпаки: суть CI — часте злиття в спільну гілку плюс автоматична перевірка кожного злиття. Інструмент лише автоматизує те, що команда й так вирішила робити.
Три звички, без яких CI не працює:
- Часті дрібні коміти в спільну гілку — не «велика фіча раз на два тижні», а маленькі порції щодня. Це прямо пов'язано з trunk-based development (див. розділ Pull Request і стратегії гілкування).
- Автоматична перевірка на кожен коміт — білд і тести запускає машина, не людина за настроєм.
- Зелена магістраль понад усе. Якщо перевірка червона — це стоп-сигнал: спільна гілка зламана, і команда лагодить її раніше, ніж додає нове. «Не зупиняй конвеєр із дефектом» — той самий принцип, що на реальному складальному конвеєрі.
Continuous Integration: як це виглядає механічно
Механіка проста й однакова майже всюди. Розробник робить git push (або відкриває Pull Request). CI-сервер помічає цю подію, бере свіжий код, у чистому середовищі збирає проєкт, проганяє тести й повертає статус: зелено або червоно. Статус видно прямо в Pull Request — червоний чек блокує злиття, зелений дозволяє.
Що дає ця петля на практиці:
- Регресію ловить машина за хвилини після коміту, а не тестувальник за тиждень перед релізом.
- «В мене локально працювало» більше не аргумент: збірка йде в чистому, відтворюваному середовищі, однаковому для всіх (звідси природний перехід до контейнерів — див. Docker і тестові середовища).
- Історія перевірок прив'язана до комітів: видно, який саме коміт зробив магістраль червоною.
Тут і живуть твої автотести. У CI прогін відрізняється від локального: headless-браузер, інші ресурси агента, інші таймінги — і тест, зелений у тебе на машині, у CI може миготіти. Це окрема велика тема (див. Автотести в CI: стабільність і дебаг), але вже тут важливо засвоїти: нестабільний (flaky) тест руйнує весь сенс CI. Якщо пайплайн падає «через раз» без причини, команда перестає довіряти червоному кольору й починає його ігнорувати — а тоді гейт не гейт.
CI vs Continuous Delivery vs Continuous Deployment
Це найчастіше плутане місце, бо обидва CD — і Delivery, і Deployment — скорочуються однаково. Розберемо по межах відповідальності. Уяви конвеєр: коміт → білд → тести → готовий артефакт → деплой на staging → деплой на prod. Три практики покривають різні відрізки цього конвеєра.
- Continuous Integration (CI) відповідає за відрізок від коміту до готового артефакта: інтегрувати, зібрати, протестувати. На виході — перевірена збірка. Куди й коли її котити — уже поза CI.
- Безперервна доставка (continuous delivery) розширює конвеєр далі: кожна зелена збірка автоматично доводиться до стану «готова до релізу» — прогнана через усі стадії, розгорнута на staging, залишилося тільки натиснути кнопку. Рішення коли котити на prod ухвалює людина. Тобто prod-деплой — за один клік, але клік свідомий.
- Безперервне розгортання (continuous deployment) прибирає й цю кнопку: кожна збірка, що пройшла всі перевірки, автоматично їде на prod без ручного апруву. Людина в петлю релізу вже не вмикається — її роль перенесена в автоматичні гейти й моніторинг.
Головний водорозділ між двома CD — наявність ручного апруву перед prod. Continuous Delivery = «завжди готові релізнути одним кліком, але вирішує людина». Continuous Deployment = «релізимо самі, без кліку». Друге вимагає значно зрілішого автоматизованого контролю якості: раз людина не дивиться перед prod, то весь захист — це перевірки в пайплайні (і сильна спостережуваність з можливістю швидкого rollback, див. Середовища, деплой і релізи).
| Практика | Що автоматизовано | Хто вирішує «котимо на prod» |
|---|---|---|
| Continuous Integration | Злиття, білд, тести | Реліз узагалі поза скоупом |
| Continuous Delivery | Усе аж до staging; prod — за одну дію | Людина (свідомий клік) |
| Continuous Deployment | Усе, включно з prod | Ніхто — автоматика, якщо перевірки зелені |
Практична підказка на співбесіду: якщо тебе просять «в двох словах» — CI про інтеграцію коду, Delivery про готовність релізу будь-коли, Deployment про автоматичний реліз без людини. Continuous Delivery — обов'язкова передумова Continuous Deployment, але не навпаки.
Пайплайн як конвеєр якості
Пайплайн — це автоматизована послідовність стадій, які код проходить від коміту до (потенційно) продакшену. Правильна ментальна модель — конвеєр контролю якості: на кожній станції стоїть перевірка, і деталь їде далі, лише якщо станцію пройдено. Не пройшов lint — далі не поїхав; впав unit-тест — до e2e справа не дійшла.
Чому саме конвеєр, а не «купа перевірок». Порядок стадій вибирають за принципом fail fast — «впасти якомога раніше й дешевше»: спершу найшвидші й найдешевші перевірки, потім повільні й дорогі.
Логіка тут економічна: немає сенсу тримати агента пів години на e2e, якщо код не проходить навіть перевірку типів — цю помилку треба показати автору за секунди. Порядок «lint → типи → unit → integration → e2e» прямо лягає на піраміду тестування (широка дешева основа знизу, вузький дорогий верх). Це і є конвеєр якості: кожна стадія — фільтр, а разом вони не пускають дефект далі по трубі.
Детальну будову — стадії, джоби, тригери, артефакти джобів — розбирає окрема глава Будова пайплайна. А те, яка стадія має блокувати злиття і що ганяти на PR проти nightly, — це стратегія якості в пайплайні, канон теми — Стратегія якості в пайплайні. Тут важливий сам образ: не «набір скриптів», а впорядкована черга гейтів.
Білд і артефакт
Два слова, які junior часто вживає навмання. Розведемо їх.
Білд (build) — це процес перетворення вихідного коду в форму, придатну до запуску чи розгортання. Для компільованих мов це буквально компіляція. Для веб-стека «збірка» теж є, хоч JavaScript і не компілюється в машинний код: встановити залежності, перевірити типи TypeScript, зібрати й мінімізувати бандл (Vite/webpack/esbuild), проставити хеші у назви файлів для cache busting (механіку версіонування ассетів дивись у главі Кешування). Білд — це дія, процес.
Артефакт (artifact) — це результат білда: незмінний пакет, готовий до розгортання. Залежно від проєкту це зібраний бандл, Docker-образ, .jar, .zip, набір статичних файлів. Ключова властивість — незмінність.
Головний принцип, який варто винести: build once, deploy many — «зібрати один раз, розгорнути багато разів». Артефакт збирають раз, а потім той самий незмінний артефакт просувають середовищами: staging → prod. Не перезбирають окремо під кожне середовище. Чому це критично саме для QA:
- Ти тестуєш на staging той самий байт-у-байт артефакт, що поїде в prod. Якби під prod робили нову збірку, твоє тестування staging нічого б не гарантувало — у prod могла б заїхати інша збірка.
- Артефакт трасується до конкретного коміту й версії. Зловив баг у prod — знаєш точну збірку й точний коміт, звідки вона зросла.
- Різницю поведінки між середовищами треба шукати не в коді (він той самий), а в конфігурації та даних (див. Секрети та конфігурація в CI).
Звідси й межа між білдом і деплоєм: білд виробляє артефакт, деплой ставить готовий артефакт у середовище. Це різні дії, і плутати їх — типова помилка новачка.
Shift-left і швидкий фідбек
Зсув уліво (shift-left) — це принцип «пересувати перевірки якості якомога раніше на часовій осі проєкту» (уліво, ближче до написання коду). Основа тут — відома крива вартості дефекту: чим пізніше знайдено баг, тим дорожче його виправити (детально — у розділі основ тестування). Баг, спійманий на коміті, коштує кількох хвилин; той самий баг у проді — інциденту, hotfix-у й репутації.
CI — це головний технічний механізм shift-left: він переносить прогін тестів із «фази тестування наприкінці» на «кожен коміт». Тестування перестає бути окремим етапом після розробки й вплітається в саму розробку.
Але shift-left працює лише за умови швидкого зворотного зв'язку (fast feedback). Уся цінність CI тримається на швидкості петлі «закомітив → дізнався результат». Якщо пайплайн іде дві години або миготить — петля розривається: люди перестають чекати результату, накопичують зміни великими пачками, зливаються рідше — і ти повертаєшся в те саме інтеграційне пекло, тільки з логотипом CI-системи згори. Тому швидкість і стабільність пайплайна — це не «зручність», а умова, за якої CI взагалі має сенс. (Питання спільного володіння автотестами й shift-left з боку автоматизації — окрема тема в розділі стратегії автоматизації.)
Місце QA в CI/CD-культурі
Найважливіший зсув, який приносить CI/CD, — якість не «пришивають» наприкінці, її вбудовують у конвеєр. Стара модель «розробники накодили → кинули QA через паркан → QA потиць руками → підписали реліз» у безперервній доставці не працює: релізів забагато й вони автоматичні. Роль QA не зникає — вона стає роллю стюарда автоматизованої мережі безпеки.
Що QA реально робить у CI/CD-культурі:
- Пише й володіє автоперевірками в пайплайні — тими самими тестами, що стоять гейтами на кожному коміті.
- Визначає гейти якості — які перевірки блокують злиття, а які лише інформують; де e2e має бути блокувальним, а де винесеним у nightly (канон — Стратегія якості в пайплайні).
- Тріажить падіння — червоний пайплайн це баг продукту, баг тесту чи інфраструктура? Це щоденна робота AQA, і плутати ці три причини дорого (див. Автотести в CI).
- Тримає сьюту вартою довіри — бо, повторимо, один хронічно flaky тест знецінює весь гейт: команда починає ігнорувати червоне.
- Рев'ює тестовий код у Pull Request нарівні з продуктовим — тести теж код, який гниє й ламається.
Головна теза для співбесіди: у зрілій CI/CD-культурі якість — відповідальність усієї команди, але QA — це та людина, що проєктує й доглядає автоматизований механізм, який цю якість стереже. Це перехід від «тестувальника, що клікає» до інженера, що володіє захисною сіткою релізу.
Типові помилки
- «У нас є Jenkins, отже у нас CI» — виглядає як CI, а насправді інструмент ≠ практика. Якщо гілки живуть тижнями й зливаються рідко, ніякий сервер не робить це безперервною інтеграцією. CI — це дисципліна частого злиття, автоматика лише її обслуговує.
- «Continuous Delivery і Continuous Deployment — те саме» — виглядає однаково (обидва CD), а насправді різниця в одному: чи є ручний апрув перед prod. Delivery — людина тисне кнопку; Deployment — кнопки немає.
- «Білд і деплой — одне й те саме» — виглядає як один крок, а насправді білд виробляє артефакт, деплой ставить готовий артефакт у середовище. Артефакт збирають раз, деплоять багато разів.
- «Зелений пайплайн = можна релізити» — виглядає як гарантія, а насправді зелене означає лише «перевірки, які ми написали, пройшли». Тонка сьюта чи flaky-тести дають зелене на дірявому покритті. Зелений колір рівно настільки цінний, наскільки чесні перевірки за ним.
- «Впав пайплайн — просто перезапущу джобу» — виглядає як швидке рішення, а насправді перезапуск маскує flaky-тест або реальну регресію. «Перезапустив і позеленіло» — це не полагоджено, це відкладено; звичка так робити вбиває довіру до гейта.
- «CI/CD — робота девопсів, не QA» — виглядає як чужа зона, а насправді саме гейти якості, тріаж падінь і здоров'я тестової сьюти — пряма відповідальність QA. Девопс володіє інфраструктурою, QA — вмістом перевірок.
Підсумок
- CI — це практика, а не інструмент: часте злиття дрібних змін у спільну гілку плюс автоматичний білд і тести на кожне злиття. Народилася вона з «інтеграційного пекла» — болю рідкісної інтеграції великих гілок.
- CI → Delivery → Deployment — це розширення того самого конвеєра. CI доводить до артефакта; Continuous Delivery — до «готово релізити одним кліком людини»; Continuous Deployment — до автоматичного prod без кліку. Різниця двох CD — ручний апрув перед prod.
- Пайплайн — конвеєр якості з fail-fast порядком: дешеві швидкі перевірки спершу, дорогі повільні потім; кожна стадія — фільтр, що не пускає дефект далі.
- Артефакт збирають раз і просувають середовищами незмінним (build once, deploy many): тестуєш на staging рівно те, що поїде в prod.
- CI — головний механізм shift-left, а його цінність тримається на швидкому й стабільному фідбеку. У CI/CD-культурі QA не гейт наприкінці, а стюард автоматизованої мережі безпеки.
Що питають на співбесіді
- «Чим CI відрізняється від CD?» — класика-пастка через подвійне «CD». Сильна відповідь одразу розводить Continuous Delivery і Continuous Deployment і називає водорозділ — ручний апрув перед prod. Інтерв'юер перевіряє, чи не каша в голові.
- «Що таке CI своїми словами?» — тут дивляться, чи скажеш «часте злиття + автоматична перевірка на кожен коміт» і чи згадаєш, що це практика, а не просто «сервер, що ганяє тести». Згадка про «інтеграційне пекло» як причину — сильний плюс.
- «Що таке пайплайн і в якому порядку йдуть стадії?» — очікують fail-fast: lint/типи → unit → integration → e2e, і пояснення чому саме так (дешеве й швидке раніше).
- «Різниця між білдом і деплоєм? Що таке артефакт?» — перевіряють, чи розумієш build once, deploy many і чому важливо тестувати той самий артефакт, що піде в prod.
- «Де роль QA у CI/CD?» — слабка відповідь: «QA тестує в кінці». Сильна: QA володіє гейтами якості, тріажить падіння, тримає сьюту стабільною, рев'ює тестовий код — якість вбудована в конвеєр, а не пришита наприкінці.
- «Що таке shift-left?» — очікують зв'язку з вартістю дефекту й з CI як механізмом раннього виявлення, а не просто переклад слова.
Джерела
- ISTQB Certified Tester Foundation Level (CTFL) 4.0 Syllabus — розділи 2.1.4 «DevOps and Testing» (CI/CD і роль тестування) та 2.1.5 «Shift-Left Approach».
- Martin Fowler — Continuous Integration — канонічна стаття, що визначає CI як практику й формулює її ключові правила.
- Continuous Delivery (Jez Humble, David Farley) — першоджерело понять Continuous Delivery і deployment pipeline, включно з принципом build once, deploy many.
- GitHub Docs — About continuous integration — стисле практичне пояснення CI на прикладі реального CI-сервісу.
Що таке «інтеграційне пекло» і чому саме воно породило CI?
Це ситуація, коли команда довго не зливає код: кожен тижнями сидить у власній гілці, а наприкінці всі разом намагаються влити роботу в спільну гілку. Що довше гілки розходяться, то більше між ними накопичується несумісностей — і явних (той самий файл правили двоє), і тихих логічних (два окремо коректні шматки разом ламають фічу), і розбіжностей у залежностях. Складність такого злиття росте не лінійно, а різко, і вибухає рівно тоді, коли до релізу лишаються дні. Безперервна інтеграція (continuous integration, CI) перевертає логіку: якщо інтегруватися боляче — роби це часто, поки порція змін дрібна, і тоді конфлікт видно й лагодиться за хвилини. Тобто CI народилася не як технологія, а як відповідь на конкретний організаційний біль.
CI — це інструмент чи практика? Чому це питання не чіпляння до слів?
CI — передусім практика, дисципліна команди, а не сервер, який ти встановив. Можна підняти GitHub Actions чи Jenkins і не мати ніякого CI, якщо всі далі сидять по гілках тижнями й зливаються раз на спринт. І навпаки: суть CI — часте злиття в спільну магістраль плюс автоматична перевірка кожного злиття, а інструмент лише автоматизує те, що команда й так вирішила робити. На співбесіді ця відповідь одразу відрізняє того, хто розуміє механізм, від того, хто завчив назви систем. Слабка відповідь звучить як «CI — це коли стоїть Jenkins, що ганяє тести».
Розкажи своїми словами, що таке безперервна інтеграція.
Два стовпи: розробники часто (щодня чи кілька разів на день) зливають дрібні порції змін у спільну гілку, і на кожне таке злиття автоматика збирає проєкт та проганяє тести. Мета — тримати спільну гілку в робочому стані постійно, а не «доводити її до пуття» перед релізом. Сильна відповідь додає причину — «інтеграційне пекло» рідкісного злиття великих гілок — і наголошує, що це практика, а не просто «машина, яка запускає тести». Ще один маркер зрілості: згадка про trunk-based development як спосіб життя, що робить часте злиття можливим. Слабка відповідь зупиняється на «сервер збирає код».
Які звички команди роблять CI справді робочим?
Перша — часті дрібні коміти в спільну гілку замість великої фічі раз на два тижні. Друга — автоматична перевірка (білд плюс тести) на кожен коміт, яку запускає машина, а не людина за настроєм. Третя, і найнедооціненіша — «зелена магістраль понад усе»: якщо перевірка червона, спільна гілка вважається зламаною, і команда лагодить її раніше, ніж додає нове. Це той самий принцип, що на реальному складальному конвеєрі — не пускай далі деталь із дефектом. Без третьої звички CI перетворюється на декорацію: червоне накопичується, ніхто його не чинить, гейт втрачає сенс.
Опиши механіку одного прогону CI від пуша до статусу.
Розробник робить git push або відкриває Pull Request — CI-сервер помічає цю подію. Він бере свіжий код, у чистому відтворюваному середовищі збирає проєкт, проганяє тести й повертає статус: зелено або червоно. Статус видно прямо в Pull Request — червоний чек блокує злиття, зелений дозволяє. Головна цінність цієї петлі — регресію ловить машина за хвилини після коміту, а не тестувальник за тиждень перед релізом, і «в мене локально працювало» перестає бути аргументом, бо збірка йде в однаковому для всіх середовищі. Історія перевірок прив'язана до комітів, тож видно, який саме коміт зробив магістраль червоною.
Чим CI відрізняється від CD?
Це класична пастка через подвійне «CD»: обидва Continuous Delivery і Continuous Deployment скорочуються однаково, тому сильна відповідь одразу їх розводить. CI відповідає за відрізок від коміту до готового артефакта: інтегрувати, зібрати, протестувати — на виході перевірена збірка. Обидва CD — про те, що з цим артефактом робити далі: доводити його до релізу. Continuous Delivery тримає кожну зелену збірку готовою до релізу «в один клік», а рішення котити на prod ухвалює людина. Continuous Deployment прибирає й цей клік: кожна збірка, що пройшла всі перевірки, їде на prod автоматично. Водорозділ між двома CD — наявність ручного апруву перед prod.
У чому конкретно різниця між Continuous Delivery і Continuous Deployment?
Різниця рівно в одному: чи є людина в петлі релізу перед продакшеном. При Continuous Delivery конвеєр автоматично доводить збірку до стану «готово релізити» — прогнано через усі стадії, розгорнуто на staging, — але саму кнопку «на prod» тисне людина у свідомий момент. При Continuous Deployment кнопки немає: пройшли всі гейти — збірка поїхала на prod сама. Друге вимагає значно зрілішого автоматизованого контролю якості, бо ніхто не дивиться на збірку перед prod очима — весь захист переноситься в перевірки пайплайна, спостережуваність і швидкий rollback. Тому Continuous Deployment без сильної автоматизації якості — це не швидкість, а рулетка.
Чи можна мати Continuous Deployment без Continuous Delivery?
Ні — Continuous Delivery це обов'язкова передумова, а не навпаки. Щоб релізити на prod автоматично без людини, спершу треба вміти стабільно доводити кожну збірку до стану «готова до релізу»: пройдена через усі стадії, розгорнута на staging, перевірена автоматичними гейтами. Continuous Deployment лише знімає останній ручний клік із уже налагодженого Continuous Delivery. Спроба «зразу автоматичний prod» без цієї бази означає, що збірки їдуть у прод, не будучи гарантовано готовими — а це прямий шлях до інцидентів. Тому послідовність завжди CI → Delivery → Deployment, і перескочити середню ланку не вийде.
Що таке пайплайн і чому його називають конвеєром якості?
Пайплайн (pipeline) — це автоматизована послідовність стадій, які код проходить від коміту до потенційного продакшену. Правильна ментальна модель — конвеєр контролю якості: на кожній станції стоїть перевірка, і деталь їде далі, лише якщо станцію пройдено. Не пройшов lint — далі не поїхав; впав unit-тест — до e2e справа взагалі не дійшла. Тобто це не «купа скриптів, які запускаються», а впорядкована черга гейтів, кожен з яких — фільтр, що не пускає дефект далі по трубі. Для AQA це ще й середовище, у якому живуть автотести: там вони запускаються на кожен коміт і там стають блокувальним гейтом.
У якому порядку йдуть стадії пайплайна і чому саме так?
Типовий порядок — lint і перевірка типів, потім unit-тести, потім integration/API, і аж наприкінці e2e. Принцип за цим — fail fast: спершу найшвидші й найдешевші перевірки, потім повільні й дорогі. Логіка суто економічна — немає сенсу тримати агента пів години на e2e, якщо код не проходить навіть перевірку типів; цю помилку треба показати автору за секунди, а не за десятки хвилин. Порядок прямо лягає на піраміду тестування: широка дешева основа знизу, вузький дорогий верх. Сильна відповідь на співбесіді називає не лише послідовність, а й це «чому»: раннє падіння економить час і гроші та дає автору швидкий фідбек.
Чим білд відрізняється від артефакта?
Білд (build) — це дія, процес перетворення вихідного коду в форму, придатну до запуску: для компільованих мов це компіляція, для веб-стека — встановити залежності, перевірити типи, зібрати й мінімізувати бандл, проставити хеші в назви файлів. Артефакт (artifact) — це результат білда: незмінний пакет, готовий до розгортання (зібраний бандл, Docker-образ, .jar, .zip, набір статичних файлів). Ключова властивість артефакта — незмінність. Звідси й межа з деплоєм: білд виробляє артефакт, а деплой ставить готовий артефакт у середовище — це різні дії. Плутати «білд» і «деплой» як один крок — типова помилка новачка.
Що означає принцип build once, deploy many і чому він критичний саме для QA?
Він означає «зібрати один раз, розгорнути багато разів»: артефакт збирають раз, а далі той самий незмінний артефакт просувають середовищами staging → prod, не перезбираючи окремо під кожне. Для QA це фундамент довіри до тестування: на staging ти перевіряєш той самий байт-у-байт артефакт, що поїде в prod, тож твоє тестування staging реально щось гарантує. Якби під prod робили нову збірку, у прод могла б заїхати інша збірка, і перевірка staging нічого не варта. Друга перевага — трасування: артефакт прив'язаний до конкретного коміту й версії, тож зловивши баг у prod, ти знаєш точну збірку й точний коміт. Практичний висновок: різницю поведінки між середовищами треба шукати не в коді (він той самий), а в конфігурації та даних.
Що таке shift-left і як CI з ним пов'язаний?
Зсув уліво (shift-left) — це принцип пересувати перевірки якості якомога раніше на часовій осі проєкту, ближче до написання коду. Основа — крива вартості дефекту: чим пізніше знайдено баг, тим дорожче його виправити; баг на коміті коштує кількох хвилин, той самий баг у проді — інциденту й hotfix-у. CI — головний технічний механізм shift-left: він переносить прогін тестів із окремої «фази тестування наприкінці» на кожен коміт, і тестування вплітається в саму розробку. Сильна відповідь пов'язує термін саме з вартістю дефекту й з CI як інструментом раннього виявлення, а не просто перекладає слово «зсув». Слабка — «shift-left це коли тестуємо раніше», без пояснення механізму й вигоди.
Чому швидкість і стабільність пайплайна — це умова, а не зручність?
Уся цінність CI тримається на швидкості петлі «закомітив → дізнався результат». Якщо пайплайн іде дві години або миготить без причини, петля зворотного зв'язку розривається: люди перестають чекати результату, накопичують зміни великими пачками, зливаються рідше — і команда повертається в те саме інтеграційне пекло, тільки тепер із логотипом CI-системи згори. Тобто повільний чи нестабільний пайплайн не просто дратує — він знищує сам сенс безперервної інтеграції. Тому швидкість (fail-fast порядок стадій) і стабільність (боротьба з flaky) — це не косметика, а умова, за якої CI взагалі працює. Для AQA це прямий обов'язок: тримати сьюту швидкою й надійною.
Чому один flaky-тест здатний знецінити весь пайплайн?
Flaky-тест падає «через раз» без зміни коду, і саме ця непередбачуваність отруює гейт. Коли пайплайн червоніє випадково, команда поступово перестає довіряти червоному кольору й починає його ігнорувати — перезапускає джобу, не читаючи причину. А щойно червоне стало «нормальним», гейт перестав бути гейтом: наступного разу за випадковим червоним сховається справжня регресія, і її пропустять. Тобто шкода не в самому падінні, а в підриві довіри до сигналу. Тому тримати сьюту вартою довіри — пряма робота QA: один хронічно нестабільний тест дорожчий, ніж відсутній.
Чому «зелений пайплайн» не завжди означає «можна релізити»?
Бо зелене означає лише «перевірки, які ми написали, пройшли» — не «продукт справний». Тонка сьюта з дірявим покриттям чи набір flaky-тестів дадуть зелене на функціоналі, який насправді зламаний, просто його ніхто не перевіряє. Зелений колір рівно настільки цінний, наскільки чесні й повні перевірки за ним. Тому за зеленим гейтом мусить стояти продумана стратегія якості: що саме блокує злиття, яке покриття вважається достатнім, які ризики свідомо лишили поза автоматикою. Сприймати зелене як залізну гарантію релізу — типова помилка, яка присипляє пильність.
Чому звичка «впав пайплайн — просто перезапущу джобу» небезпечна?
Бо перезапуск не лагодить причину, а маскує її. За випадковим падінням стоїть або flaky-тест, або реальна регресія, що спрацювала на конкретних таймінгах — і «перезапустив, позеленіло» означає не «полагоджено», а «відкладено до наступного разу». Гірше те, що звичка перезапускати вбиває довіру до гейта: команда привчається не читати червоне, а клікати «retry», і одного дня за цим retry проскочить справжній баг. Правильна реакція на червоне — розібратися, чому впало, і завести це у три корзини: баг продукту, баг тесту чи інфраструктура. Тріаж падінь — щоденна робота AQA, і підміняти його кнопкою перезапуску дорого коштує.
Де місце QA у зрілій CI/CD-культурі?
Слабка відповідь — «QA тестує наприкінці». Сильна — якість не пришивають наприкінці, її вбудовують у конвеєр, а QA стає стюардом цієї автоматизованої мережі безпеки. Конкретно QA пише й володіє автоперевірками в пайплайні, визначає гейти якості (що блокує злиття, а що лише інформує; де e2e блокувальний, а де винесений у nightly), тріажить падіння (продукт / тест / інфраструктура), тримає сьюту вартою довіри й рев'ює тестовий код у Pull Request нарівні з продуктовим. У цій моделі якість — відповідальність усієї команди, але саме QA проєктує й доглядає механізм, який цю якість стереже. Це перехід від «тестувальника, що клікає» до інженера, що володіє захисною сіткою релізу: девопс володіє інфраструктурою, QA — вмістом перевірок.
Три ситуації, у яких CI/CD перестає бути теорією й стає щоденною роботою AQA: тріаж червоного пайплайна за таблицею причин, читання fail-fast конвеєра в GitHub Actions і рішення, який гейт куди поставити, та розбір «на staging працювало, на prod ні» через призму build once, deploy many. Скрізь — що дивитися й чому.
Кейс 1. Червоний пайплайн: тріаж за три корзини
Пайплайн упав на PR, і перша реакція новачка — клікнути «Re-run jobs». Це найгірше, що можна зробити: перезапуск не каже, що сталося, а лише відкладає діагноз. Червоне падіння завжди розкладають у три корзини — баг продукту, баг тесту, інфраструктура — бо лікуються вони по-різному, і плутати їх дорого.
| Симптом у логах CI | Найімовірніша корзина | Перший крок діагностики |
|---|---|---|
| Асерт впав на конкретному кроці, стабільно відтворюється локально | Баг продукту або тесту | Відтворити крок вручну; якщо продукт поводиться не так, як каже асерт — баг продукту |
| Зелено локально, червоно лише в CI, падіння «плаває» | Баг тесту (flaky) або гонка | Перезапустити той самий коміт кілька разів; нестабільність підтверджує flaky |
ECONNREFUSED, таймаути на підйомі сервісу, 502/503 від застосунку | Інфраструктура/середовище | Перевірити, чи середовище й залежності взагалі піднялися до тестів |
| Падіння одразу після оновлення залежностей або конфігу CI | Інфраструктура/конфіг | Порівняти з попереднім зеленим прогоном: що змінилось поза продуктовим кодом |
Що дивитися й чому:
- Стабільність відтворення — головний розділювач. Падіння, що чесно повторюється на тому самому коміті, — це або регресія продукту, або зламаний асерт. Падіння, що «через раз», — майже завжди flaky-тест чи гонка, і його не можна «полагодити перезапуском»: позеленіло — значить, відклали, а не полагодили.
5xxвід застосунку в момент прогону — окремий діагноз. Масові502/503одразу після деплою частіше означають, що середовище ще прогрівається, ніж баг продукту; спершу переконайся, що застосунок піднявся, а вже потім заводь дефект.- Локально зелено, у CI червоно — не привід звинувачувати CI. Прогін у CI йде в headless-браузері, з іншими ресурсами й таймінгами, тож нестабільність вилазить саме там. Це не «поламаний CI», а тест, який спирався на удачу локальної машини.
- Тріаж — це відповідальність QA, а не девопса. Девопс володіє інфраструктурою, але рішення «це баг продукту / тесту / середовища» ухвалює той, хто розуміє вміст перевірок.
Кейс 2. Fail-fast конвеєр у GitHub Actions і місце e2e-гейта
Порядок стадій у пайплайні — не косметика, а економіка: дешеве й швидке має падати першим, поки автор ще за клавіатурою. У GitHub Actions цей порядок задають залежності needs — джоб не стартує, поки не позеленів попередній.
name: ci
on: [pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint && npm run typecheck # секунди
unit:
needs: lint # не запуститься, поки lint червоний
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:unit # секунди-хвилини
e2e:
needs: unit # найдорожча стадія — остання
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright test --project=chromium # десятки хвилин
Ту саму e2e-сьюту можна не тримати блокувальною на кожному PR, а винести важку її частину в nightly — окремий запуск за розкладом:
name: nightly-e2e
on:
schedule:
- cron: '0 2 * * *' # щоночі о 02:00 — повний регрес, усі браузери
jobs:
full-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright test # усі проєкти, довгий хвіст сценаріїв
Що дивитися й чому:
needs— це і є fail-fast. Якщоlintчервоний,unitіe2eнавіть не стартують: агент не витрачає пів години на e2e для коду, що не проходить перевірку типів. Помилку автор бачить за секунди, а не наприкінці.- Порядок повторює піраміду тестування. Багато дешевих unit знизу, кілька дорогих e2e зверху — це не випадковість, а той самий принцип «широка дешева основа, вузький дорогий верх», перенесений у конвеєр.
- Рішення «блокувати чи винести в nightly» — стратегія якості, і його ухвалює QA. Швидкий димовий e2e тримають гейтом на PR; повний регрес по всіх браузерах ганяють уночі, щоб не гальмувати кожен коміт. Це компроміс між швидкістю фідбека й повнотою покриття.
- Зелений цієї сьюти каже рівно те, що написано. Якщо на PR блокує лише димовий набір, «зелено» не означає «повний регрес пройдено» — воно означає «пройшли ті перевірки, що на гейті». Плутати одне з іншим — присипляти пильність.
Кейс 3. «На staging працювало, на prod зламалось»: build once, deploy many на практиці
Фіча відпрацювала на staging, а в prod одразу після релізу — помилка. Перша думка новачка — «код у prod інший». Якщо процес побудований правильно, це майже завжди хибний слід: артефакт зібрали раз і той самий незмінний просунули staging → prod, тож код там байт-у-байт однаковий. Отже, шукати треба не в коді, а в конфігурації та даних.
Щоб зняти саме питання «а чи справді там той самий артефакт», перед прогоном сьюти корисно мати оракул версії — застосунок віддає свою збірку, а тест звіряє її з очікуваною:
import { test, expect } from '@playwright/test';
test('на середовищі крутиться очікувана збірка', async ({ request }) => {
// застосунок віддає свій build/commit, наприклад, у /healthz або /version
const res = await request.get(`${process.env.BASE_URL}/version`);
expect(res.status()).toBe(200);
const { commit } = await res.json();
// очікувану версію передаємо з CI (SHA артефакта, що деплоївся)
expect(commit, 'на середовищі стара збірка — деплой не доїхав').toBe(process.env.EXPECTED_SHA);
});
Якщо версія збіглася, а поведінка все одно різна — розбір іде за таблицею відмінностей середовищ:
| Джерело різниці | Приклад | Де перевіряти |
|---|---|---|
| Конфігурація / змінні оточення | Інший API-URL, вимкнений feature-flag, інший рівень логів | Секрети й конфіг середовища, не код |
| Дані | На staging тестова фікстура, у prod реальні дані з крайніми випадками | Стан бази, вхідні дані конкретного користувача |
| Зовнішні залежності | Платіжний шлюз у sandbox проти бойового | Інтеграції, доступні саме цьому середовищу |
| Масштаб / навантаження | Гонки й таймаути вилазять лише під prod-трафіком | Метрики, конкурентність, ліміти |
Що дивитися й чому:
- Незмінність артефакта — це те, що робить тестування staging осмисленим. Ти перевіряєш той самий байт, що поїде в prod; якби під prod робили нову збірку, перевірка staging нічого б не гарантувала.
- Оракул версії відсікає найдешевшу гіпотезу першою. Половина «загадкових» різниць між середовищами — це банально не доїхав деплой: у prod ще стара збірка. Звіривши SHA, ти або підтверджуєш це за секунди, або чесно виключаєш і йдеш далі.
- Трасування до коміту економить години. Артефакт прив'язаний до конкретної версії, тож зловивши баг у prod, ти знаєш точну збірку й точний коміт, звідки вона зросла, — не треба гадати «а що ж там задеплоєно».
- Різницю шукай у конфізі й даних, а не в коді. Це прямий наслідок build once, deploy many: код той самий за побудовою, тож усе, що відрізняється, живе в оточенні середовища.
Інтеграційне пекло і суть CI
- Можу пояснити «інтеграційне пекло»: що довше гілки розходяться, то різкіше (нелінійно) росте складність злиття, і вибух припадає на дедлайн.
- Знаю головну тезу: CI — це практика й дисципліна команди, а не інструмент; Jenkins сам по собі ще не CI.
- Можу назвати три звички робочого CI: часті дрібні коміти в спільну гілку, автоперевірка на кожен коміт, «зелена магістраль понад усе».
- Розумію правило «не пускай далі деталь із дефектом»: червона магістраль — стоп-сигнал, її лагодять раніше, ніж додають нове.
Механіка і роль автотестів
- Можу описати петлю: push/PR → CI бере свіжий код → чисте середовище → білд → тести → статус green/red у Pull Request.
- Розумію, чому «в мене локально працювало» перестає бути аргументом: збірка йде у відтворюваному, однаковому для всіх середовищі.
- Можу пояснити, чому один flaky-тест руйнує весь сенс CI: команда перестає довіряти червоному й починає його ігнорувати.
CI vs Delivery vs Deployment
- Можу розмежувати відрізки конвеєра: CI — від коміту до артефакта; Delivery — до «готово релізити одним кліком»; Deployment — до автоматичного prod.
- Знаю водорозділ двох CD: наявність ручного апруву перед prod (Delivery — людина тисне кнопку; Deployment — кнопки немає).
- Розумію, що Continuous Delivery — обов'язкова передумова Continuous Deployment, але не навпаки.
Пайплайн як конвеєр якості
- Розумію пайплайн як конвеєр контролю якості: кожна стадія — гейт, деталь їде далі лише пройшовши станцію.
- Знаю fail-fast порядок стадій: lint/типи → unit → integration/API → e2e, і можу пояснити чому (дешеве й швидке раніше).
Білд і артефакт
- Можу розвести білд (дія, процес збірки) і артефакт (результат: незмінний пакет, готовий до розгортання).
- Знаю ключову властивість артефакта — незмінність, і межу з деплоєм: білд виробляє артефакт, деплой ставить його в середовище.
- Розумію принцип build once, deploy many: один артефакт просувають середовищами, а не перезбирають під кожне.
- Можу пояснити, чому це критично для QA: на staging тестую той самий байт-у-байт артефакт, що поїде в prod.
Shift-left і роль QA
- Можу пояснити shift-left через криву вартості дефекту: чим пізніше знайдено баг, тим дорожче виправити.
- Розумію, що CI — головний технічний механізм shift-left: тести переносяться з «фази наприкінці» на кожен коміт.
- Можу назвати обов'язки QA у CI/CD: володіння автоперевірками, визначення гейтів, тріаж падінь, здоров'я сьюти, рев'ю тестового коду в PR.
- Розумію тезу «зелений пайплайн ≠ можна релізити»: зелене означає лише, що написані перевірки пройшли, не що продукт справний.
Що найточніше описує суть CI?
Питання
Що таке «інтеграційне пекло» (integration hell)?