docs: document CI/CD bootstrap, seed images, and troubleshooting
Build and Deploy Platform / build-and-deploy (push) Successful in 8m9s
Build and Deploy Platform / build-and-deploy (push) Successful in 8m9s
Add bootstrap checklist (seed-ci-images, Sealed Secrets, two-repo GitOps), Kaniko BASE_IMAGE/insecure-pull details, platform secret requirements, and updated gitops install order. Link RUNBOOK-CICD from README. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,6 +13,8 @@ custom `wp-content` entrypoint).
|
|||||||
> 🇮🇷 Production deployment on the `abrban.com` k3s cluster — including all the
|
> 🇮🇷 Production deployment on the `abrban.com` k3s cluster — including all the
|
||||||
> Iran-network workarounds — is documented step-by-step in **[RUNBOOK.fa.md](RUNBOOK.fa.md)** (Persian).
|
> Iran-network workarounds — is documented step-by-step in **[RUNBOOK.fa.md](RUNBOOK.fa.md)** (Persian).
|
||||||
|
|
||||||
|
> 🔄 **CI/CD (Gitea Actions → Kaniko → Harbor → Argo CD):** see **[RUNBOOK-CICD.fa.md](RUNBOOK-CICD.fa.md)** (Persian) and **[gitops/README.md](gitops/README.md)** for bootstrap (`seed-ci-images`, Sealed Secrets, two-repo GitOps layout).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|||||||
+73
-2
@@ -32,6 +32,55 @@ flowchart TD
|
|||||||
|
|
||||||
> **جلوگیری از حلقهٔ CI:** کامیتِ Pipeline به ریپوی جدا (`cloud-host-gitops`) میرود که هیچ Workflowای ندارد؛ بنابراین Build دوباره trigger نمیشود.
|
> **جلوگیری از حلقهٔ CI:** کامیتِ Pipeline به ریپوی جدا (`cloud-host-gitops`) میرود که هیچ Workflowای ندارد؛ بنابراین Build دوباره trigger نمیشود.
|
||||||
|
|
||||||
|
**زمان تقریبی یک Pipeline کامل:** ۱۵–۲۵ دقیقه (backend سنگینتر است؛ شامل دانلود npm، helm و kubectl داخل Dockerfile).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bootstrap — پیشنیازهای یکبار (کلاستر تازه)
|
||||||
|
|
||||||
|
قبل از اولین push به `main`، این موارد باید در کلاستر آماده باشند:
|
||||||
|
|
||||||
|
| # | کار | دستور / فایل |
|
||||||
|
|---|-----|--------------|
|
||||||
|
| 1 | Mirror k3s → Harbor | `./scripts/apply-k3s-registries.sh` |
|
||||||
|
| 2 | Secretهای TLS و registry در nsهای `gitea`, `cloudhost-builds`, `argocd` | [`gitops/README.md`](gitops/README.md) گام ۴ |
|
||||||
|
| 3 | پروکسی egress در `gitea` و `cloudhost-builds` | همان گام ۴ — برای npm/helm/kubectl داخل build و دانلود kubectl توسط Runner |
|
||||||
|
| 4 | **Seed ایمیجهای CI** در Harbor `abrban/` | [`gitops/jobs/seed-ci-images.yaml`](gitops/jobs/seed-ci-images.yaml) |
|
||||||
|
| 5 | Sealed Secrets controller | `helm upgrade --install sealed-secrets ... -f gitops/sealed-secrets/values.yaml` |
|
||||||
|
| 6 | SealedSecretها از ریپوی gitops | `kubectl apply -f` روی `cloud-host-gitops/sealed-secrets/` |
|
||||||
|
| 7 | Gitea Runner + Secret `CI_TOKEN` در ریپو | [`gitops/gitea/act-runner.yaml`](gitops/gitea/act-runner.yaml) |
|
||||||
|
| 8 | ریپوی `cloud-host-gitops` + Argo Application | [`gitops/argocd/application-platform.yaml`](gitops/argocd/application-platform.yaml) |
|
||||||
|
|
||||||
|
### Seed ایمیجهای CI (الزامی)
|
||||||
|
|
||||||
|
kubelet و Kaniko نمیتوانند reliably از proxy-cache هاربر برای همهٔ ایمیجها استفاده کنند. این ایمیجها باید **یکبار** با skopeo در پروژهٔ `abrban/` کپی شوند:
|
||||||
|
|
||||||
|
| ایمیج در Harbor | منبع upstream | مصرف |
|
||||||
|
|-----------------|---------------|------|
|
||||||
|
| `abrban/act-runner:0.2.11` | docker.io/gitea/act_runner | Gitea Actions runner |
|
||||||
|
| `abrban/alpine-git:2.43.0` | docker.io/alpine/git | initContainer کلون در Kaniko Job |
|
||||||
|
| `abrban/node:24-alpine` | docker.io/library/node | **BASE_IMAGE** در Dockerfile (هر stage) |
|
||||||
|
| `abrban/kaniko-executor:v1.27.6-debug` | gcr.io/kaniko-project/executor | Kaniko Job |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# پیشنیاز: secret registry-egress-proxy و registry-pull-secret در ns cloudhost
|
||||||
|
kubectl apply -f gitops/jobs/seed-ci-images.yaml
|
||||||
|
kubectl -n cloudhost wait --for=condition=complete job/seed-ci-images --timeout=15m
|
||||||
|
kubectl -n cloudhost logs job/seed-ci-images --tail=5
|
||||||
|
# انتظار: SEED_OK
|
||||||
|
```
|
||||||
|
|
||||||
|
بررسی:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n cloudhost run tags --rm -i --restart=Never \
|
||||||
|
--image=registry.abrban.com/abrban/alpine:3 \
|
||||||
|
--overrides='{"spec":{"imagePullSecrets":[{"name":"registry-pull-secret"}]}}' \
|
||||||
|
-- sh -c 'H="harbor_registry_user:$(kubectl -n cloudhost get secret harbor-core -o jsonpath="{.data.REGISTRY_CREDENTIAL_PASSWORD}" | base64 -d)@harbor-registry.cloudhost.svc.cluster.local:5000"; for r in act-runner kaniko-executor alpine-git node; do wget -qO- "http://${H}/v2/abrban/${r}/tags/list"; echo; done'
|
||||||
|
```
|
||||||
|
|
||||||
|
> بعد از bootstrap، Pipeline با push به `main` خودکار اجرا میشود؛ نیازی به `./scripts/trigger-platform-build.sh` برای جریان عادی نیست (فقط برای دیباگ دستی).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ساختار Repository (دو ریپو)
|
## ساختار Repository (دو ریپو)
|
||||||
@@ -105,7 +154,21 @@ kubectl -n cloudhost-builds create secret docker-registry kaniko-harbor-auth \
|
|||||||
|
|
||||||
نمونهٔ manifest: [`gitops/jobs/kaniko-harbor-auth.example.yaml`](gitops/jobs/kaniko-harbor-auth.example.yaml) — نسخهٔ واقعی بهصورت SealedSecret در ریپوی gitops است.
|
نمونهٔ manifest: [`gitops/jobs/kaniko-harbor-auth.example.yaml`](gitops/jobs/kaniko-harbor-auth.example.yaml) — نسخهٔ واقعی بهصورت SealedSecret در ریپوی gitops است.
|
||||||
|
|
||||||
ورکفلو این Secret را در مسیر `/kaniko/.docker/config.json` هر دو Kaniko Job مانت میکند. چون push داخلی و بدون TLS است، فلگهای `--insecure --skip-tls-verify` لازماند — این ترافیک از کلاستر خارج نمیشود.
|
ورکفلو این Secret را در مسیر `/kaniko/.docker/config.json` هر دو Kaniko Job مانت میکند. چون push/pull داخلی و بدون TLS است، این فلگها لازماند:
|
||||||
|
|
||||||
|
- `--insecure` / `--skip-tls-verify` — push
|
||||||
|
- `--insecure-pull` / `--insecure-registry=${PUSH_REGISTRY}` — pull ایمیج پایه از `harbor-registry:5000`
|
||||||
|
|
||||||
|
ایمیج پایه (`node:24-alpine`) از endpoint داخلی کشیده میشود، نه از `registry.abrban.com`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# در .gitea/workflows/build-deploy.yaml
|
||||||
|
--build-arg=BASE_IMAGE=harbor-registry.cloudhost.svc.cluster.local:5000/abrban/node:24-alpine
|
||||||
|
```
|
||||||
|
|
||||||
|
Dockerfileها از `ARG BASE_IMAGE=node:24-alpine` استفاده میکنند (build محلی بدون تغییر).
|
||||||
|
|
||||||
|
> **پروکسی egress** (`registry-egress-proxy` در ns `cloudhost-builds`) هنوز لازم است برای `npm ci` و دانلود helm/kubectl **داخل** مراحل RUN در Dockerfile — فقط pull ایمیج پایه از docker.io حذف شده است.
|
||||||
|
|
||||||
> **عارضهٔ جانبی push مستقیم به :5000** — Harbor DB از این ایمیجها بیخبر میماند؛ در UI هاربر دیده نمیشوند ولی pull بهدرستی کار میکند. برای دیدن تگها از registry API استفاده کنید (بخش عیبیابی).
|
> **عارضهٔ جانبی push مستقیم به :5000** — Harbor DB از این ایمیجها بیخبر میماند؛ در UI هاربر دیده نمیشوند ولی pull بهدرستی کار میکند. برای دیدن تگها از registry API استفاده کنید (بخش عیبیابی).
|
||||||
|
|
||||||
@@ -186,6 +249,9 @@ git push origin main
|
|||||||
| `gitea-act-runner-token` | `gitea` | توکن ثبت Runner |
|
| `gitea-act-runner-token` | `gitea` | توکن ثبت Runner |
|
||||||
| `kaniko-harbor-auth` | `cloudhost-builds` | dockerconfig کاربر `harbor_registry_user` |
|
| `kaniko-harbor-auth` | `cloudhost-builds` | dockerconfig کاربر `harbor_registry_user` |
|
||||||
| `gitea-gitops-repo-creds` | `argocd` | repo credential ریپوی gitops (کاربر `ci`) |
|
| `gitea-gitops-repo-creds` | `argocd` | repo credential ریپوی gitops (کاربر `ci`) |
|
||||||
|
| `abrban-platform-secrets` | `cloudhost` | postgres-password، jwt-secret، jwt-refresh-secret، **cluster-kubeconfig-key** |
|
||||||
|
|
||||||
|
چارت Helm با `secrets.existingSecret: abrban-platform-secrets` در `platform/values-abrban.yaml` (ریپوی gitops) از Secret ازپیشساخته استفاده میکند — Argo CD با `helm template` نمیتواند Secret تصادفی بسازد (lookup خالی است و هر sync مقادیر JWT را عوض میکند).
|
||||||
|
|
||||||
### ساخت/بهروزرسانی یک SealedSecret
|
### ساخت/بهروزرسانی یک SealedSecret
|
||||||
|
|
||||||
@@ -228,10 +294,15 @@ Secretهایی که هنوز دستیاند (خارج از چرخهٔ CI): `a
|
|||||||
|-------|-------|
|
|-------|-------|
|
||||||
| Workflow اجرا نمیشود | `kubectl -n gitea logs deploy/gitea-act-runner` — ثبت Runner و لیبل `abrban-builder` |
|
| Workflow اجرا نمیشود | `kubectl -n gitea logs deploy/gitea-act-runner` — ثبت Runner و لیبل `abrban-builder` |
|
||||||
| Build fail — clone | معتبربودن Secret `CI_TOKEN` در تنظیمات ریپوی `cloud-host` |
|
| Build fail — clone | معتبربودن Secret `CI_TOKEN` در تنظیمات ریپوی `cloud-host` |
|
||||||
| Build fail — pull ایمیج پایه (403/timeout از docker.io) | Kaniko نباید مستقیم از docker.io بکشد؛ ایمیج `node:24-alpine` باید در Harbor پروژهٔ `abrban/` seed شده باشد (`gitops/jobs/seed-ci-images.yaml`) و Workflow `--build-arg=BASE_IMAGE=registry.abrban.com/abrban/node:24-alpine` را پاس میدهد |
|
| Build fail — pull ایمیج پایه | `node:24-alpine` باید seed شده باشد؛ Workflow باید `BASE_IMAGE=harbor-registry.../abrban/node:24-alpine` + `--insecure-pull` داشته باشد؛ نه pull مستقیم از docker.io |
|
||||||
|
| Build fail — UNAUTHORIZED روی registry.abrban.com | BASE_IMAGE نباید `registry.abrban.com/...` باشد — credential کانیکو فقط برای `harbor-registry:5000` است |
|
||||||
|
| Build fail — HTTP response to HTTPS client | `--insecure-pull` و `--insecure-registry=harbor-registry.cloudhost.svc.cluster.local:5000` در Kaniko args |
|
||||||
|
| Build fail — timeout npm/helm/kubectl | `registry-egress-proxy` در ns `cloudhost-builds` و سلامت پروکسی egress |
|
||||||
| Build fail — push به Harbor | `kubectl -n cloudhost-builds get secret kaniko-harbor-auth`؛ پسورد باید با `REGISTRY_CREDENTIAL_PASSWORD` هاربر یکی باشد |
|
| Build fail — push به Harbor | `kubectl -n cloudhost-builds get secret kaniko-harbor-auth`؛ پسورد باید با `REGISTRY_CREDENTIAL_PASSWORD` هاربر یکی باشد |
|
||||||
| کامیت values push نمیشود | دسترسی write کاربر `ci` روی `cloud-host-gitops` |
|
| کامیت values push نمیشود | دسترسی write کاربر `ci` روی `cloud-host-gitops` |
|
||||||
| Argo sync نمیکند | `kubectl -n argocd get app abrban-platform`؛ هر دو repo credential (`gitea-repo-creds` و `gitea-gitops-repo-creds`) |
|
| Argo sync نمیکند | `kubectl -n argocd get app abrban-platform`؛ هر دو repo credential (`gitea-repo-creds` و `gitea-gitops-repo-creds`) |
|
||||||
| Pod ایمیج را pull نمیکند | `registry-pull-secret` در ns `cloudhost` و mirror k3s (`scripts/apply-k3s-registries.sh`) |
|
| Pod ایمیج را pull نمیکند | `registry-pull-secret` در ns `cloudhost` و mirror k3s (`scripts/apply-k3s-registries.sh`) |
|
||||||
| دیدن تگهای موجود در registry | از داخل کلاستر: `wget -qO- "http://harbor_registry_user:<REG_PASS>@harbor-registry.cloudhost.svc.cluster.local:5000/v2/abrban/cloudhost-backend/tags/list"` |
|
| دیدن تگهای موجود در registry | از داخل کلاستر: `wget -qO- "http://harbor_registry_user:<REG_PASS>@harbor-registry.cloudhost.svc.cluster.local:5000/v2/abrban/cloudhost-backend/tags/list"` |
|
||||||
|
| Backend CrashLoop — CLUSTER_KUBECONFIG_KEY | Secret `abrban-platform-secrets` باید کلید `cluster-kubeconfig-key` داشته باشد و در values: `secrets.existingSecret: abrban-platform-secrets` |
|
||||||
|
| Backend CrashLoop — DB auth | پسورد postgres در Secret با DB واقعی همخوان باشد (`ALTER USER ... WITH PASSWORD` در صورت rotate شدن Secret) |
|
||||||
| SealedSecret باز نمیشود | `kubectl get sealedsecrets -A` (ستون SYNCED) و لاگ `kubectl -n kube-system logs deploy/sealed-secrets-controller` |
|
| SealedSecret باز نمیشود | `kubectl get sealedsecrets -A` (ستون SYNCED) و لاگ `kubectl -n kube-system logs deploy/sealed-secrets-controller` |
|
||||||
|
|||||||
+17
-13
@@ -46,34 +46,38 @@ helm upgrade --install argocd argo/argo-cd -n argocd --create-namespace \
|
|||||||
helm upgrade --install gitea gitea-charts/gitea -n gitea --create-namespace \
|
helm upgrade --install gitea gitea-charts/gitea -n gitea --create-namespace \
|
||||||
-f gitops/gitea/values.yaml --timeout 15m --wait
|
-f gitops/gitea/values.yaml --timeout 15m --wait
|
||||||
|
|
||||||
# 4. TLS + registry secrets در namespaceهای argocd/gitea/cloudhost-builds
|
# 4. TLS + registry + egress secrets در namespaceهای argocd/gitea/cloudhost-builds
|
||||||
for ns in argocd gitea cloudhost-builds; do
|
for ns in argocd gitea cloudhost-builds; do
|
||||||
kubectl -n cloudhost get secret abrban-wildcard-tls -o yaml | sed "s/namespace: cloudhost/namespace: ${ns}/" | kubectl apply -f -
|
kubectl -n cloudhost get secret abrban-wildcard-tls -o yaml | sed "s/namespace: cloudhost/namespace: ${ns}/" | kubectl apply -f -
|
||||||
kubectl -n cloudhost get secret registry-pull-secret -o yaml | sed "s/namespace: cloudhost/namespace: ${ns}/" | kubectl apply -f -
|
kubectl -n cloudhost get secret registry-pull-secret -o yaml | sed "s/namespace: cloudhost/namespace: ${ns}/" | kubectl apply -f -
|
||||||
done
|
done
|
||||||
|
|
||||||
# پروکسی egress برای act-runner (دانلود kubectl) و Kaniko (pull ایمیج پایه از docker.io)
|
|
||||||
for ns in gitea cloudhost-builds; do
|
for ns in gitea cloudhost-builds; do
|
||||||
kubectl -n cloudhost get secret registry-egress-proxy -o yaml | sed "s/namespace: cloudhost/namespace: ${ns}/" | kubectl apply -f -
|
kubectl -n cloudhost get secret registry-egress-proxy -o yaml | sed "s/namespace: cloudhost/namespace: ${ns}/" | kubectl apply -f -
|
||||||
done
|
done
|
||||||
|
|
||||||
# 5. git push سورس به Gitea (نه docker push)
|
# 5. Seed ایمیجهای CI در Harbor abrban/ (یکبار — الزامی قبل از Pipeline)
|
||||||
|
kubectl apply -f gitops/jobs/seed-ci-images.yaml
|
||||||
|
kubectl -n cloudhost wait --for=condition=complete job/seed-ci-images --timeout=15m
|
||||||
|
|
||||||
|
# 6. Sealed Secrets controller
|
||||||
|
helm repo add sealed-secrets https://bitnami.github.io/sealed-secrets
|
||||||
|
helm upgrade --install sealed-secrets sealed-secrets/sealed-secrets \
|
||||||
|
-n kube-system -f gitops/sealed-secrets/values.yaml --timeout 10m --wait
|
||||||
|
|
||||||
|
# 7. git push سورس به Gitea
|
||||||
# git remote add gitea https://git.abrban.com/abrban/cloud-host.git
|
# git remote add gitea https://git.abrban.com/abrban/cloud-host.git
|
||||||
# git push gitea main
|
# git push gitea main
|
||||||
|
# ریپوی GitOps: https://git.abrban.com/abrban/cloud-host-gitops (SealedSecretها + values)
|
||||||
# 6. اولین build در کلاستر (Kaniko → abrban/)
|
|
||||||
./scripts/trigger-platform-build.sh
|
|
||||||
|
|
||||||
# 7. Deploy
|
|
||||||
./scripts/gitops-deploy.sh
|
|
||||||
|
|
||||||
# 8. Gitea Actions runner
|
# 8. Gitea Actions runner
|
||||||
# توکن ثبت: SealedSecret در ریپوی cloud-host-gitops (sealed-secrets/gitea-act-runner-token.yaml)
|
# توکن ثبت: SealedSecret در cloud-host-gitops/sealed-secrets/gitea-act-runner-token.yaml
|
||||||
# یا دستی: kubectl -n gitea create secret generic gitea-act-runner-token --from-literal=token='<TOKEN>'
|
|
||||||
kubectl apply -f gitops/gitea/act-runner.yaml
|
kubectl apply -f gitops/gitea/act-runner.yaml
|
||||||
|
|
||||||
# 9. Argo CD Application
|
# 9. Argo CD Application (multi-source: chart از cloud-host، values از cloud-host-gitops)
|
||||||
kubectl apply -f gitops/argocd/application-platform.yaml
|
kubectl apply -f gitops/argocd/application-platform.yaml
|
||||||
|
|
||||||
|
# 10. اولین deploy: push به main → Gitea Actions → Argo CD sync (جریان عادی)
|
||||||
|
# برای bootstrap دستی: TAG=... ./scripts/gitops-deploy.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## CI/CD
|
## CI/CD
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
# Bootstrap: copy act_runner + kaniko into abrban/ (kubelet cannot use proxy-cache reliably)
|
# Bootstrap: seed CI/build images into Harbor project abrban/
|
||||||
|
#
|
||||||
|
# kubelet and Kaniko cannot reliably use Harbor proxy-cache for all images.
|
||||||
|
# Run once after Harbor is up and registry-egress-proxy exists in cloudhost:
|
||||||
|
#
|
||||||
|
# kubectl apply -f gitops/jobs/seed-ci-images.yaml
|
||||||
|
# kubectl -n cloudhost wait --for=condition=complete job/seed-ci-images --timeout=15m
|
||||||
|
#
|
||||||
|
# Images copied (see RUNBOOK-CICD.fa.md):
|
||||||
|
# abrban/act-runner, abrban/alpine-git, abrban/node, abrban/kaniko-executor
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
metadata:
|
metadata:
|
||||||
@@ -25,6 +34,7 @@ spec:
|
|||||||
- |
|
- |
|
||||||
set -eux
|
set -eux
|
||||||
DEST="docker://harbor-registry.cloudhost.svc.cluster.local:5000/abrban"
|
DEST="docker://harbor-registry.cloudhost.svc.cluster.local:5000/abrban"
|
||||||
|
# Must match harbor-core → REGISTRY_CREDENTIAL_PASSWORD (default: harbor_registry_password)
|
||||||
CREDS="harbor_registry_user:harbor_registry_password"
|
CREDS="harbor_registry_user:harbor_registry_password"
|
||||||
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
skopeo copy --dest-tls-verify=false --dest-creds="${CREDS}" \
|
||||||
docker://docker.io/gitea/act_runner:0.2.11 \
|
docker://docker.io/gitea/act_runner:0.2.11 \
|
||||||
|
|||||||
Reference in New Issue
Block a user