feat(wave5): CI/CD pipeline + Vault KMS + OKR deploy to port 80/3001
Infrastructure (H3 CI gate, H5 KMS): - Gitea Actions enabled (GITEA__actions__ENABLED=true) - act_runner: Docker-outside-of-Docker for deploy job - Vault Transit RSA-2048 signing keys (casan-audit-key, casan-policy-key) Vault KMS scripts (H5 governance): - .specify/scripts/bash/vault-kms.sh — sign/verify/pubkey/ensure-key - .specify/scripts/bash/sign-audit-head.sh — sign audit chain via Vault - Updated sign-policy-bundle.sh — Vault path + local fallback - Updated security-gate.sh — KMS gate added (PASS=11 FAIL=0) OKR app deployment (port 80/3001): - Dockerfile.backend — node:22-slim (node:sqlite requires Node 22) - Dockerfile.frontend — node:20-alpine build + nginx:alpine runtime - nginx/nginx.conf — React SPA + /api/v1/* proxy to okr-backend:3001 - backend/entrypoint.sh — auto init DB on first run + seed - .dockerignore CI pipeline (.gitea/workflows/ci.yml): - Job 1: Vitest frontend tests (H3) - Job 2: CASAN security gate + Vault KMS signing (H4/H5) - Job 3: Deploy OKR → port 80 (runs on push to main after tests pass) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6e95e929f0
commit
9892e82221
@@ -0,0 +1,222 @@
|
||||
# VPS CI/CD Setup Runbook
|
||||
# Oracle Cloud Tokyo — 161.33.139.73
|
||||
|
||||
## Architecture
|
||||
```
|
||||
VPS (Ubuntu 24.04, 1 GB RAM)
|
||||
├── /opt/gitea/
|
||||
│ ├── docker-compose.yml ← add act-runner service here
|
||||
│ ├── .env ← add RUNNER_REGISTRATION_TOKEN here
|
||||
│ ├── act-runner-config.yaml ← copy from .gitea/act-runner-config.yaml
|
||||
│ └── gitea-data/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Enable Gitea Actions
|
||||
|
||||
SSH into the VPS:
|
||||
```bash
|
||||
ssh ubuntu@161.33.139.73
|
||||
```
|
||||
|
||||
Add the Actions env variable to the Gitea service in docker-compose.yml:
|
||||
```yaml
|
||||
# In the gitea service environment section, add:
|
||||
- GITEA__actions__ENABLED=true
|
||||
```
|
||||
|
||||
Restart Gitea:
|
||||
```bash
|
||||
cd /opt/gitea
|
||||
docker compose restart gitea
|
||||
```
|
||||
|
||||
Verify: Open http://161.33.139.73:3000 → Site Administration → Runners
|
||||
You should see "Runners" menu item (confirming Actions is enabled).
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Get the Runner Registration Token
|
||||
|
||||
1. Log into Gitea as admin: http://161.33.139.73:3000
|
||||
2. Go to: Site Administration (⚙) → Runners → "Create new runner"
|
||||
3. Copy the **Registration Token** shown (looks like: `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`)
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Copy act_runner config to VPS
|
||||
|
||||
From your local machine:
|
||||
```bash
|
||||
scp AINative_OKR_CASAN5/.gitea/act-runner-config.yaml \
|
||||
ubuntu@161.33.139.73:/opt/gitea/act-runner-config.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Add RUNNER_REGISTRATION_TOKEN to /opt/gitea/.env
|
||||
|
||||
On the VPS:
|
||||
```bash
|
||||
# Replace <TOKEN> with the token copied in Step 2
|
||||
echo "RUNNER_REGISTRATION_TOKEN=<TOKEN>" >> /opt/gitea/.env
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Add act_runner service to docker-compose.yml
|
||||
|
||||
Edit `/opt/gitea/docker-compose.yml` and add the `act-runner` service.
|
||||
|
||||
**Typical Gitea docker-compose.yml after changes:**
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
gitea:
|
||||
external: false
|
||||
|
||||
volumes:
|
||||
gitea-data:
|
||||
act-runner-data:
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: always
|
||||
networks:
|
||||
- gitea
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__actions__ENABLED=true # ← ADD THIS LINE
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "2222:22"
|
||||
volumes:
|
||||
- ./gitea-data:/data
|
||||
|
||||
act-runner:
|
||||
image: gitea/act_runner:latest
|
||||
container_name: act-runner
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- gitea # same network as gitea
|
||||
depends_on:
|
||||
- gitea
|
||||
environment:
|
||||
- GITEA_INSTANCE_URL=http://gitea:3000 # internal Docker hostname
|
||||
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_REGISTRATION_TOKEN}
|
||||
- GITEA_RUNNER_NAME=casan-runner-oracle
|
||||
- CONFIG_FILE=/config/act-runner-config.yaml
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock # DinD for job containers
|
||||
- ./act-runner-config.yaml:/config/act-runner-config.yaml:ro
|
||||
- act-runner-data:/data
|
||||
```
|
||||
|
||||
> If your current docker-compose.yml already has a `networks:` or `volumes:` section,
|
||||
> merge them — don't add duplicate top-level keys.
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — Start act_runner
|
||||
|
||||
```bash
|
||||
cd /opt/gitea
|
||||
docker compose pull act-runner
|
||||
docker compose up -d act-runner
|
||||
```
|
||||
|
||||
Check registration:
|
||||
```bash
|
||||
docker compose logs -f act-runner
|
||||
# Look for: "runner registered" or "connected to Gitea"
|
||||
```
|
||||
|
||||
In Gitea Web UI: Site Administration → Runners → you should see "casan-runner-oracle" with status **Online**.
|
||||
|
||||
---
|
||||
|
||||
## Step 7 — Pull the catthehacker runner image (one-time)
|
||||
|
||||
The first CI run will pull `catthehacker/ubuntu:act-22.04` (~2 GB). Pre-pull to avoid timeout:
|
||||
|
||||
```bash
|
||||
docker pull catthehacker/ubuntu:act-22.04
|
||||
```
|
||||
|
||||
This takes ~2-5 minutes depending on internet speed.
|
||||
|
||||
---
|
||||
|
||||
## Step 8 — Create repo in Gitea and push the project
|
||||
|
||||
On the VPS (or via Gitea web UI), create a new repository:
|
||||
- URL: http://161.33.139.73:3000
|
||||
- Name: `casan5` (or any name)
|
||||
- Make it public or private (your choice)
|
||||
|
||||
On your local machine:
|
||||
```bash
|
||||
cd Output_CASAN5_REFINED/AINative_OKR_CASAN5
|
||||
|
||||
# Add Gitea as remote
|
||||
git remote add gitea ssh://git@161.33.139.73:2222/<YOUR_USER>/casan5.git
|
||||
|
||||
# Push
|
||||
git push gitea main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 9 — Verify CI triggered
|
||||
|
||||
After push, go to:
|
||||
http://161.33.139.73:3000/<YOUR_USER>/casan5/actions
|
||||
|
||||
You should see a workflow run in progress. Click it to see live logs.
|
||||
|
||||
Expected final result:
|
||||
```
|
||||
✅ Frontend Tests (H3 gate) — 16/16 PASS
|
||||
✅ CASAN Security Gate (H4/H5/H2) — PASS=7 SKIP=1 FAIL=0
|
||||
```
|
||||
|
||||
SKIP=1 is expected (Ollama is not on the CI server — this is the model-router/red-team group).
|
||||
The gate exits 0 because FAIL=0.
|
||||
|
||||
---
|
||||
|
||||
## Memory Monitoring
|
||||
|
||||
```bash
|
||||
# Watch RAM usage while CI runs
|
||||
watch -n 2 'free -h && docker stats --no-stream'
|
||||
```
|
||||
|
||||
If OOM occurs, reduce the job container memory limit in act-runner-config.yaml
|
||||
or add swap:
|
||||
```bash
|
||||
sudo fallocate -l 1G /swapfile
|
||||
sudo chmod 600 /swapfile
|
||||
sudo mkswap /swapfile
|
||||
sudo swapon /swapfile
|
||||
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Fix |
|
||||
|---|---|
|
||||
| Runner shows "Offline" | Check `docker compose logs act-runner`; verify token is correct |
|
||||
| `GITEA_INSTANCE_URL` unreachable | Ensure gitea and act-runner are on the same Docker network |
|
||||
| Job stuck "Waiting for runner" | Runner is busy (capacity=1); wait or increase capacity |
|
||||
| `python: command not found` | The workflow's "Install test tools" step installs `python-is-python3` |
|
||||
| OOM during npm ci | Switch to `npm ci -w frontend` (already done in workflow) or add swap |
|
||||
| `catthehacker/ubuntu:act-22.04` pull fails | Run `docker pull` manually on VPS first |
|
||||
Reference in New Issue
Block a user