Вступление
Разработчики часто сталкиваются с тем, что сборка, тестирование и деплой становятся узким местом в цикле поставки. В этой статье мы построим рабочий CI/CD пайплайн, который автоматически собирает Docker‑образ, прогоняет юнит‑тесты и выкладывает готовый контейнер в реестр. Вы получите готовый workflow‑файл и набор рекомендаций, чтобы избежать типичных проблем.
1. Контекст и предпосылки
| Что уже может быть готово | Что понадобится добавить |
|---|---|
| Репозиторий на GitHub с исходным кодом | Файл Dockerfile и тестовый набор |
| Docker‑клиент на разработчике | Доступ к реестру Docker (Docker Hub, GitHub Packages или собственный) |
| Базовое понимание GitHub Actions | Переменные окружения для доступа к реестру |
Пайплайн будет состоять из трёх стадий:
- Build – сборка Docker‑образа.
- Test – запуск тестов внутри контейнера.
- Deploy – публикация образа в реестр и (по желанию) триггер деплоя в продакшн‑кластер.
2. Пошаговая реализация
-
Создайте репозиторий и разместите в корне проекта
Dockerfileи каталогtests/. -
Подготовьте секреты в настройках репозитория (
Settings → Secrets and variables → Actions):
-DOCKER_USERNAME
-DOCKER_PASSWORD
- (Опционально)DEPLOY_TOKEN– токен для вашего кластера. -
Добавьте workflow в
.github/workflows/ci-cd.yml. Файл будет запускаться на каждыйpushв веткуmain. -
Проверьте работу пайплайна в GitHub → Actions. При ошибках откройте лог отдельного шага.
3. Пример кода
# .github/workflows/ci-cd.yml
name: CI/CD
on:
push:
branches: [ main ]
jobs:
build-test-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
id: build
uses: docker/build-push-action@v4
with:
context: .
push: false
tags: ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }}
- name: Run tests in container
run: |
docker run --rm ${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }} ./run-tests.sh
- name: Push image to registry
if: success()
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/my-app:latest
${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }}
- name: Trigger deployment (optional)
if: success()
run: |
curl -X POST -H "Authorization: token ${{ secrets.DEPLOY_TOKEN }}" \
https://example.com/deploy
Dockerfile (минимальный пример)
FROM python:3.11-slim
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Тестовый скрипт run-tests.sh
#!/usr/bin/env bash
set -e
pytest tests/
4. Нюансы, грабли, альтернативы
- Кеширование слоёв.
docker/build-push-actionумеет кешировать слои между запусками. Добавьтеcache-from/cache-to, если сборка занимает много времени. - Тайм‑ауты. По умолчанию каждый шаг ограничен 6 ч. Для долгих интеграционных тестов используйте
timeout-minutes. - Секреты не передаются в логах. Не выводите их в
echo. Если необходимо отладить, используйтеset -xлишь внутри безопасных скриптов. - Альтернативные реестры. Вместо Docker Hub можно подключить GitHub Packages (
docker/login-actionподдерживаетregistry: ghcr.io). Поменяйтеtagsиregistryвbuild-push-action. - Параллельные задачи. Если тестов слишком много, их можно разбить на несколько jobs, используя
needsдля синхронизации. - Rollback. CI/CD без отката – риск. Храните предыдущие теги (
${{ github.sha }}) и реализуйте скрипт, который переключает трафик обратно в случае неудачного деплоя.
Вывод
Мы собрали полностью автоматизированный процесс: от кода до готового Docker‑образа в реестре. Главные тезисы:
- GitHub Actions обеспечивает простую интеграцию с Docker через официальные экшены.
- Секреты и кеширование делают пайплайн безопасным и быстрым.
- Типичные ошибки – неправильные секреты, отсутствие тегов и игнорирование тайм‑аутов.
Дальнейшее улучшение может включать тесты в разных средах (один‑контеейнер, несколько), динамические переменные окружения и более продвинутый roll‑out в Kubernetes. Теперь вы можете запускать новые версии без ручных команд и контролировать весь процесс из репозитория.