diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3f3ad33..38f1cfd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,6 +10,10 @@ on: branches: [main] workflow_dispatch: +# Images are pushed to Docker Hub (obchain219/volx-*). Requires repo secrets: +# DOCKER_USERNAME (obchain219) DOCKER_PASSWORD (Docker Hub access token) +# SERVER_SSH_KEY (+ optional SERVER_KNOWN_HOSTS) + # One deploy at a time; never cancel mid-flight (would risk a half-applied # stack). Queued runs wait their turn. concurrency: @@ -22,10 +26,8 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest timeout-minutes: 30 - # Only the build job pushes images; deploy needs nothing beyond read. permissions: contents: read - packages: write strategy: fail-fast: false matrix: @@ -39,12 +41,11 @@ jobs: - uses: docker/setup-buildx-action@v3 - - name: Log in to GHCR + - name: Log in to Docker Hub uses: docker/login-action@v3 with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Build & push ${{ matrix.svc }} uses: docker/build-push-action@v6 @@ -53,8 +54,8 @@ jobs: file: ${{ matrix.dockerfile }} push: true tags: | - ghcr.io/${{ github.repository_owner }}/volx-${{ matrix.svc }}:latest - ghcr.io/${{ github.repository_owner }}/volx-${{ matrix.svc }}:${{ github.sha }} + ${{ secrets.DOCKER_USERNAME }}/volx-${{ matrix.svc }}:latest + ${{ secrets.DOCKER_USERNAME }}/volx-${{ matrix.svc }}:${{ github.sha }} cache-from: type=gha,scope=${{ matrix.svc }} cache-to: type=gha,mode=max,scope=${{ matrix.svc }} @@ -100,14 +101,26 @@ jobs: - name: Ship compose + deploy script, then pull & apply env: DEPLOY_DIR: /home/ancilar/volx-deploy + # Keeper runtime secrets — written into the server .env each deploy. + # GitHub masks these values in the logs. + SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + # Pin the server's registry to whatever CI pushed to, so the compose + # default can never drift from the images that were just built. + VOLX_REGISTRY: ${{ secrets.DOCKER_USERNAME }} run: | ssh ssh.ancilar.com "mkdir -p $DEPLOY_DIR" scp docker/docker-compose.prod.yml ssh.ancilar.com:"$DEPLOY_DIR/docker-compose.prod.yml" scp docker/clickhouse-init.sql ssh.ancilar.com:"$DEPLOY_DIR/clickhouse-init.sql" scp scripts/deploy.sh ssh.ancilar.com:"$DEPLOY_DIR/deploy.sh" - # The server already holds $DEPLOY_DIR/.env (keeper secrets), placed - # once by hand. deploy.sh pulls the freshly-pushed images and recreates - # only the services whose digest changed. + # Write the runtime .env on the server from the GitHub secrets (umask + # 077 -> 0600). docker compose auto-loads it; the keeper reads the keys. + # Docker Hub repos must be PUBLIC (no server-side login is configured). + ssh ssh.ancilar.com "umask 077; cat > $DEPLOY_DIR/.env" < docker login ghcr.io as ${GHCR_USER:-obchain}" - echo "$GHCR_TOKEN" | docker login ghcr.io -u "${GHCR_USER:-obchain}" --password-stdin +# Docker Hub auth only needed for PRIVATE repos. Public repos pull anonymously; +# set DOCKER_USERNAME + DOCKER_PASSWORD (access token) in .env if private. +if [ -n "${DOCKER_USERNAME:-}" ] && [ -n "${DOCKER_PASSWORD:-}" ]; then + echo "==> docker login as $DOCKER_USERNAME" + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin fi -echo "==> pulling images (${VOLX_REGISTRY:-ghcr.io/obchain}, tag ${VOLX_TAG:-latest})" +echo "==> pulling images (${VOLX_REGISTRY:-obchain219}, tag ${VOLX_TAG:-latest})" "${DC[@]}" "${PROFILE_ARGS[@]}" pull # `up -d` diffs each service's desired vs running state and recreates only the