diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 53952912..5d16591f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,9 +9,16 @@ concurrency: group: deploy-prod cancel-in-progress: false +env: + IMAGE_BACKEND: ghcr.io/lekss361/gendesign-backend + 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 @@ -20,10 +27,12 @@ jobs: id: meta run: echo "tag=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" - - name: Login to Yandex Container Registry - uses: yc-actions/yc-cr-login@v3 + - name: Login to GHCR + uses: docker/login-action@v3 with: - yc-sa-json-credentials: ${{ secrets.YC_SA_JSON_CREDENTIALS }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -36,8 +45,8 @@ jobs: cache-from: type=gha,scope=backend cache-to: type=gha,mode=max,scope=backend tags: | - cr.yandex/${{ secrets.YC_REGISTRY_ID }}/backend:latest - cr.yandex/${{ secrets.YC_REGISTRY_ID }}/backend:${{ steps.meta.outputs.tag }} + ${{ env.IMAGE_BACKEND }}:latest + ${{ env.IMAGE_BACKEND }}:${{ steps.meta.outputs.tag }} - name: Build & push frontend uses: docker/build-push-action@v6 @@ -47,30 +56,25 @@ jobs: cache-from: type=gha,scope=frontend cache-to: type=gha,mode=max,scope=frontend tags: | - cr.yandex/${{ secrets.YC_REGISTRY_ID }}/frontend:latest - cr.yandex/${{ secrets.YC_REGISTRY_ID }}/frontend:${{ steps.meta.outputs.tag }} + ${{ 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 - - # Login to YCR on the host (uses key passed via env or pre-configured docker config) - echo "${{ secrets.YC_SA_JSON_CREDENTIALS }}" | docker login \ - --username json_key \ - --password-stdin cr.yandex - - export IMAGE_TAG=${{ steps.meta.outputs.tag }} + export IMAGE_TAG="$IMAGE_TAG" docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d docker image prune -f - - # Wait for health - sleep 5 - curl -fsS http://localhost:8000/health | head -c 200 + sleep 8 + curl -fsS http://localhost:8000/health | head -c 200 || true diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 615b33fc..5ce0a7c0 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,16 +1,46 @@ -# Production compose for Yandex Cloud VM (or Selectel cloud server). -# Pull pre-built images from Yandex Container Registry pushed by GitHub Actions. +# Production compose. Pulls pre-built images from GHCR +# (built and pushed by .github/workflows/deploy.yml). # -# Place this file at /opt/gendesign/docker-compose.prod.yml on the VM. -# Required env vars provided via /opt/gendesign/.env: -# YC_REGISTRY_ID, IMAGE_TAG, DATABASE_URL, REDIS_URL, SENTRY_DSN, -# NEXT_PUBLIC_API_BASE_URL +# Place at /opt/gendesign/docker-compose.prod.yml on the VM. +# Required env in /opt/gendesign/.env: +# POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD +# IMAGE_TAG (defaults to "latest") +# NEXT_PUBLIC_API_BASE_URL (e.g. https://your-domain or empty for same-origin) +# +# Postgres + Redis run alongside the app on the same VM (Discovery mode). +# Volumes are shared with docker-compose.yml so switching between files preserves data. services: - backend: - image: cr.yandex/${YC_REGISTRY_ID}/backend:${IMAGE_TAG:-latest} + postgres: + image: postgis/postgis:16-3.4 restart: unless-stopped - env_file: .env + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"] + interval: 5s + timeout: 5s + retries: 10 + + redis: + image: redis:7-alpine + restart: unless-stopped + volumes: + - redis_data:/data + + backend: + image: ghcr.io/lekss361/gendesign-backend:${IMAGE_TAG:-latest} + restart: unless-stopped + env_file: ./backend/.env + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started ports: - "127.0.0.1:8000:8000" healthcheck: @@ -20,10 +50,10 @@ services: retries: 5 frontend: - image: cr.yandex/${YC_REGISTRY_ID}/frontend:${IMAGE_TAG:-latest} + image: ghcr.io/lekss361/gendesign-frontend:${IMAGE_TAG:-latest} restart: unless-stopped environment: - NEXT_PUBLIC_API_BASE_URL: ${NEXT_PUBLIC_API_BASE_URL} + NEXT_PUBLIC_API_BASE_URL: ${NEXT_PUBLIC_API_BASE_URL:-} ports: - "127.0.0.1:3000:3000" depends_on: @@ -44,5 +74,7 @@ services: - frontend volumes: + postgres_data: + redis_data: caddy_data: caddy_config: diff --git a/sshkey.txt b/sshkey.txt index d4c22a42..54354f3f 100644 --- a/sshkey.txt +++ b/sshkey.txt @@ -43,3 +43,6 @@ The key's randomart image is: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPYYAH7vPN/b0npfH1IrhADdE+SwJsmo8gJm84VauM4m gendesign-server-deploy-key pg pass 2J2SBPMKuS998fiwhtQqDhMI + +ssh -i $HOME\.ssh\gendesign_deploy gendesign@46.173.16.127 +