feat(deploy): aibook.fun deploy layer (terraform + ansible + docker on DO)
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# 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`.
|
||||
#
|
||||
# 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.
|
||||
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'marketing-site/**'
|
||||
- 'deploy/**'
|
||||
- '.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
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build image
|
||||
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
|
||||
Reference in New Issue
Block a user