mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-11 03:13:46 +00:00
chore: switch to Apache-2.0 license; import plans from upstream miti99bot
This commit is contained in:
1 parent
ab617ade63
commit
5d27cd8356
57 files changed
+9724
-17
No files matched your search
@@ -0,0 +1,90 @@
|
||||
---
|
||||
phase: 10
|
||||
title: "CI/CD + Dockerfile + Secret Manager"
|
||||
status: pending
|
||||
priority: P2
|
||||
effort: "4h"
|
||||
dependencies: [2]
|
||||
---
|
||||
|
||||
# Phase 10: CI/CD + Dockerfile + Secret Manager
|
||||
|
||||
## Overview
|
||||
Production-grade build + deploy pipeline. GitHub Actions builds image, pushes to Artifact Registry, deploys to Cloud Run. Secrets pulled from Secret Manager at runtime via Cloud Run's `--set-secrets`. Post-deploy hook runs `setWebhook` + `setMyCommands` against Telegram (replacing JS `scripts/register.js`).
|
||||
|
||||
## Requirements
|
||||
- Functional: PR → CI green; merge to `main` → auto-deploy to Cloud Run; deploy includes Telegram registration.
|
||||
- Non-functional: build time ≤2 min; no secrets in image, in env yaml, or in repo. Workload Identity Federation between GHA + GCP (no long-lived JSON key).
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
.github/workflows/
|
||||
├── ci.yml ← PRs: vet, test, build (no deploy)
|
||||
└── deploy.yml ← main: build, push to AR, deploy Cloud Run, register Telegram
|
||||
|
||||
cmd/register/main.go ← Go port of scripts/register.js (setWebhook + setMyCommands)
|
||||
Dockerfile ← finalized multi-stage
|
||||
firestore.indexes.json ← composite indexes (Phase 08)
|
||||
.dockerignore
|
||||
```
|
||||
|
||||
Secret Manager secrets (created in Phase 01, populated here):
|
||||
- `telegram-bot-token`
|
||||
- `telegram-webhook-secret`
|
||||
- `gemini-api-key`
|
||||
|
||||
Cloud Run service env (non-secret):
|
||||
- `MODULES=util,misc,wordle,loldle,loldle-emoji,loldle-quote,loldle-ability,loldle-splash,trading,lolschedule,semantle,doantu,twentyq`
|
||||
- `GOOGLE_CLOUD_PROJECT`
|
||||
- `LOG_LEVEL=info`
|
||||
|
||||
## Related Code Files
|
||||
- Create: `.github/workflows/{ci,deploy}.yml`
|
||||
- Create: `cmd/register/main.go`
|
||||
- Modify: `Dockerfile` (finalize from Phase 02)
|
||||
- Create: `infra/cloud-run.yaml` (declarative service spec) OR keep imperative `gcloud run deploy` flags
|
||||
|
||||
## Implementation Steps
|
||||
1. **Workload Identity Federation setup** (one-time):
|
||||
- `gcloud iam workload-identity-pools create github-pool --location=global`.
|
||||
- `gcloud iam workload-identity-pools providers create-oidc github-provider …`.
|
||||
- Bind `roles/iam.workloadIdentityUser` from GHA repo → `miti99bot-deployer` SA.
|
||||
2. **Dockerfile finalization**:
|
||||
- Builder: `FROM golang:1.23-alpine`, install ca-certs, `CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /server ./cmd/server`.
|
||||
- Runtime: `FROM gcr.io/distroless/static-debian12:nonroot`, `COPY --from=builder /server /server`, `USER nonroot`, `ENTRYPOINT ["/server"]`.
|
||||
3. **`ci.yml`**:
|
||||
- Triggers: `pull_request`, `push: branches: [main]`.
|
||||
- Steps: checkout, setup-go, `go vet ./...`, `go test ./...`, `go build ./...`. (No emulator integration tests in CI — run locally.)
|
||||
4. **`deploy.yml`**:
|
||||
- Trigger: `push: branches: [main]` after `ci` workflow succeeds.
|
||||
- Auth via WIF (`google-github-actions/auth@v2`).
|
||||
- Build + push: `docker build -t asia-southeast1-docker.pkg.dev/$PROJECT/miti99bot-go/server:$SHA .; docker push …`.
|
||||
- Deploy: `gcloud run deploy miti99bot-go --image=… --region=asia-southeast1 --service-account=miti99bot-runtime@… --set-env-vars="MODULES=…,GOOGLE_CLOUD_PROJECT=$PROJECT" --set-secrets="TELEGRAM_BOT_TOKEN=telegram-bot-token:latest,TELEGRAM_WEBHOOK_SECRET=telegram-webhook-secret:latest,GEMINI_API_KEY=gemini-api-key:latest" --min-instances=0 --max-instances=2 --memory=256Mi --cpu=1 --timeout=30s --allow-unauthenticated`.
|
||||
- Apply Firestore indexes: `gcloud firestore indexes composite create --collection-group=trading_users --field-config=field-path=pnlVnd,order=descending` (idempotent — errors on already-exists, swallow).
|
||||
- Apply Scheduler jobs: invoke `scripts/setup-scheduler.sh` with current Cloud Run URL.
|
||||
- Post-deploy: `go run ./cmd/register` reads `MODULES` + Cloud Run URL + bot token from env, calls Telegram `setWebhook` (with secret token) + `setMyCommands` (public commands only). Idempotent.
|
||||
5. **`cmd/register/main.go`**:
|
||||
- Build registry locally (no Firestore — embed an `OfflineKVStore` that no-ops). Walk public commands.
|
||||
- HTTP POST to `https://api.telegram.org/bot<TOKEN>/setWebhook` with `{url, secret_token, allowed_updates: ["message"]}`.
|
||||
- HTTP POST to `…/setMyCommands` with `{commands: [{command, description}]}`.
|
||||
- `--dry-run` flag prints payloads without calling API (parity with JS `register:dry`).
|
||||
6. **Concurrency-1 lock** on `deploy.yml` to prevent overlapping deploys (Cloud Run handles multiple revisions, but webhook race is annoying).
|
||||
7. **Smoke after deploy**: GHA waits 10s, curls `/` → expect 200 "miti99bot-go ok"; if not, fail the workflow.
|
||||
|
||||
## Success Criteria
|
||||
- [ ] PR triggers CI, all checks pass
|
||||
- [ ] Merge → deploy runs end-to-end, Cloud Run revision served
|
||||
- [ ] No secret values appear in workflow logs
|
||||
- [ ] Telegram webhook is set after deploy (verify `getWebhookInfo`)
|
||||
- [ ] `setMyCommands` reflects current `MODULES`
|
||||
- [ ] Image size ≤30 MiB
|
||||
|
||||
## Risk Assessment
|
||||
- **Risk**: WIF setup is tricky; bad bind → GHA can't auth. **Mitigation**: validate via a manual workflow run before relying on auto-deploy.
|
||||
- **Risk**: Deploy runs Telegram register before Cloud Run is healthy → Telegram pings new URL, gets 503. **Mitigation**: smoke `/` first, register only after.
|
||||
- **Risk**: A bad deploy auto-flips webhook to broken revision. **Mitigation**: Cloud Run keeps prior revision; manual `gcloud run services update-traffic` is the rollback. Document in deployment-guide.md.
|
||||
- **Risk**: Cost spike if `--max-instances` set too high under attack. **Mitigation**: capped at 2 — handles VN-side org load comfortably; raise only if measured.
|
||||
|
||||
## Rollback
|
||||
`gcloud run services update-traffic miti99bot-go --to-revisions=<previous>=100`. Re-register webhook against prev URL not needed (URL is service-level, not revision-level).
|
||||
Reference in new issue
Block a user