Files
image-gateway/docs/ci-cd.md
S.Gromov 98b162f2b8
Some checks failed
CI / e2e (push) Failing after 1m56s
CI / docker (push) Has been skipped
chore: добавить CI/CD для прод-деплоя
- добавлены Gitea workflows для CI и ручного CD

- настроен prod compose для запуска за reverse proxy

- добавлена публикация Caddy image в Container Registry

- обновлена документация по CI/CD и prod-сети
2026-05-04 12:51:28 +03:00

5.1 KiB
Raw Blame History

CI/CD

Проект использует Gitea Actions workflows в .gitea/workflows.

Прод Схема

В проде проект запускается через Docker Compose, а не через один общий Dockerfile.

Причины:

  • caddy и imgproxy — разные runtime-сервисы;
  • для Caddy нужен кастомный image с Souin, Otter и NutsDB modules;
  • imgproxy берется как готовый upstream image darthsim/imgproxy;
  • кешу нужны persistent volumes caddy-data и caddy-cache;
  • Compose проще обновляет только Caddy image без пересборки на сервере;
  • Image Gateway должен быть доступен только из сети внешнего reverse proxy.

В registry публикуется только кастомный Caddy image из Dockerfile.caddy. На сервере docker-compose.yml подставляет его через переменную CADDY_IMAGE.

Prod compose не публикует host-порты. Caddy подключается к external network web с alias image-gateway, поэтому внешний reverse proxy должен проксировать на http://image-gateway:80 при CADDY_PORT=80.

CI

Файл: .gitea/workflows/ci.yml.

Запускается на:

  • push в main, master, dev;
  • pull request в main, master, dev;
  • ручной запуск через workflow_dispatch.

Что делает:

  • проверяет docker-compose.test.yml через docker compose config;
  • запускает e2e-тесты кеша через ./scripts/test-e2e.sh;
  • на основной ветке собирает и публикует Caddy image в Gitea Container Registry.

Публикуемые теги:

  • branch tag, например master или main;
  • commit SHA;
  • latest для default branch.

CD

Файл: .gitea/workflows/deploy.yml.

Запускается вручную через workflow_dispatch.

Что делает:

  • вычисляет registry image текущего репозитория;
  • подключается к серверу по SSH;
  • копирует docker-compose.yml и Caddyfile в директорию деплоя;
  • логинится в Gitea Container Registry;
  • тянет CADDY_IMAGE=<registry>/<repo>:latest;
  • создает Docker network внешнего reverse proxy, если ее еще нет;
  • запускает docker compose up -d --no-build.

Сборка на прод-сервере не выполняется.

Secrets

В Gitea repository secrets должны быть заданы:

Secret Назначение
CR_USER пользователь Container Registry
CR_TOKEN токен Container Registry
SSH_PRIVATE_KEY приватный ключ для деплоя

CD workflow использует те же registry и SSH secrets, что и другие проекты.

Настройки целевого сервера заданы в env файла .gitea/workflows/deploy.yml:

Переменная Значение по умолчанию Назначение
DEPLOY_HOST 188.225.47.78 host/IP прод-сервера
DEPLOY_USER root SSH-пользователь
DEPLOY_PATH /opt/image-gateway директория проекта на сервере
IMAGE_TAG latest тег Caddy image для деплоя
WEB_NETWORK web Docker network внешнего reverse proxy

На прод-сервере в DEPLOY_PATH должен лежать .env с runtime-настройками:

DOMAIN=images.example.com
CADDY_PORT=80
WEB_NETWORK=web
IMGPROXY_KEY=
IMGPROXY_SALT=
IMGPROXY_ALLOWED_SOURCES=example.com,cdn.example.com

CD workflow не копирует .env, чтобы не перетирать секреты и runtime-настройки на сервере.

Ручной Деплой На Сервере

Если нужно повторить деплой вручную на сервере:

cd /path/to/image-gateway
docker login registry.example.com
CADDY_IMAGE=registry.example.com/owner/image-gateway:latest docker compose -f docker-compose.yml pull caddy imgproxy
CADDY_IMAGE=registry.example.com/owner/image-gateway:latest docker compose -f docker-compose.yml up -d --no-build

Reverse Proxy

Внешний reverse proxy должен быть подключен к той же Docker network, что и Image Gateway (WEB_NETWORK, по умолчанию web).

Внутренний upstream при CADDY_PORT=80:

http://image-gateway:80

Прокидывайте исходный Host, чтобы Souin cache key не дробился по внутренним именам:

Host: images.example.com
X-Forwarded-Proto: https
X-Forwarded-For: <client-ip>

Admin API :2019 не должен публиковаться наружу.

Skip CI

Для пропуска CI добавьте [skip ci] в сообщение коммита.