@@ -120,3 +120,82 @@ docker exec front-proxy caddy reload
120120Cutover is instant. Green is now live, and Blue is the idle stack.
121121
122122And rollback is simple : flip the `Caddyfile` back and `caddy reload` again.
123+
124+ # # Github Actions
125+
126+ Here's a workflow for B/G deploys :
127+
128+ <details>
129+ <summary>Click to expand</summary>
130+
131+ ` ` ` yaml title=".github/workflows/ci.yaml"
132+ name: Deploy to VPS
133+
134+ on:
135+ push:
136+ branches:
137+ - main
138+
139+ jobs:
140+ deploy:
141+ runs-on: ubuntu-latest
142+ environment: production
143+
144+ steps:
145+ - name: Checkout code
146+ uses: actions/checkout@v4
147+
148+ - name: Start SSH agent
149+ uses: webfactory/ssh-agent@v0.9.0
150+ with:
151+ ssh-private-key: ${{ secrets.VPS_SSH_KEY }}
152+
153+ - name: Get the idle stack
154+ id: idle
155+ run: |
156+ ACTIVE=$(ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no \
157+ ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} \
158+ 'cat active_stack 2>/dev/null || echo blue')
159+
160+ if [ "$ACTIVE" = "blue" ]; then
161+ echo "IDLE=green" >> $GITHUB_OUTPUT
162+ else
163+ echo "IDLE=blue" >> $GITHUB_OUTPUT
164+ fi
165+ echo "ACTIVE=$ACTIVE" >> $GITHUB_OUTPUT
166+
167+ - name: Copy compose.yaml to idle stack
168+ uses: appleboy/scp-action@master
169+ with:
170+ host: ${{ secrets.VPS_HOST }}
171+ username: ${{ secrets.VPS_USER }}
172+ port: 22
173+ key: ${{ secrets.VPS_SSH_KEY }}
174+ source: "compose.yaml"
175+ target: "${{ steps.idle.outputs.IDLE }}/"
176+
177+ - name: Deploy with Docker Compose
178+ uses: appleboy/ssh-action@v1.0.3
179+ with:
180+ host: ${{ secrets.VPS_HOST }}
181+ username: ${{ secrets.VPS_USER }}
182+ key: ${{ secrets.VPS_SSH_KEY }}
183+ envs: GHCR_PAT,JWT_SECRET,POSTGRES_USER,PGUSER,POSTGRES_PASSWORD,PGPASS,PGRST_AUTHENTICATOR_PASS
184+ script: |
185+ set -euo pipefail
186+ echo $GHCR_PAT | docker login ghcr.io -u ${{ github.actor }} --password-stdin
187+ cd ${{ steps.idle.outputs.IDLE }}
188+ docker compose pull -q
189+ docker compose up -d
190+ echo "${{ steps.idle.outputs.ACTIVE }}" > active_stack
191+ env:
192+ GHCR_PAT: ${{ secrets.GHCR_PAT }}
193+ JWT_SECRET: ${{ secrets.JWT_SECRET }}
194+ PGRST_AUTHENTICATOR_PASS: ${{ secrets.PGRST_AUTHENTICATOR_PASS }}
195+ PGUSER: ${{ secrets.PGUSER }}
196+ PGPASS: ${{ secrets.PGPASS }}
197+ POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
198+ POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
199+ ` ` `
200+
201+ </details>
0 commit comments