Привіт, розробники! У цій статті я розповім про CI/CD – концепцію.
- Що таке CI/CD пайплайн у контексті програмування?
- 🔄 З чого зазвичай складається CI/CD пайплайн?
- 🛠 Популярні інструменти для CI/CD:
- 🧠 Навіщо взагалі потрібен CI/CD?
- 📦 Прості приклади CI/CD з GitHub Actions
- 🚚 Деплой на популярні платформи
- 🌟 Просунутий CI/CD: Build Docker → Push у GHCR → Staging/Production на GCP Cloud Run
Що таке CI/CD пайплайн у контексті програмування?
CI/CD пайплайн (Continuous Integration / Continuous Delivery або Continuous Deployment) — це автоматизований процес, який дозволяє розробникам швидко та надійно доставляти зміни в коді в робоче середовище (продакшн).
Давайте розберемо ключові поняття:
🔧 CI — Continuous Integration (Безперервна інтеграція)
Це практика, при якій розробники часто вносять зміни в загальну кодову базу. Кожна така зміна автоматично: * Збирається (build) * Тестується (юніт-тести, інтеграційні тести) * Перевіряється на відповідність стандартам (лінтинг, статичний аналіз)
👉 Мета CI: Виявляти помилки на найранішому етапі, до того як вони зламають щось важливе або потраплять у реліз.
🚀 CD — Continuous Delivery (Безперервна доставка) або Continuous Deployment (Безперервне розгортання)
Тут є два варіанти:
✅ Continuous Delivery (Безперервна доставка)
Після успішного проходження етапу CI, зміни автоматично: * Проходять додаткові тести (наприклад, E2E – end-to-end тести) * Потрапляють на staging (тестовий) сервер
👉 Але деплой у продакшн все ще вимагає ручного підтвердження. Це дає команді контроль над тим, коли саме зміни побачать користувачі.
🤖 Continuous Deployment (Безперервний деплой)
Це наступний крок після Continuous Delivery. Тут деплой у продакшн відбувається повністю автоматично, якщо всі попередні етапи пайплайну (збірка, всі тести) пройшли успішно. Це найпросунутіший рівень автоматизації.
🔄 З чого зазвичай складається CI/CD пайплайн?
Типовий пайплайн включає наступні етапи:
- Checkout — Клонування останньої версії коду з репозиторію.
- Build — Збірка проекту (компіляція, збірка артефактів, Docker-образів).
- Test — Запуск різних видів тестів (юніт, інтеграційні, E2E).
- Lint/Code Quality — Перевірка коду на відповідність стилю та потенційні помилки за допомогою статичних аналізаторів.
- Deploy — Розгортання програми (на staging або production сервер).
- Notify — Надсилання сповіщень про статус пайплайну команді (наприклад, у Slack, Email).
🛠 Популярні інструменти для CI/CD:
- GitHub Actions (наш фокус сьогодні!)
- GitLab CI/CD
- Jenkins
- CircleCI
- Bitbucket Pipelines
- Azure DevOps
- TeamCity
🧠 Навіщо взагалі потрібен CI/CD?
- Зменшує людський фактор: Автоматизація виключає помилки, пов’язані з ручними операціями.
- Швидке виявлення багів: Помилки знаходяться раніше, їх простіше та дешевше виправити.
- Автоматизація рутинних завдань: Розробники витрачають менше часу на збірку та деплой, більше – на код.
- Покращення якості коду: Постійні перевірки та тести підвищують загальну планку якості.
- Швидка доставка фіч користувачам: Нові можливості доходять до кінцевого користувача швидше та частіше.
📦 Прості приклади CI/CD з GitHub Actions
Давайте подивимося на базові пайплайни для популярних технологій. Всі приклади використовують GitHub Actions і зберігаються в директорії `.github/workflows/` вашого проекту.
🐍 CI/CD для Python (з `pytest` та `flake8`)
# .github/workflows/python-ci.yml
name: Python CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11' # Вкажіть вашу версію
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt # Переконайтеся, що у вас є requirements.txt
pip install flake8 pytest
- name: Lint with flake8
run: |
# Перевіряємо код у папках src та tests (адаптуйте під свій проект)
flake8 src tests
- name: Run tests
run: |
pytest
🌐 CI/CD для Node.js (з `npm test` та `eslint`)
# .github/workflows/node-ci.yml
name: Node.js CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x] # Вкажіть вашу версію Node.js
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm install # або npm ci для більш передбачуваної установки
- name: Lint with ESLint
run: npx eslint . # Переконайтеся, що ESLint налаштований у проекті
- name: Run tests
run: npm test
🐳 CI/CD для Docker (збірка та пуш у Docker Hub)
Для цього прикладу вам знадобляться секрети `DOCKER_USERNAME` та `DOCKER_PASSWORD` (або токен) у налаштуваннях вашого GitHub репозиторію (`Settings -> Secrets and variables -> Actions`).
# .github/workflows/docker-ci.yml
name: Docker CI/CD
on:
push:
branches: [ main ] # Запускаємо тільки для main гілки
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Log in to Docker Hub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: Build Docker image
# Замініть myapp на назву вашої програми
run: docker build -t ${{ secrets.DOCKER_USERNAME }}/myapp:latest .
- name: Push Docker image
run: docker push ${{ secrets.DOCKER_USERNAME }}/myapp:latest
🚚 Деплой на популярні платформи
Тепер, коли у нас є зібрані та протестовані артефакти (наприклад, Docker-образ), давайте подивимося, як їх можна розгорнути.
🟣 Деплой на Heroku
🔐 Секрети GitHub: `HEROKU_API_KEY`, `HEROKU_APP_NAME`.
# .github/workflows/deploy-heroku.yml
name: Deploy to Heroku
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Heroku CLI
run: curl https://cli-assets.heroku.com/install.sh | sh
- name: Login to Heroku
env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
run: heroku auth:token
- name: Deploy to Heroku
env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
run: |
heroku git:remote -a ${{ secrets.HEROKU_APP_NAME }}
git push heroku main -f # Будьте обережні з -f (force push)
Якщо ви деплоїте Docker-образ на Heroku:
# ... (кроки build та login to Docker Hub/GHCR з попередніх прикладів) ...
# deploy:
# name: Deploy to Heroku
# needs: build # Залежить від джоба збірки образу
# runs-on: ubuntu-latest
# steps:
# # ...
# - name: Login to Heroku container registry
# run: echo "${{ secrets.HEROKU_API_KEY }}" | docker login --username=_ --password-stdin registry.heroku.com
# - name: Tag image for Heroku
# # Припускаємо, що образ зібраний як ghcr.io/username/repo/myapp:latest
# run: docker tag ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/myapp:latest registry.heroku.com/${{ secrets.HEROKU_APP_NAME }}/web
# - name: Push image to Heroku
# run: docker push registry.heroku.com/${{ secrets.HEROKU_APP_NAME }}/web
# - name: Release Heroku App
# env:
# HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
# run: heroku container:release web --app ${{ secrets.HEROKU_APP_NAME }}
🟨 Деплой на AWS (наприклад, статика в S3)
🔐 Секрети GitHub: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, `S3_BUCKET_NAME`.
# .github/workflows/deploy-aws-s3.yml
name: Deploy Static Site to AWS S3
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Sync files to S3
# Замініть ./public на шлях до ваших статичних файлів
run: aws s3 sync ./public s3://${{ secrets.S3_BUCKET_NAME }} --delete
Для деплою на **AWS Elastic Beanstalk** зазвичай використовується EB CLI, пайплайн буде схожий, але з командами `eb deploy`.
🔵 Деплой на Google Cloud Platform (GCP App Engine)
🔐 Секрети GitHub: `GCP_CREDENTIALS` (JSON ключ сервіс-акаунту), `GCP_PROJECT_ID`.
# .github/workflows/deploy-gcp-app-engine.yml
name: Deploy to GCP App Engine
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
with:
project_id: ${{ secrets.GCP_PROJECT_ID }}
service_account_key: ${{ secrets.GCP_CREDENTIALS }}
export_default_credentials: true
- name: Deploy to App Engine
# Переконайтеся, що у вас є app.yaml у корені проекту
run: gcloud app deploy --quiet
🟪 Деплой на Render.com
Render часто автоматично деплоїть при push у GitHub, якщо репозиторій підключений. Але для ручного тригера (або як частина більш складного пайплайну) можна використовувати Deploy Hook.
🔐 Секрети GitHub: `RENDER_DEPLOY_HOOK` (URL, отриманий з налаштувань сервісу в Render).
# .github/workflows/deploy-render.yml
name: Trigger Render Deploy
on:
workflow_dispatch: # Ручний запуск з UI GitHub
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Trigger Render Deploy Hook
run: curl -X POST ${{ secrets.RENDER_DEPLOY_HOOK }}
🌟 Просунутий CI/CD: Build Docker → Push у GHCR → Staging/Production на GCP Cloud Run
А тепер вишенька на торті! Зберемо просунутий пайплайн: 1. Збірка Docker-образу. 2. Публікація образу в GitHub Container Registry (ghcr.io). 3. Автоматичний деплой у **staging** середовище на GCP Cloud Run. 4. Деплой у **production** середовище на GCP Cloud Run **після ручного підтвердження**.
Для цього нам знадобиться кілька файлів воркфлоу.
Необхідні секрети GitHub:
- `GCP_PROJECT_ID`: ID вашого проекту в GCP.
- `GCP_CREDENTIALS`: JSON-ключ сервіс-акаунту GCP з правами на деплой у Cloud Run та доступ до GHCR (якщо потрібно). Зазвичай `GITHUB_TOKEN` достатньо для доступу до GHCR з Actions.
- `GCP_REGION`: Регіон для Cloud Run (наприклад, `europe-west1`).
1. Збірка та публікація Docker-образу в GHCR
# .github/workflows/build.yml
name: Build & Push to GHCR
on:
push:
branches: [main] # Запускаємо при пуші в main
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read # Для checkout
packages: write # Для пушу в GHCR
steps:
- uses: actions/checkout@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/myapp:latest
# Можна додати тегування за SHA коміту для унікальності:
# tags: |
# ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/myapp:latest
# ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/myapp:${{ github.sha }}
- `github.repository_owner`: Власник репозиторію (ваш username або організації).
- `github.event.repository.name`: Назва репозиторію.
- `myapp`: Назва вашої програми/образу.
2. Автоматичний деплой у Staging (GCP Cloud Run)
Цей воркфлоу буде запускатися автоматично після успішного завершення `build.yml`.
# .github/workflows/deploy-staging.yml
name: Deploy to GCP Cloud Run (Staging)
on:
workflow_run:
workflows: ["Build & Push to GHCR"] # Назва воркфлоу збірки
types:
- completed
jobs:
deploy-staging:
runs-on: ubuntu-latest
# Запускаємо тільки якщо воркфлоу збірки завершився успішно
if: ${{ github.event.workflow_run.conclusion == 'success' }}
# Використовуємо GitHub Environments для staging (опціонально, але хороша практика)
environment:
name: staging
url: ${{ steps.deploy.outputs.url }} # URL буде доступний після деплою
steps:
- uses: actions/checkout@v3 # Потрібен, якщо використовуєте конфігурації з репозиторію
- id: 'auth'
uses: 'google-github-actions/auth@v2'
with:
credentials_json: '${{ secrets.GCP_CREDENTIALS }}'
- name: 'Deploy to Cloud Run (Staging)'
id: deploy
uses: 'google-github-actions/deploy-cloudrun@v2'
with:
service: 'myapp-staging' # Назва вашого staging сервісу в Cloud Run
region: '${{ secrets.GCP_REGION }}'
# Використовуємо образ, який був запушений в build.yml
image: 'ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/myapp:latest'
project_id: '${{ secrets.GCP_PROJECT_ID }}'
flags: '--allow-unauthenticated --platform=managed' # Дозволяємо неаутентифікований доступ для прикладу
3. Деплой у Production з ручним підтвердженням (GCP Cloud Run)
Цей воркфлоу запускається вручну через UI GitHub Actions.
# .github/workflows/deploy-prod.yml
name: Deploy to GCP Cloud Run (Production)
on:
workflow_dispatch: # Дозволяє ручний запуск
jobs:
deploy-production:
runs-on: ubuntu-latest
environment:
name: production
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v3
- id: 'auth'
uses: 'google-github-actions/auth@v2'
with:
credentials_json: '${{ secrets.GCP_CREDENTIALS }}'
- name: 'Deploy to Cloud Run (Production)'
id: deploy
uses: 'google-github-actions/deploy-cloudrun@v2'
with:
service: 'myapp-production' # Назва вашого production сервісу
region: '${{ secrets.GCP_REGION }}'
image: 'ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/myapp:latest' # Використовуємо той самий 'latest' образ
project_id: '${{ secrets.GCP_PROJECT_ID }}'
flags: '--allow-unauthenticated --platform=managed'
# Для production можна додати --no-traffic і потім поступово перемикати трафік
# traffic:
# latest: true
# percent: 100
Важливі моменти цього просунутого пайплайну:
- GitHub Container Registry (ghcr.io): Ми використовуємо його для зберігання Docker-образів. Це зручно, оскільки він тісно інтегрований з GitHub Actions.
- `workflow_run`:** Дозволяє запускати один воркфлоу (деплой на staging) по завершенні іншого (збірка).
- `workflow_dispatch`:** Дає можливість ручного запуску воркфлоу (деплой на production), що забезпечує контроль.
- GitHub Environments:** Дозволяють налаштувати правила захисту для production (наприклад, вимагати схвалення від певних рев’юерів) та зберігати специфічні для середовища секрети.
- GCP Cloud Run:** Відмінний serverless-варіант для запуску контейнеризованих програм.
🔐 Безпека – це важливо! Використовуйте GitHub Secrets:** Ніколи не зберігайте токени, паролі, ключі API безпосередньо в YAML-файлах. Використовуйте `Settings -> Secrets and variables -> Actions` у вашому репозиторії. Мінімальні привілеї:** Для сервіс-акаунтів (наприклад, GCP) надавайте лише ті права, які дійсно необхідні для виконання завдань CI/CD. Ізолюйте середовища:** Staging та Production повинні бути максимально ізольовані. Різні проекти/акаунти в хмарних провайдерах – хороша практика. Захист гілок:** Налаштуйте захист для `main` (або `master`) гілки, щоб пушити в неї можна було лише через Pull Request з обов’язковими перевірками CI.