d8dd97ba39
docker-compose.prod.yml монтирует promtail-config.yml как volume, но workflow копировал на сервер только сам compose-файл. При отсутствии источника Docker молча создавал вместо файла пустую директорию — promtail падал с ошибкой монтирования, и docker compose up не успевал поднять app. На проде поправлено руками (файл выложен, контейнеры подняты), этот коммит просто чинит воркфлоу на будущее.
206 lines
9.9 KiB
YAML
206 lines
9.9 KiB
YAML
# Копия .github/workflows/deploy.yml для Gitea Actions. Образы тянутся из
|
||
# встроенного Container Registry самой Gitea (gitea.netrunner-vpn.com), не
|
||
# ghcr.io — secrets.GT_REGISTRY_TOKEN, не GHCR_TOKEN/GITHUB_TOKEN.
|
||
# Триггер workflow_run (авто-деплой после успешной сборки) поддерживается не
|
||
# во всех версиях Gitea Actions — если deploy-dev не срабатывает автоматически
|
||
# после build, проверить версию Gitea или временно дергать деплой вручную
|
||
# через workflow_dispatch.
|
||
name: Deploy
|
||
|
||
# Один пайплайн, две джобы:
|
||
# - deploy-dev: авто, срабатывает после успешного "Build & Push Image" на main.
|
||
# - deploy-prod: вручную из вкладки Actions ("Run workflow"), как и раньше.
|
||
#
|
||
# .env на обоих VPS теперь полностью собирается этим workflow из repo
|
||
# Variables/Secrets (тот же принцип, что и в netrunner-data) — руками на
|
||
# сервере ничего не создаётся и не редактируется, весь конфиг живёт в
|
||
# Settings → Actions этого репозитория.
|
||
on:
|
||
workflow_run:
|
||
workflows: ["Build & Push Image"]
|
||
types: [completed]
|
||
branches: [main]
|
||
workflow_dispatch:
|
||
inputs:
|
||
image_tag:
|
||
description: "Тег образа в Gitea Registry для прод-деплоя"
|
||
required: true
|
||
default: "latest"
|
||
|
||
jobs:
|
||
deploy-dev:
|
||
name: Auto-deploy to Dev VPS
|
||
if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success'
|
||
runs-on: ubuntu-24.04
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
ref: ${{ github.event.workflow_run.head_sha }}
|
||
|
||
# Копируем compose-файл + Caddyfile (примонтированный конфиг, не образ —
|
||
# сам Caddy-образ, как и образ бэкенда, дев-сервер тянет из Gitea Registry,
|
||
# собран в build.yml::build-caddy. Собирать xcaddy прямо на VPS один раз уже не
|
||
# уложилось в таймаут SSH-деплоя и уронило весь прогон).
|
||
- name: Sync compose file to Dev VPS
|
||
uses: appleboy/scp-action@v0.1.7
|
||
with:
|
||
host: ${{ vars.DEV_VPS_IP }}
|
||
username: root
|
||
key: ${{ secrets.DEV_SSH_PRIVATE_KEY }}
|
||
source: "docker-compose.dev-remote.yml,Caddyfile.dev"
|
||
target: "/root/netrunner-core"
|
||
strip_components: 0
|
||
|
||
- name: Write .env and deploy via SSH
|
||
uses: appleboy/ssh-action@v1
|
||
with:
|
||
host: ${{ vars.DEV_VPS_IP }}
|
||
username: root
|
||
key: ${{ secrets.DEV_SSH_PRIVATE_KEY }}
|
||
envs: "DB_PASSWORD,CF_API_TOKEN,JWT_SECRET,ARGON_SALT,TON_MASTER_WALLET,PROXY_INTERNAL_SECRET,CRYPTOBOT_API_TOKEN,TELOXIDE_TOKEN,BOT_USERNAME,GT_REGISTRY_TOKEN"
|
||
script: |
|
||
set -e
|
||
cd /root/netrunner-core
|
||
|
||
# .env — статические значения (никогда не меняются между деплоями)
|
||
# зашиты здесь же литералом, секреты/domain-специфичное — из vars/secrets.
|
||
cat > .env <<EOF
|
||
DB_USER=netrunner_admin
|
||
DB_PASSWORD=${DB_PASSWORD}
|
||
DB_NAME=netrunner
|
||
CF_API_TOKEN=${CF_API_TOKEN}
|
||
JWT_SECRET=${JWT_SECRET}
|
||
ARGON_SALT=${ARGON_SALT}
|
||
TON_MASTER_WALLET=${TON_MASTER_WALLET}
|
||
PROXY_INTERNAL_SECRET=${PROXY_INTERNAL_SECRET}
|
||
# Нужен самому бэкенду в рантайме, не только CI — см.
|
||
# NodeService::provision_node_via_ssh (шлёт этот же токен на новую
|
||
# ноду, чтобы она тоже могла тянуть образ с gitea.netrunner-vpn.com).
|
||
GT_REGISTRY_TOKEN=${GT_REGISTRY_TOKEN}
|
||
CRYPTOBOT_API_TOKEN=${CRYPTOBOT_API_TOKEN}
|
||
CRYPTOBOT_TESTNET=true
|
||
BOT_ENABLED=true
|
||
TELOXIDE_TOKEN=${TELOXIDE_TOKEN}
|
||
BOT_USERNAME=${BOT_USERNAME}
|
||
WEB_APP_BASE_URL=https://dev.netrunner-vpn.com
|
||
SUBSCRIPTION_CHECK_INTERVAL=1800
|
||
RUST_LOG=netrunner_control_plane=debug,axum=info,tower_http=debug,sqlx=warn
|
||
CORS_ALLOWED_ORIGINS=http://localhost:1420,http://localhost:5173,tauri://localhost,http://tauri.localhost,http://dev.netrunner-vpn.com:3000,https://dev.netrunner-vpn.com
|
||
CSRF_ALLOWED_ORIGINS=http://localhost:1420,http://localhost:5173,http://dev.netrunner-vpn.com:3000,https://dev.netrunner-vpn.com
|
||
COOKIE_DOMAIN=
|
||
COOKIE_SECURE=true
|
||
EOF
|
||
chmod 600 .env
|
||
|
||
export IMAGE="gitea.netrunner-vpn.com/nineap/netrunner-control-plane:latest"
|
||
export CADDY_IMAGE="gitea.netrunner-vpn.com/nineap/netrunner-caddy-cloudflare:latest"
|
||
echo "🚀 Deploying ${IMAGE} to DEV"
|
||
|
||
echo "${{ secrets.GT_REGISTRY_TOKEN }}" | docker login gitea.netrunner-vpn.com -u ${{ github.actor }} --password-stdin
|
||
|
||
docker compose -f docker-compose.dev-remote.yml pull
|
||
docker compose -f docker-compose.dev-remote.yml up -d --remove-orphans
|
||
|
||
docker image prune -f
|
||
|
||
echo "✅ Dev synchronized."
|
||
env:
|
||
DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }}
|
||
CF_API_TOKEN: ${{ secrets.DEV_CF_API_TOKEN }}
|
||
JWT_SECRET: ${{ secrets.DEV_JWT_SECRET }}
|
||
ARGON_SALT: ${{ secrets.DEV_ARGON_SALT }}
|
||
TON_MASTER_WALLET: ${{ vars.TON_MASTER_WALLET }}
|
||
PROXY_INTERNAL_SECRET: ${{ secrets.DEV_PROXY_INTERNAL_SECRET }}
|
||
CRYPTOBOT_API_TOKEN: ${{ secrets.DEV_CRYPTOBOT_API_TOKEN }}
|
||
TELOXIDE_TOKEN: ${{ secrets.DEV_TELOXIDE_TOKEN }}
|
||
BOT_USERNAME: ${{ vars.DEV_BOT_USERNAME }}
|
||
GT_REGISTRY_TOKEN: ${{ secrets.GT_REGISTRY_TOKEN }}
|
||
|
||
deploy-prod:
|
||
name: Pull & restart on Prod VPS
|
||
if: github.event_name == 'workflow_dispatch'
|
||
runs-on: ubuntu-24.04
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Sync compose file to Prod VPS
|
||
uses: appleboy/scp-action@v0.1.7
|
||
with:
|
||
host: ${{ vars.VPS_IP }}
|
||
username: root
|
||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||
source: "docker-compose.prod.yml,promtail-config.yml"
|
||
target: "/root/netrunner-core"
|
||
strip_components: 0
|
||
|
||
- name: Write .env and deploy via SSH
|
||
uses: appleboy/ssh-action@v1
|
||
with:
|
||
host: ${{ vars.VPS_IP }}
|
||
username: root
|
||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||
envs: "DB_PASSWORD,DATA_VPS_IP,JWT_SECRET,ARGON_SALT,TON_MASTER_WALLET,GRAFANA_PUBLIC_URL,PROXY_INTERNAL_SECRET,CRYPTOBOT_API_TOKEN,TELOXIDE_TOKEN,BOT_USERNAME,WEB_APP_BASE_URL,GT_REGISTRY_TOKEN"
|
||
script: |
|
||
set -e
|
||
cd /root/netrunner-core
|
||
|
||
cat > .env <<EOF
|
||
DB_USER=netrunner_admin
|
||
DB_NAME=netrunner
|
||
DB_PASSWORD=${DB_PASSWORD}
|
||
DB_HOST=${DATA_VPS_IP}
|
||
DB_PORT=5432
|
||
REDIS_URL=redis://redis:6379
|
||
JWT_SECRET=${JWT_SECRET}
|
||
ARGON_SALT=${ARGON_SALT}
|
||
TON_MASTER_WALLET=${TON_MASTER_WALLET}
|
||
LOKI_PUSH_URL=http://${DATA_VPS_IP}:3100
|
||
GRAFANA_PUBLIC_URL=${GRAFANA_PUBLIC_URL}
|
||
CRYPTOBOT_API_TOKEN=${CRYPTOBOT_API_TOKEN}
|
||
BOT_ENABLED=true
|
||
TELOXIDE_TOKEN=${TELOXIDE_TOKEN}
|
||
BOT_USERNAME=${BOT_USERNAME}
|
||
WEB_APP_BASE_URL=${WEB_APP_BASE_URL}
|
||
PROXY_INTERNAL_SECRET=${PROXY_INTERNAL_SECRET}
|
||
# Нужен самому бэкенду в рантайме, не только CI — см.
|
||
# NodeService::provision_node_via_ssh.
|
||
GT_REGISTRY_TOKEN=${GT_REGISTRY_TOKEN}
|
||
PORT=8080
|
||
SUBSCRIPTION_CHECK_INTERVAL=1800
|
||
NODE_HEALTH_CHECK_INTERVAL=60
|
||
APP_ENV=production
|
||
RUST_LOG=netrunner_control_plane=info,axum=info,tower_http=info,sqlx=warn
|
||
CORS_ALLOWED_ORIGINS=https://netrunner-vpn.com,https://account.netrunner-vpn.com,tauri://localhost,http://tauri.localhost
|
||
CSRF_ALLOWED_ORIGINS=https://netrunner-vpn.com,https://account.netrunner-vpn.com
|
||
COOKIE_DOMAIN=.netrunner-vpn.com
|
||
COOKIE_SECURE=true
|
||
EOF
|
||
chmod 600 .env
|
||
|
||
export IMAGE="gitea.netrunner-vpn.com/nineap/netrunner-control-plane:${{ github.event.inputs.image_tag }}"
|
||
echo "🚀 Deploying ${IMAGE}"
|
||
|
||
echo "${{ secrets.GT_REGISTRY_TOKEN }}" | docker login gitea.netrunner-vpn.com -u ${{ github.actor }} --password-stdin
|
||
|
||
# Тянем свежий образ, прогоняем миграции (one-shot) и поднимаем сервисы.
|
||
docker compose -f docker-compose.prod.yml pull
|
||
docker compose -f docker-compose.prod.yml up -d --remove-orphans
|
||
|
||
# Чистим старые слои.
|
||
docker image prune -f
|
||
|
||
echo "✅ Uplink synchronized."
|
||
env:
|
||
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
|
||
DATA_VPS_IP: ${{ vars.DATA_VPS_IP }}
|
||
JWT_SECRET: ${{ secrets.JWT_SECRET }}
|
||
ARGON_SALT: ${{ secrets.ARGON_SALT }}
|
||
TON_MASTER_WALLET: ${{ vars.TON_MASTER_WALLET }}
|
||
GRAFANA_PUBLIC_URL: ${{ vars.GRAFANA_PUBLIC_URL }}
|
||
PROXY_INTERNAL_SECRET: ${{ secrets.PROXY_INTERNAL_SECRET }}
|
||
CRYPTOBOT_API_TOKEN: ${{ secrets.CRYPTOBOT_API_TOKEN }}
|
||
TELOXIDE_TOKEN: ${{ secrets.TELOXIDE_TOKEN }}
|
||
BOT_USERNAME: ${{ vars.BOT_USERNAME }}
|
||
WEB_APP_BASE_URL: ${{ vars.WEB_APP_BASE_URL }}
|
||
GT_REGISTRY_TOKEN: ${{ secrets.GT_REGISTRY_TOKEN }}
|