ci(deploy): rewrite for build-on-droplet + local runner #5
+17
-84
@@ -1,21 +1,9 @@
|
||||
# aibook-fun — CI/CD: build the Next.js marketing site, push to reg.mini.dev,
|
||||
# pin the image ref in Infisical, then trigger a pull + bounce on the droplet.
|
||||
#
|
||||
# Runs on Gitea Actions (GitHub-compatible syntax). This repo has Actions
|
||||
# enabled; the runner must be labeled `ubuntu-latest`.
|
||||
# Rebuild + roll aibook.fun forward on any push to main.
|
||||
# Runner: repo-registered act_runner on the aibook.fun droplet itself
|
||||
# (co-located → local docker commands, no cross-host SSH needed).
|
||||
#
|
||||
# Repository secrets required (Settings → Actions → Secrets):
|
||||
# MINIMUS_TOKEN reg.mini.dev registry token (u: minimus)
|
||||
# INFISICAL_CLIENT_ID Infisical Machine Identity Client ID
|
||||
# INFISICAL_CLIENT_SECRET Infisical Machine Identity Client Secret
|
||||
# INFISICAL_PROJECT_ID the /AIBook-Fun project ID
|
||||
# DROPLET_IP droplet reserved IP (or resolve via DNS)
|
||||
# DROPLET_SSH_KEY private SSH key for root@ on the droplet
|
||||
#
|
||||
# NOTE: first provision is NOT done here — it's terraform + ansible converge
|
||||
# (deploy/docker-compose/terraform + ansible/deploy.yml). This workflow handles
|
||||
# everything after the site exists: every main-branch push to app/deploy code
|
||||
# rebuilds and rolls forward idempotently.
|
||||
# (none — runner is on the droplet, has local root)
|
||||
|
||||
name: deploy
|
||||
|
||||
@@ -28,78 +16,23 @@ on:
|
||||
- '.gitea/workflows/**'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: aibook-fun-deploy
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
REGISTRY: reg.mini.dev
|
||||
IMAGE_REPO: weownai/aibook-fun-marketing
|
||||
INFISICAL_ENV: prod
|
||||
INFISICAL_PATH: /AIBook-Fun
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
deploy:
|
||||
runs-on: aibook-fun-droplet
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build image
|
||||
- name: Pull latest + rebuild + roll
|
||||
run: |
|
||||
docker build \
|
||||
--pull \
|
||||
-f deploy/docker-compose/docker/Dockerfile \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_REPO }}:${{ github.sha }}" \
|
||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_REPO }}:latest" \
|
||||
marketing-site/
|
||||
|
||||
- name: Login to reg.mini.dev
|
||||
run: echo "${{ secrets.MINIMUS_TOKEN }}" | docker login "${{ env.REGISTRY }}" -u minimus --password-stdin
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
docker push "${{ env.REGISTRY }}/${{ env.IMAGE_REPO }}:${{ github.sha }}"
|
||||
docker push "${{ env.REGISTRY }}/${{ env.IMAGE_REPO }}:latest"
|
||||
|
||||
- name: Pin AIBOOK_IMAGE in Infisical
|
||||
env:
|
||||
INFISICAL_UNIVERSAL_AUTH_CLIENT_ID: ${{ secrets.INFISICAL_CLIENT_ID }}
|
||||
INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET }}
|
||||
run: |
|
||||
sudo curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | sudo -E bash
|
||||
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq infisical >/dev/null
|
||||
export INFISICAL_TOKEN="$(infisical login --method=universal-auth --plain --silent)"
|
||||
infisical secrets set \
|
||||
AIBOOK_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_REPO }}:${{ github.sha }}" \
|
||||
--projectId="${{ secrets.INFISICAL_PROJECT_ID }}" \
|
||||
--env="${{ env.INFISICAL_ENV }}" \
|
||||
--path="${{ env.INFISICAL_PATH }}"
|
||||
|
||||
- name: Deploy to droplet (pull + up)
|
||||
uses: appleboy/ssh-action@v1
|
||||
with:
|
||||
host: ${{ secrets.DROPLET_IP }}
|
||||
username: root
|
||||
key: ${{ secrets.DROPLET_SSH_KEY }}
|
||||
command_timeout: "15m"
|
||||
script: |
|
||||
set -euo pipefail
|
||||
cd /opt/aibook_fun
|
||||
# Droplet-side Infisical auth (auth file written by cloud-init).
|
||||
source .infisical-auth.env
|
||||
export INFISICAL_UNIVERSAL_AUTH_CLIENT_ID="$INFISICAL_CLIENT_ID"
|
||||
export INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET="$INFISICAL_CLIENT_SECRET"
|
||||
export INFISICAL_TOKEN="$(infisical login --method=universal-auth --plain --silent)"
|
||||
# Re-auth reg.mini.dev if the docker login from ansible has lapsed.
|
||||
MINIMUS_TOKEN="$(infisical secrets get MINIMUS_TOKEN --projectId="$INFISICAL_PROJECT_ID" --env=prod --path=/AIBook-Fun --plain || true)"
|
||||
if [ -n "${MINIMUS_TOKEN:-}" ]; then
|
||||
printf '%s' "$MINIMUS_TOKEN" | docker login reg.mini.dev -u minimus --password-stdin
|
||||
fi
|
||||
# AIBOOK_IMAGE is injected by `infisical run`; also export it so the
|
||||
# ${AIBOOK_IMAGE:?} compose ref resolves even without run-injection.
|
||||
export AIBOOK_IMAGE="$(infisical secrets get AIBOOK_IMAGE --projectId="$INFISICAL_PROJECT_ID" --env=prod --path=/AIBook-Fun --plain)"
|
||||
infisical run --projectId="$INFISICAL_PROJECT_ID" --env=prod --path=/AIBook-Fun \
|
||||
-- docker compose up -d --remove-orphans
|
||||
set -euo pipefail
|
||||
cd /opt/aibook_fun/repo
|
||||
git fetch --prune origin
|
||||
git reset --hard origin/main
|
||||
docker build -t aibook-fun-marketing:v1 \
|
||||
-f /opt/aibook_fun/repo/deploy/docker/Dockerfile \
|
||||
/opt/aibook_fun/repo/marketing-site/
|
||||
cd /opt/aibook_fun
|
||||
docker compose up -d --remove-orphans
|
||||
docker image prune -f --filter "dangling=true"
|
||||
|
||||
Reference in New Issue
Block a user