Більшість команд до 20 розробників не потребують ні Jenkins, ні TeamCity, ні навіть GitLab CI з власними runner'ами. GitHub Actions з правильно зібраним пайплайном покриває 95% сценаріїв і вимагає мінімум обслуговування. Нижче — шаблон CI/CD, який ми налаштовуємо клієнтам за два дні: чотири стейджі, агресивне кешування, секрети без статичних ключів і деплой через approval. Розбираємо повний workflow, логіку кожного блоку і сигнали, що настав час виходити за межі GitHub-hosted runners.
Чому GitHub Actions достатньо для невеликої команди
Якщо код уже живе на GitHub, Actions прибирає цілий клас роботи: немає CI-сервера, який треба патчити, немає плагінів для оновлення і окремого керування користувачами. Pull request'и, перевірки, середовища та історія деплоїв — в одному місці.
Економіку на такому масштабі теж складно перевершити. Публічні репозиторії працюють на GitHub-hosted runners безкоштовно, а приватні отримують щомісячний ліміт хвилин у кожному тарифі (GitHub Docs: білінг Actions). З 1 січня 2026 року GitHub знизив ціни на hosted runners до 39%: стандартний Linux runner на 2 ядра тепер коштує $0.006 за хвилину (GitHub, зміни цін 2026; довідник цін на runners). Команда з 15 людей, що запускає 3 000 восьмихвилинних білдів на місяць, витрачає близько $144 на обчислення — менше, ніж година інженерного часу на обслуговування Jenkins.
Швидкість важить не менше за вартість. Дослідницька програма DORA вже десятиліття показує, що короткий lead time і часті деплої корелюють із кращими результатами організації, а не з гіршою стабільністю (DORA: метрики software delivery). Швидкий пайплайн — це шлях до цього для маленької команди.
Базовий пайплайн із 4 стейджів
Кожен стейдж має одне завдання і падає якомога раніше:
- Lint + type-check — 30–60 секунд, fail-fast. Ніщо інше не стартує, поки цей крок не пройде.
- Unit-тести з кешуванням залежностей, розбиті на матрицю, якщо набір великий.
- Build + інтеграційні тести з реальними сервісами через Testcontainers або E2E-тести на Playwright.
- Deploy на staging автоматично з
main, на production — через ручний approval.
Ось ядро workflow, з якого ми починаємо:
# .github/workflows/ci.yml
name: CI
on:
pull_request:
push:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm lint && pnpm typecheck
test:
needs: lint
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
matrix:
shard: [1, 2, 3]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm test --shard=${{ matrix.shard }}/3
build:
needs: test
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
Три деталі в цьому файлі економлять найбільше нервів. concurrency скасовує застарілі запуски для того самого PR (документація concurrency). permissions: contents: read обмежує стандартний GITHUB_TOKEN до мінімуму (права токена). А timeout-minutes не дає завислій джобі спалити стандартний шестигодинний ліміт.
Кешування — найбільший виграш
Без кешу npm, pnpm чи Gradle ваш пайплайн працює в 3–5 разів повільніше, бо кожна джоба наново завантажує пів інтернету. Setup-екшени для Node.js, Java і Python мають вбудоване кешування з ключем за lock-файлом; для решти використовуйте actions/cache з ключем на основі hashFiles('**/pnpm-lock.yaml') або аналога.
Docker-збірки виграють ще більше. Docker Buildx вміє зберігати кеш шарів у кеші GitHub Actions (type=gha) або у вашому container registry (type=registry). На клієнтських проєктах це скоротило збірку образів приблизно з 8 хвилин до 90 секунд, бо перебудовуються лише шари після зміненого кроку COPY.
Два правила тримають кеш корисним:
- Впорядковуйте Dockerfile від найстабільнішого до найзмінюванішого. Спершу копіюйте lock-файл і встановлюйте залежності, потім — вихідний код.
- Стежте за розміром кешу. Кожен репозиторій за замовчуванням отримує 10 ГБ кешу Actions, найстаріші записи витісняються першими (довідник з кешування залежностей). Docker-кеш у режимі
mode=maxдля багатьох гілок заповнює цей обсяг швидко.
Безпека секретів
CI-система тримає ключі від продакшену, тож вона — приваблива ціль для атак. У березні 2025 року популярний екшен tj-actions/changed-files був скомпрометований і злив секрети в логи workflow у тисячах репозиторіїв (алерт CISA, CVE-2025-30066). Наш базовий набір:
- OIDC замість статичних хмарних ключів. GitHub видає короткоживучий токен на кожну джобу, а AWS, GCP чи Azure обмінюють його на тимчасові облікові дані. Жоден довгоживучий access key не зберігається в секретах репозиторію (OpenID Connect у GitHub Actions; гайд для AWS).
- Environment protection rules. Production-секрети живуть у середовищі
production, доступному лише зmainі з обов'язковим approval рев'юера (керування середовищами). - Пінінг сторонніх екшенів до повного SHA коміту, а не до змінюваного тегу; оновлення хай пропонує Dependabot (гайд з безпеки).
- Dependabot з auto-merge для minor-оновлень після проходження перевірок через
dependabot/fetch-metadata(автоматизація Dependabot через Actions). - SAST через CodeQL. Code scanning безкоштовний для публічних репозиторіїв; для приватних потрібне доповнення GitHub Code Security (About code scanning with CodeQL).
Деплой-джоба з OIDC виглядає так:
deploy-production:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # потребує approval, тільки з main
permissions:
id-token: write # дозволяє джобі запитати OIDC-токен
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/gha-deploy
aws-region: eu-central-1
- run: ./scripts/deploy.sh
Що економить найбільше часу
- Matrix-білди. Паралельний прогін тестів за шардами або версіями Node.js і Python через
strategy.matrix(документація matrix). - Concurrency-контроль. Не витрачайте хвилини на застарілі коміти PR — скасовуйте їх, як показано вище.
- Reusable workflows. Тримайте один пайплайн з
workflow_callу спільному репозиторії і викликайте його з кожного сервісу замість копіювання кроків (повторне використання workflow). - Path-фільтри. Не запускайте білд фронтенду, якщо змінився лише
backend/, — черезon.push.paths(синтаксис workflow).
Виклик reusable workflow — три рядки на репозиторій:
jobs:
ci:
uses: acme/platform-workflows/.github/workflows/node-ci.yml@v3
with:
node-version: 22
secrets: inherit
Команда, яка чекає на CI 25 хвилин, перестає робити маленькі коміти. CI повільніший за 8 хвилин — це проблема процесу, а не інструменту.
Як міряти пайплайн
Відстежуйте кілька чисел щомісяця і ставтеся до регресій як до багів:
| Метрика | Ціль для команди до 20 людей | Де дивитися |
|---|---|---|
| Медіанна тривалість пайплайна PR | менше 8 хвилин | Метрики використання Actions |
| Частка flaky-тестів | менше 2% запусків | Звіти тестів, кількість перезапусків |
| Частота деплоїв | щодня або частіше | Історія деплоїв за середовищами |
| Change failure rate | менше 15% | Інциденти, пов'язані з деплоями |
| Вартість на місяць | відстежується, а не вгадується | Billing → Usage |
Останні три — метрики DORA; гайд DORA пояснює, як міряти їх без важкого інструментарію. Вбудовані метрики використання й продуктивності Actions показують, які workflow і джоби з'їдають найбільше хвилин.
Коли GitHub Actions перестає працювати
GitHub-hosted runners перестають бути очевидним вибором у трьох ситуаціях:
- Вартість. Команда виросла понад 50 розробників, і ви платите $3 000+ на місяць за хвилини Actions.
- Залізо. Потрібні GPU, більше пам'яті, масові ARM-збірки або доступ до приватної мережі.
- Тривалість. Великі монорепозиторії чи Android-збірки регулярно перевищують 20–30 хвилин навіть з кешем.
Тоді переходьте на self-hosted runners на Hetzner або власному Kubernetes з Actions Runner Controller, який масштабує ефемерні runner'и на вимогу. Зазвичай ми бачимо економію в 5–10 разів, а налаштування займає 2–3 дні. У грудні 2025 року GitHub анонсував плату $0.002 за хвилину для self-hosted runners, а потім відклав її (GitHub, зміни цін 2026), тож враховуйте це у фінансовій моделі. Про кластерну частину — у статті Kubernetes на Hetzner: дешевше за AWS у 5 разів — міф чи реальність.
Пов'язані гайди
Ваш пайплайн — частина ланцюга постачання ПЗ. Детальніше про SBOM, підписи і provenance — у статті Безпека контейнерів і ланцюга постачання, ризики пайплайна в контексті OWASP Top 10:2025, а інфраструктурні пайплайни — у статті Terraform чи OpenTofu.
Пайплайни тепер можуть запускати й AI-рев'юерів та кодових агентів; див. AI-рев'ю коду і AI-агенти в CI/CD.
FAQ
GitHub Actions чи GitLab CI для невеликої команди? Якщо код уже на GitHub — Actions. Обидва інструменти потужні; час економить саме інтеграція з pull request'ами, середовищами і Dependabot.
Скільки безкоштовних хвилин ми отримуємо? Залежить від тарифу: приватні репозиторії мають щомісячний ліміт, а публічні працюють на стандартних runners безкоштовно (білінг Actions).
Чи безпечно деплоїти в продакшен з GitHub Actions?
Так — з OIDC, захищеним середовищем production, обов'язковими рев'юерами та екшенами, запіненими до SHA комітів.
Що з монорепозиторіями? Поєднуйте path-фільтри з reusable workflows для кожного пакета або використовуйте білд-інструмент з віддаленим кешем, як-от Turborepo чи Nx.
Джерела
- GitHub (2025). Pricing changes for GitHub Actions.
- GitHub Docs. Actions runner pricing і GitHub Actions billing.
- GitHub Docs. OpenID Connect.
- GitHub Docs. Managing environments for deployment.
- GitHub Docs. Secure use reference.
- GitHub Docs. Reusing workflows.
- Docker Docs. Cache management with GitHub Actions.
- CISA (2025). Supply chain compromise of tj-actions/changed-files (CVE-2025-30066).
- DORA. DORA's software delivery metrics: the four keys.