Руководство по Docker Compose: Управление многоконтейнерными приложениями
Многоконтейнерные приложения с Docker Compose: зависимости сервисов, переменные окружения, health check, масштабирование и запуск в production.
CI/CD с GitHub Actions: сборка и публикация Docker-образов, развёртывание на сервер по SSH, автотесты, управление секретами и оптимизация workflow.
GitHub Actions — мощная CI/CD-платформа, которая автоматически тестирует, собирает и развёртывает изменения кода на сервере. В этом руководстве мы создадим готовый к production пайплайн с нуля.
GitHub Actions — платформа автоматизации, интегрированная в репозитории GitHub:
Файлы рабочих процессов GitHub Actions хранятся в формате YAML в директории .github/workflows/.
# .github/workflows/deploy.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Настройка Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Установка зависимостей
run: npm ci
- name: Запуск тестов
run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Развернуть
run: echo "Шаги развёртывания здесь"
on:
# Push в ветку
push:
branches: [main, develop]
paths:
- 'src/**'
- 'package.json'
# Pull request
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
# Запуск по расписанию (cron)
schedule:
- cron: '0 2 * * *' # Каждую ночь в 02:00
# Ручной запуск
workflow_dispatch:
inputs:
environment:
description: 'Среда развёртывания'
required: true
default: 'staging'
type: choice
options: [staging, production]
# При завершении другого рабочего процесса
workflow_run:
workflows: ["Build"]
types: [completed]
jobs:
build:
runs-on: ubuntu-latest
env:
NODE_ENV: test
timeout-minutes: 30
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Метаданные Docker
id: meta
uses: docker/metadata-action@v5
with:
images: username/myapp
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha,prefix=sha-
- name: Настройка Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Вход в Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Сборка и публикация
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Вход в GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Сборка и публикация (GHCR)
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
deploy:
needs: docker
runs-on: ubuntu-latest
environment: production
steps:
- name: Развёртывание по SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SERVER_PORT }}
script: |
cd /root/myapp
git pull origin main
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
echo "Развёртывание завершено: $(date)"
- name: Развёртывание Docker Compose
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# Получить новый образ
docker pull ghcr.io/${{ github.repository }}:latest
# Развёртывание без простоя
docker compose -f /root/app/docker-compose.yml up -d \
--no-deps \
--build \
--remove-orphans
# Очистить старые образы
docker image prune -af --filter "until=24h"
# Проверка работоспособности
sleep 10
curl -f http://localhost:3000/health || exit 1
GitHub Secrets надёжно хранит конфиденциальную информацию:
steps:
- name: Конфигурация приложения
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
API_KEY: ${{ secrets.API_KEY }}
run: |
echo "Конфигурация загружена"
# Секреты никогда не выводятся в логи, автоматически маскируются
Необходимые секреты:
SERVER_HOST: IP-адрес сервераSERVER_USER: имя пользователя SSHSSH_PRIVATE_KEY: приватный ключ SSHDOCKERHUB_USERNAME: имя пользователя Docker HubDOCKERHUB_TOKEN: токен доступа Docker Hub - name: Кэширование зависимостей Node.js
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: npm ci (с кэшем)
run: npm ci
# Кэш слоёв Docker
- name: Сборка и публикация
uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
jobs:
test:
strategy:
fail-fast: false
matrix:
node: [18, 20]
os: [ubuntu-latest, macos-latest]
include:
- node: 20
os: ubuntu-latest
coverage: true
exclude:
- node: 18
os: macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
- name: Отчёт о покрытии
if: matrix.coverage
run: npm run coverage
jobs:
deploy-production:
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- name: Развёртывание в production
run: echo "Развёртывание в production"
В GitHub в разделе Settings > Environments > production:
name: Full CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm test -- --coverage
- name: Загрузить покрытие
uses: codecov/codecov-action@v4
build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- uses: docker/build-push-action@v5
with:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://example.com
steps:
- uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main
docker compose -f /root/app/docker-compose.yml up -d
docker image prune -f
Настроив полностью автоматизированный CI/CD-пайплайн с GitHub Actions, вы сможете повысить качество кода, сократить ошибки при развёртывании и ускорить процесс разработки. Управление секретами, оптимизация кэша и правила защиты окружений обеспечат вам пайплайн production-уровня.
Для публичных репозиториев — полностью бесплатно и без ограничений. Приватные репозитории получают 2 000 бесплатных минут в месяц. При превышении лимита на плане GitHub Free рабочие процессы приостанавливаются. Планы GitHub Pro и Team включают больше минут.
Создайте пару ключей на локальной машине командой 'ssh-keygen -t ed25519 -C "github-actions"'. Добавьте публичный ключ (~/.ssh/id_ed25519.pub) в ~/.ssh/authorized_keys на сервере. Сохраните приватный ключ (~/.ssh/id_ed25519) в репозитории GitHub в разделе Settings > Secrets как SSH_PRIVATE_KEY.
'needs: test' означает, что это задание не запустится, пока задание 'test' не завершится успешно. Используйте 'needs: [test, build]' для нескольких зависимостей. Если задание завершается с ошибкой, зависимые задания автоматически отменяются.
Да, используйте 'on.push.paths' для отслеживания конкретных файлов или директорий. Например, 'paths: ["src/**", "package.json"]' запускает рабочий процесс только при изменении этих файлов. Используйте 'paths-ignore' для исключения определённых файлов.
Кэш сборки Docker предотвращает пересборку неизменённых слоёв. 'cache-from: type=gha' использует кэш GitHub Actions. Это может сократить время сборки на 50-80%. Особенно большой эффект даёт для шагов установки зависимостей (npm install, pip install).
Они добавляют механизм одобрения для критических окружений, таких как production. С 'Required reviewers' развёртывание невозможно без одобрения определённых людей. 'Wait timer' устанавливает время ожидания перед развёртыванием. Это предотвращает случайные развёртывания в production.
Многоконтейнерные приложения с Docker Compose: зависимости сервисов, переменные окружения, health check, масштабирование и запуск в production.
Ansible по шагам: установка, инвентарь, написание playbook, роли, переменные, зашифрованный vault, ad-hoc команды и автоматизация настройки серверов.
Веб-сервер Caddy: установка, Caddyfile, автоматический SSL от Let's Encrypt, обратный прокси, статические сайты, интеграция PHP-FPM и производительность.