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,
|
# Rebuild + roll aibook.fun forward on any push to main.
|
||||||
# pin the image ref in Infisical, then trigger a pull + bounce on the droplet.
|
# Runner: repo-registered act_runner on the aibook.fun droplet itself
|
||||||
#
|
# (co-located → local docker commands, no cross-host SSH needed).
|
||||||
# Runs on Gitea Actions (GitHub-compatible syntax). This repo has Actions
|
|
||||||
# enabled; the runner must be labeled `ubuntu-latest`.
|
|
||||||
#
|
#
|
||||||
# Repository secrets required (Settings → Actions → Secrets):
|
# Repository secrets required (Settings → Actions → Secrets):
|
||||||
# MINIMUS_TOKEN reg.mini.dev registry token (u: minimus)
|
# (none — runner is on the droplet, has local root)
|
||||||
# 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.
|
|
||||||
|
|
||||||
name: deploy
|
name: deploy
|
||||||
|
|
||||||
@@ -28,78 +16,23 @@ on:
|
|||||||
- '.gitea/workflows/**'
|
- '.gitea/workflows/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: aibook-fun-deploy
|
group: aibook-fun-deploy
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: reg.mini.dev
|
|
||||||
IMAGE_REPO: weownai/aibook-fun-marketing
|
|
||||||
INFISICAL_ENV: prod
|
|
||||||
INFISICAL_PATH: /AIBook-Fun
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-deploy:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: aibook-fun-droplet
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Pull latest + rebuild + roll
|
||||||
|
|
||||||
- name: Build image
|
|
||||||
run: |
|
run: |
|
||||||
docker build \
|
set -euo pipefail
|
||||||
--pull \
|
cd /opt/aibook_fun/repo
|
||||||
-f deploy/docker-compose/docker/Dockerfile \
|
git fetch --prune origin
|
||||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_REPO }}:${{ github.sha }}" \
|
git reset --hard origin/main
|
||||||
-t "${{ env.REGISTRY }}/${{ env.IMAGE_REPO }}:latest" \
|
docker build -t aibook-fun-marketing:v1 \
|
||||||
marketing-site/
|
-f /opt/aibook_fun/repo/deploy/docker/Dockerfile \
|
||||||
|
/opt/aibook_fun/repo/marketing-site/
|
||||||
- name: Login to reg.mini.dev
|
cd /opt/aibook_fun
|
||||||
run: echo "${{ secrets.MINIMUS_TOKEN }}" | docker login "${{ env.REGISTRY }}" -u minimus --password-stdin
|
docker compose up -d --remove-orphans
|
||||||
|
docker image prune -f --filter "dangling=true"
|
||||||
- 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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user