141 lines
5.4 KiB
YAML
141 lines
5.4 KiB
YAML
name: Deploy
|
||
|
||
# Деплоится только при изменениях основного стека.
|
||
# Obsidian-стек (CouchDB) — отдельный workflow `deploy-obsidian.yml`.
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
paths:
|
||
- "backend/**"
|
||
- "frontend/**"
|
||
- "docker-compose.prod.yml"
|
||
- "Caddyfile"
|
||
- ".github/workflows/deploy.yml"
|
||
# NB: shared compose-fragments (network) — тоже триггерят main
|
||
# потому что Caddy шарит сеть с obsidian-stack
|
||
workflow_dispatch:
|
||
|
||
concurrency:
|
||
group: deploy-prod
|
||
cancel-in-progress: false
|
||
|
||
env:
|
||
IMAGE_BACKEND: ghcr.io/lekss361/gendesign-backend
|
||
IMAGE_WORKER: ghcr.io/lekss361/gendesign-worker
|
||
IMAGE_FRONTEND: ghcr.io/lekss361/gendesign-frontend
|
||
|
||
jobs:
|
||
build-and-deploy:
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set image tag
|
||
id: meta
|
||
run: echo "tag=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Login to GHCR
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ github.actor }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Build & push backend (lean — без Chromium)
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: ./backend
|
||
target: runner
|
||
push: true
|
||
cache-from: type=gha,scope=backend
|
||
cache-to: type=gha,mode=max,scope=backend
|
||
tags: |
|
||
${{ env.IMAGE_BACKEND }}:latest
|
||
${{ env.IMAGE_BACKEND }}:${{ steps.meta.outputs.tag }}
|
||
|
||
- name: Build & push worker (с Chromium для Playwright)
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: ./backend
|
||
target: runner-with-chromium
|
||
push: true
|
||
cache-from: type=gha,scope=worker
|
||
cache-to: type=gha,mode=max,scope=worker
|
||
tags: |
|
||
${{ env.IMAGE_WORKER }}:latest
|
||
${{ env.IMAGE_WORKER }}:${{ steps.meta.outputs.tag }}
|
||
|
||
- name: Build & push frontend
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: ./frontend
|
||
push: true
|
||
cache-from: type=gha,scope=frontend
|
||
cache-to: type=gha,mode=max,scope=frontend
|
||
tags: |
|
||
${{ env.IMAGE_FRONTEND }}:latest
|
||
${{ env.IMAGE_FRONTEND }}:${{ steps.meta.outputs.tag }}
|
||
|
||
- name: Deploy to VM via SSH
|
||
uses: appleboy/ssh-action@v1.0.3
|
||
env:
|
||
IMAGE_TAG: ${{ steps.meta.outputs.tag }}
|
||
with:
|
||
host: ${{ secrets.DEPLOY_HOST }}
|
||
username: ${{ secrets.DEPLOY_USER }}
|
||
key: ${{ secrets.DEPLOY_SSH_KEY }}
|
||
port: ${{ secrets.DEPLOY_PORT || 22 }}
|
||
envs: IMAGE_TAG
|
||
script: |
|
||
set -euo pipefail
|
||
cd /opt/gendesign
|
||
|
||
# Sync compose / Caddyfile / init scripts from the repo.
|
||
# --ff-only refuses if there are local commits on the VM (we don't expect any).
|
||
git fetch origin main
|
||
git reset --hard origin/main
|
||
|
||
# Sentry release tracking — записываем git-sha в .env.runtime.
|
||
# ВАЖНО: НЕ перезаписываем файл целиком (там могут быть
|
||
# COUCHDB_PASSWORD и др. user-managed secrets). Заменяем только
|
||
# строку SENTRY_RELEASE или добавляем если её нет.
|
||
mkdir -p backend
|
||
touch backend/.env.runtime
|
||
if grep -q '^SENTRY_RELEASE=' backend/.env.runtime; then
|
||
sed -i "s|^SENTRY_RELEASE=.*|SENTRY_RELEASE=$IMAGE_TAG|" backend/.env.runtime
|
||
else
|
||
printf 'SENTRY_RELEASE=%s\n' "$IMAGE_TAG" >> backend/.env.runtime
|
||
fi
|
||
chmod 600 backend/.env.runtime
|
||
|
||
# Создать external network если её нет (нужна Caddy для маршрута
|
||
# obsidian.gendsgn.ru → couchdb из отдельного obsidian-stack).
|
||
docker network inspect gendesign_shared >/dev/null 2>&1 \
|
||
|| docker network create gendesign_shared
|
||
|
||
export IMAGE_TAG="$IMAGE_TAG"
|
||
# Project name явно — `gendesign` (по имени папки auto), но
|
||
# фиксируем для consistency с obsidian-stack (-p gendesign-obsidian).
|
||
docker compose -p gendesign -f docker-compose.prod.yml pull
|
||
docker compose -p gendesign -f docker-compose.prod.yml up -d
|
||
|
||
# Caddyfile is bind-mounted; up -d won't re-read it. Reload explicitly.
|
||
# `|| true` so a temporary Caddy hiccup doesn't fail the whole deploy.
|
||
docker compose -p gendesign -f docker-compose.prod.yml exec -T caddy \
|
||
caddy reload --config /etc/caddy/Caddyfile || true
|
||
|
||
# Clean up disk: dangling layers + tagged images older than 72h that
|
||
# nothing is using anymore. Plus build cache (we never build on prod
|
||
# but old buildkit caches may linger from earlier compose builds).
|
||
docker image prune -af --filter "until=72h" || true
|
||
docker builder prune -af || true
|
||
|
||
sleep 8
|
||
curl -fsS http://localhost:8000/health | head -c 200 || true
|