Як створити надійний пайплайн CI/CD за допомогою дій GitHub

  • Дії GitHub дозволяють створювати повноцінні пайплайни CI/CD з робочими процесами YAML, інтегруючи тестування, збірку та розгортання в одному репозиторії.
  • Сучасні конвеєри поєднують швидку безперервну інтеграцію, автоматизоване розгортання та найкращі практики, такі як повторне використання робочих процесів та безпечне керування секретними файлами.
  • Можна оркеструвати складні конвеєри для бекенду, фронтенду та мікросервісів, розгортаючи їх на зовнішніх Kubernetes, GAE, Cloud Functions або PaaS.
  • Спостережуваність, безпека (сканування коду та залежностей) і сповіщення є ключовими компонентами надійності конвеєра CI/CD у продакшені.

Конвеєр CI/CD з діями GitHub

Побудова якісного конвеєра CI/CD за допомогою дій GitHub Це вже не додатковий варіант «на випадок, коли буде час»: у сучасних командах це практично вимога для швидкого та надійного розгортання. Навіть попри це, знайти повний, універсальний та добре продуманий приклад, який можна адаптувати до вашої компанії, часто набагато складніше, ніж здається.

У наступних рядках ми поєднаємо класичну теорію CI/CD з реальними прикладами реалізації за допомогою дій GitHub, багаторазових конвеєрів, завдань, bash-скриптів, Модулі PowerShell PnPРозгортання в Kubernetes, Google Cloud та Kinsta, а також найкращі практики щодо безпеки, моніторингу та масштабованості. Ідея полягає в тому, що ви можете взяти ці частини, вписати їх у свій контекст та уникнути багатьох типових помилок.

Чому вам потрібен добре побудований конвеєр CI/CD

У сучасному професійному розвитку CI/CD є кровоносною системою кодуВін інтегрує зміни, проводить тести, створює артефакти та розгортає нові версії з мінімальним втручанням. Без цього робочого процесу кожне розгортання стає повільним, схильним до помилок та ручним випробуванням.

Безперервна інтеграція (БІ) зосереджена на перевірці змін Щойно вони завантажуються до репозиторію, запускаються модульні тести, лінтери та статичний аналіз, щоб якомога швидше виявити помилки. Чим швидше ви отримаєте зворотний зв'язок, тим швидше зможете їх виправити, і тим менш болісною буде будь-яка регресія.

Безперервне розгортання (CD у сенсі Continuous Deployment) або Безперервна доставка (залежно від рівня автоматизації) додає автоматизацію частини релізу: створення образів, публікація пакетів, розгортання в тестових, проміжних або виробничих середовищах і навіть зміна трафіку за допомогою синьо-зелених або канаркових стратегій.

У компаніях з великою кількістю застарілого кодуГарний пайплайн — один із найкращих важелів модернізації екосистеми: він дозволяє впроваджувати тести у застарілі сервіси, автоматизувати завдання, які раніше виконувалися вручну, та зменшувати витрати на обслуговування інфраструктур, таких як Jenkins або Nexus, які застаріли.

Що таке GitHub Actions і чому вони так добре поєднуються з CI/CD?

GitHub Actions — це платформа автоматизації, вбудована в GitHub. Це дозволяє визначати робочі процеси у файлах YAML у самому репозиторії. За його допомогою ви можете компілювати, тестувати, аналізувати та розгортати своє програмне забезпечення без налаштування зовнішніх серверів неперевершеної інтеграції (CI).

Робочий процес – це набір завдань та кроків що викликається такими подіями, як push, pull_request, schedule (CRON), workflow_dispatch (вручну) або навіть дії щодо проблем. Кожне завдання виконується у виконавці (наприклад, ubuntu-latest) і складається з кроків, які використовують дії або команди, що використовуються повторно run.

GitHub пропонує величезний ринок для акцій де у вас є готові інтеграції майже для всього: Docker, Kubernetes, AWS, Azure, Google Cloud, SonarCloud, Slack, Jira, аналіз безпеки, лінтери для тисячі мов тощо. Це значно скорочує час, необхідний для налаштування розширених пайплайнів.

Порівняно з такими рішеннями, як Jenkins або ConcourseGitHub Actions має кілька очевидних переваг: це керований сервіс (ви не керуєте серверами), він тісно пов'язаний з кодом, використовує модель оплати за використання та підтримується величезною спільнотою. Крім того, багато розробників вже знайомі з ним з особистих проектів, що значно скорочує криву навчання.

Базові компоненти робочого процесу GitHub Actions

Все починається з YAML-файлу в .github/workflows/, наприклад ci.yml o build-test-deploy.ymlХоча синтаксис може значно розширюватися, базова структура є відносно простою.

Ключові розділи YAML: name (назва робочого процесу), on (події, що його провокують), jobs (набір логічних завдань), і в межах кожного завдання, runs-on (бігун), steps (кроки), env (глобальні змінні) та if (умови для виконання кроків або завдань).

Робота представляє собою блоки роботи які можна запускати паралельно або в ланцюзі, використовуючи needsУ кожному завданні кроки використовують дії (uses:) або команди (run:Типовий приклад включає: перевірку коду, встановлення залежностей, виконання лінтера, тести та збірку.

Секрети та змінні середовища Ними керують на рівні репозиторію, організації або середовища. У робочих процесах на них посилаються за допомогою ${{ secrets.MI_SECRET }} та дозволяють працювати з ключами API, токенами розгортання або хмарними обліковими даними без їх розкриття в репозиторії.

YAML також дозволяє створювати масиви виконання з strategy.matrix, дуже корисно для тестування вашого коду на різних версіях Node, Python або Java, або навіть на різних операційних системах без необхідності записувати один і той самий блок кілька разів.

Розробка сучасного конвеєра CI/CD з використанням найкращих практик

Здоровий трубопровід зазвичай поділяється на чіткі фази: швидкі перевірки (lint, модульні тести), збірка артефактів, випуск (версія, маркування, журнал змін, публікація в репозиторії артефактів) та розгортання в одному або кількох середовищах.

Фаза безперервної інтеграції має бути якомога швидшою. Це гарантує, що будь-який запит на надсилання або зняття отримує майже миттєвий відгук. Поширеною практикою є паралельне виконання різних перевірок з використанням окремих масивів або завдань, що передбачає дещо вищу вартість в обмін на зменшення загального часу очікування.

Щоб відокремити конвеєр від конкретної мовиВи можете використовувати інструмент для завдань, такий як Task (подібний до Make, але з більш зручним синтаксисом). Таким чином, робочий процес GitHub Actions викликає лише загальні завдання (task test, task lintтощо), і кожен репозиторій визначає, як вони реалізовані внутрішньо, залежно від того, чи це Node, Java, Python тощо.

Версіонування та артефакти вступають у гру на етапі випуску.Тут ви створюєте образ Docker, jar/war файл, npm-пакет або будь-який інший артефакт, завантажуєте його до відповідного реєстру (реєстр Docker, Maven, npm у реєстрі артефактів тощо), позначаєте коміти та генеруєте релізи GitHub або журнали змін за допомогою таких інструментів, як git-cliff або дії щодо випуску.

Нарешті, етап розгортання Перенесіть цей артефакт у середовище виконання: Kubernetes (GKE), Google App Engine, Cloud Functions, сервіси на Kinsta, власні сервери через SSH тощо. Тут ви можете об'єднати наступні кроки, такі як функціональні тести після розгортання або сповіщення Slack з деталями випуску.

Приклад: Повний пайплайн з ESLint, тестами та розгортанням на Kinsta

Дуже показовим прикладом є використання дій GitHub Валідувати React-застосунок за допомогою ESLint та модульних тестів, а потім розгорнути його в Kinsta за допомогою API. Все організовано в єдиному робочому процесі CI/CD.

Перша частина YAML визначає тригер і назву конвеєра. Наприклад, що він працює на кожному push y pull_request до відділення main, і навіть заплановані за допомогою CRON-завдань (наприклад, щодня опівночі або щопонеділка о 8:00 UTC) за допомогою події schedule.

Перше завдання в конвеєрі можна назвати eslint і він відповідає за перевірку синтаксису коду. Він працює в ubuntu-latest та використовує масив версій Node (наприклад, 18.x, 20.x) з кроками для перевірки та налаштування Node actions/setup-node, кешувати залежності npm, встановити за допомогою npm ci і кинути npm run lint.

Друга робота, testsЦе залежить від eslint через needs: eslintтому він запускається лише за умови успішної перевірки синтаксису. Усередині шаблон повторюється: перевірка, встановлення залежностей та виконання npm run test на певній версії Node.

Третя робота, deployВін прив'язаний до ланцюга після обох завдань використання needs: і використовує крок з curl для виклику API Kinsta. Для цього ключ API та ідентифікатор програми налаштовуються як секрети в GitHub (KINSTA_API_KEY y APP_ID) і піддаються впливу в роботі через env створити POST-запит, який запускає розгортання.

Важливо розуміти, що це завдання розгортання Kinsta вважає успіхом саме прийняття API; однак, якщо розгортання згодом завершиться внутрішнім збоєм у Kinsta, робочий процес GitHub все ще може показувати зелений статус. Це слід пам’ятати, щоб уникнути самовдоволення та доповнити процес моніторингом після розгортання.

Розширене керування cron-списками та планування робочих процесів

Синтаксис CRON у діях GitHub Він базується на п'ятиполевому форматі UNIX: хвилина, година, день місяця, місяць та день тижня. Кожне поле може використовувати зірочки, діапазони, списки та кроки (*, 1-5, 1,15,30, */5), що дозволяє планувати завдання технічного обслуговування, резервне копіювання, очищення або періодичні перевірки.

Наприклад, 0 0 * * * виконувати робочий процес щоопівночі (UTC), поки 0 8 * * 1 Це відбувається щопонеділка о 8:00. Це бездоганно поєднується зі звичайними тригерами push y pull_requestщоб той самий YAML міг реагувати як на зміни коду, так і на заплановані виконання.

Ця можливість ідеально підходить для завдань, які не має сенсу випускати в кожному коміті.: інтенсивне сканування безпеки (наприклад, за допомогою OWASP Dependency Check в Java), аудит залежностей, перевірка охоплення тестами або очищення старих артефактів у реєстрі.

Повторне використання робочого процесу: масштабування CI/CD до сотень репозиторіїв

Коли ваша організація має десятки або сотні репозиторіївКопіювання та вставка одного й того ж YAML всюди – це рецепт хаосу. Будь-яка зміна вимагає модифікації половини GitHub Enterprise, що робить практично неможливим підтримку узгодженості та найкращих практик.

Рішення полягає в розробці робочих процесів, що можуть бути повторно використані централізовано в репозиторії шаблонів CI/CD. Ці робочі процеси надають доступ до вхідних та вихідних даних, і кожен сервіс визначає лише невеликий YAML, який їх викликає, передаючи такі параметри, як тип артефакту (Docker, бібліотека Java, пакет npm), середовище виконання розгортання (GKE, GAE, хмарна функція тощо) або елементи завдань, які потрібно виконати.

Поширеною схемою є розділення трьох великих робочих процесів повторного використання: один з build-check-task (безперервна інтеграція), ще один з build-release-dockerfile або інші артефакти та третє розгортання (deploy-gke, deploy-gaeтощо), щоб кожен репозиторій будував свій конвеєр шляхом їх об'єднання.

Для інкапсуляції спільної логіки також можна визначити власні дії. en .github/actionsНаприклад, для налаштування Gradle, Java, Node або Task, для отримання метаданих збірки, для публікації образів Docker, для позначення версій у Git за допомогою bash-скрипта або для надсилання сповіщень до Slack. Золоте правило полягає в тому, що репозиторії сервісів повинні використовувати лише повторно використовувані робочі процеси, а не ці дії безпосередньо, щоб забезпечити більшу керованість зворотною сумісністю.

Швидка безперервна інтеграція із завданнями, матрицями та статичним аналізом

Під час фази збірки або перевірки доцільно запускати багато речей паралельно.Юніт-тести, статичний аналіз (PMD, Checkstyle, SpotBugs на Java; ESLint на JS/TS), сканування за допомогою SonarCloud тощо. Це забезпечує розумний загальний час виконання навіть у великих кодових базах.

Завдання (Taskfile.yml) діє як рівень абстракції для певних команд, що дозволяє робочому процесу CI просто викликати task check, task test o task lintДля проекту Java ці завдання можна делегувати Gradle за допомогою JUnit, PMD, Checkstyle та SpotBugs; для проекту Node — Jest, ESLint та інструментам безпеки, таким як npm audit або подібні.

Дії GitHub додають елемент масиву Щоб запускати ті самі завдання на різних версіях середовища виконання: наприклад, тестування бібліотеки Node на 16, 18 та 20, або проекту Python на 3.10 та 3.12. Це так само просто, як оголошення масиву версій та використання його в конфігурації завдання.

Цей підхід особливо корисний в організаціях, які хочуть підтримувати кілька стеків. (Java, Node, TypeScript, Python тощо) без необхідності переписувати логіку конвеєра для кожного репозиторію: Task адаптується до кожної мови, а робочі процеси, які можна повторно використовувати, залишаються практично незмінними.

Фаза випуску: керування версіями, тегування та публікація артефактів

Після проходження перевірок настає час створювати артефакт, який фактично буде розгорнуто.Образ Docker, JAR-файл, npm-пакет, все, що доречно. Це стосується як мовних інструментів, так і реєстрів організації та політики керування версіями.

Деякі Java-проєкти використовують плагіни, такі як Gradle Axion. керувати версіями на основі тегів Git. У змішаних контекстах (Java, Node тощо) може бути простіше використовувати власний bash-скрипт, який обчислює наступну версію (наприклад, за допомогою SemVer), створює тег, надсилає його на віддалений комп'ютер та генерує відповідний реліз.

Такі інструменти, як git-cliff Вони допомагають створювати журнали змін На основі повідомлень про коміти зміни класифікуються за типом (функція, виправлення, помилка тощо). Інтеграція їх у конвеєр гарантує, що кожен реліз постачається з чітким журналом змін без необхідності писати його вручну.

Для публікації артефактів відповідні дії та облікові дані поєднуються.Реєстри Docker (Docker Hub, GitHub Container Registry, Artifact Registry), репозиторії Maven, реєстри npm тощо. Знову ж таки, облікові дані зберігаються як секрети та вводяться в завдання лише за потреби.

Безперервне розгортання в Kubernetes, GCP, Kinsta та інших середовищах

Розгортання – це процес взаємодії CI/CD з інфраструктурою.Тут GitHub Actions бездоганно інтегрується майже з будь-якою платформою: Kubernetes, App Engine, Cloud Functions, традиційними серверами, платформами, такими як Kinsta тощо.

Для Kubernetes (наприклад, у GKE) звичайна схема Це: автентифікація за допомогою Google Cloud (використовуючи офіційні дії), налаштування kubectl У контексті кластера застосуйте маніфести або діаграми Helm та, за необхідності, виконайте контрольоване розгортання (наприклад, з canary або blue-green) та перевірте стан за допомогою команд з kubectl rollout status.

У випадку App Engine або Cloud FunctionsКонвеєр створює образ або артефакт, публікує його в реєстрі артефактів, а потім викликає команди розгортання. gcloud доречно, знову ж таки використовуючи керовані облікові дані, такі як секрети та ефемерні бігуни.

Коли розгортання виконується на зовнішніх API, таких як Kinstaзазвичай достатньо одного кроку curl або спеціалізована дія, яка надсилає запит із токеном автентифікації та необхідними параметрами (ідентифікатор програми, гілка тощо). Завдання вважається успішним, якщо API правильно відповідає на новий запит на випуск.

Розгортання майже завжди супроводжується повідомленням. до Slack, Teams або інших інструментів комунікації, із зазначенням того, який сервіс було розгорнуто, в якому середовищі, з якою версією, хто його запустив, та посиланнями на журнали робочого процесу. У продакшені це також служить для аудиту та відстеження.

Контроль якості: безпека, моніторинг та журнали

Автоматизація збірки та розгортання – це чудово, але без видимості Щодо того, що відбувається, конвеєр може перетворитися на чорну скриньку. GitHub Actions пропонує детальні журнали за виконанням, завданням та кроком, що дозволяє діагностувати збої компіляції, тестування або розгортання.

Для більш просунутих потреб інтегровані зовнішні сервіси спостереження. такі як Datadog, New Relic або Splunk, які збирають показники робочих процесів, часу виконання, рівня збоїв тощо, допомагаючи виявляти вузькі місця та визначати пріоритети оптимізації конвеєрів.

Паралельно, безпека відіграє ключову роль: управління зашифрованими секретами, мінімально необхідні політики доступу, перегляд дозволів на дії, включення сканерів вразливостей коду та залежностей (сканування коду, сканування секретів, OWASP тощо) у самі робочі процеси.

Багато команд також додають тестування після розгортання у нещодавно оновленому середовищі: наскрізні функціональні тести, перевірки продуктивності, базові димові тести та, у разі збою, автоматизовані механізми відкату, які відновлюють попередню стабільну версію.

Управління робочим процесом: захищені гілки та запити на зняття (pull requests)

Спосіб роботи з гілками та запитами на зняття має відповідати принципам CI/CD. щоб усе мало сенс. Найпоширенішим є захист головної гілки (main o master) та вимагати, щоб будь-яка зміна проходила процес зв'язку з громадськістю та перевірки конвеєра.

GitHub дозволяє визначати правила захисту гілок Ці політики примусово вимагають використання запитів на злиття (pull requests), блокують прямі коміти та вимагають, щоб певні перевірки статусу (конкретні робочі процеси дій) були активними перед дозволом на злиття. Вони також можуть вимагати мінімальних редагувань, правил затвердження тощо.

Ця модель гарантує, що код, який потрапляє у продакшн Він пройшов перевірку людиною та всі автоматизовані перевірки конвеєра, що значно знижує ризик пропуску серйозних помилок або вразливостей.

У компаніях з кількома середовищами Розгортання (розробка, промежуточне тестування, виробництво) у продакшн зазвичай резервується для злиття з основною гілкою, тоді як інші гілки можуть ініціювати розгортання в попередні середовища для внутрішнього тестування або демонстрацій.

Дивлячись на загальну картину, добре розроблений конвеєр CI/CD з діями GitHub Це стає основою розробки: інтеграція змін, запуск комплексних тестових наборів, створення та публікація артефактів, розгортання на кількох хмарних платформах, моніторинг за допомогою інструментів спостереження та управління за допомогою чітких правил розгалуження та запитів на втягування. Завдяки багаторазовим робочим процесам, користувацьким діям, допоміжним інструментам, таким як Task, Rease Action та Git Cliff, а також надійному управлінню секретами та дозволами, можливо підтримувати все: від простих додатків Python до складних архітектур Kubernetes, зберігаючи швидкість доставки, якість коду та безпеку, не перевантажуючи команду ручними завданнями.

лазур
Пов'язана стаття:
Практичний посібник з хмарних інцидентів у Microsoft Azure та Microsoft 365