docs: add portable from-zero deploy runbook and GitOps templates

Document server-side rollout (values, Sealed Secrets, logging, greenfield
reset) with environment variables so any cluster can follow the same steps.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
keyhan
2026-07-03 12:17:55 +03:30
parent 22359be40e
commit 6d9cd89cc5
9 changed files with 668 additions and 13 deletions
+7 -4
View File
@@ -1,5 +1,7 @@
# GitOps stack for abrban.com
> **راهنمای استقرار از صفر (هر محیط):** [`RUNBOOK-DEPLOY.fa.md`](../RUNBOOK-DEPLOY.fa.md) — متغیرها، values، Sealed Secrets، logging، deploy، greenfield reset.
## DNS (A record → cluster IP `78.157.39.52`)
| Host | Purpose |
@@ -84,8 +86,9 @@ kubectl apply -f gitops/argocd/application-platform.yaml
Gitea Actions: [.gitea/workflows/build-deploy.yaml](../.gitea/workflows/build-deploy.yaml)
Push به `main` → Kaniko → push به `abrban/` → کامیت tag در ریپوی [cloud-host-gitops](https://git.abrban.com/abrban/cloud-host-gitops) → ArgoCD sync.
Push به `main` **تست Jest** Kaniko → push به `abrban/` → کامیت tag در ریپوی [cloud-host-gitops](https://git.abrban.com/abrban/cloud-host-gitops) → ArgoCD sync.
- مقادیر Production در ریپوی جدا `abrban/cloud-host-gitops` است (`platform/values-abrban.yaml`)؛ Application به‌صورت multi-source تعریف شده.
- Secretهای CI به‌صورت SealedSecret در همان ریپو هستند (کنترلر در `kube-system`، values در `gitops/sealed-secrets/values.yaml`).
- مستند کامل: [RUNBOOK-CICD.fa.md](../RUNBOOK-CICD.fa.md)
- **استقرار اولیه از صفر:** [`RUNBOOK-DEPLOY.fa.md`](../RUNBOOK-DEPLOY.fa.md) (فاز ۲–۷)
- مقادیر Production: [`platform/values-abrban.example.yaml`](platform/values-abrban.example.yaml) → کپی به gitops و ویرایش
- SealedSecretهای نمونه: [`sealed-secrets/abrban-platform-secrets.example.yaml`](sealed-secrets/abrban-platform-secrets.example.yaml)، [`sealed-secrets/elasticsearch-credentials.example.yaml`](sealed-secrets/elasticsearch-credentials.example.yaml)
- Pipeline و rollback: [RUNBOOK-CICD.fa.md](../RUNBOOK-CICD.fa.md)
+148
View File
@@ -0,0 +1,148 @@
# Production values template — copy and customize for YOUR environment.
#
# Full step-by-step (from zero, any cluster):
# See RUNBOOK-DEPLOY.fa.md — Phase 2 (values) and Phase 3 (secrets)
#
# Example for abrban.com:
# cp values-abrban.example.yaml ../cloud-host-gitops/platform/values-abrban.yaml
#
# CI only updates images.backend.tag and images.frontend.tag on each deploy.
namespace: cloudhost
createNamespace: false
global:
storageClass: local-path
images:
# Harbor proxy-cache — first pull is slow, no manual seed needed (see gitops/README.md)
postgres: registry.abrban.com/proxy-dockerhub/library/postgres:16-alpine
redis: registry.abrban.com/proxy-dockerhub/library/redis:7-alpine
busybox: registry.abrban.com/proxy-dockerhub/library/busybox:1.36
backend:
repository: registry.abrban.com/abrban/cloudhost-backend
tag: "1.0.0" # ← CI overwrites on each deploy
pullPolicy: IfNotPresent
frontend:
repository: registry.abrban.com/abrban/cloudhost-frontend
tag: "1.0.0" # ← CI overwrites on each deploy
pullPolicy: IfNotPresent
postgres:
enabled: true
database: cloudhost
username: cloudhost
password: "" # managed in abrban-platform-secrets (postgres-password)
storage: 10Gi
imagePullSecrets:
- name: registry-pull-secret
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
redis:
enabled: true
storage: 1Gi
password: "" # managed in abrban-platform-secrets (redis-password)
imagePullSecrets:
- name: registry-pull-secret
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 512Mi
# GitOps: never let Helm generate random JWT/redis passwords on each sync.
# Create once with kubeseal — see gitops/sealed-secrets/abrban-platform-secrets.example.yaml
secrets:
existingSecret: abrban-platform-secrets
backend:
enabled: true
replicas: 1
imagePullSecrets:
- name: registry-pull-secret
uploads:
size: 20Gi
sourceStorage:
enabled: false
existingSecret: ceph-app-sources-credentials
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
env:
NODE_ENV: production
PORT: "4000"
JWT_EXPIRES_IN: 15m
JWT_REFRESH_EXPIRES_IN: 7d
PLATFORM_DOMAIN: apps.abrban.com
PREVIEW_BASE_DOMAIN: apps.abrban.com
FRONTEND_URL: https://panel.abrban.com,https://abrban.com
REGISTRY_URL: harbor-registry.cloudhost.svc.cluster.local:5000/abrban
REGISTRY_PULL_URL: registry.abrban.com/abrban
BUILD_NAMESPACE: cloudhost-builds
BUILD_SERVICE_ACCOUNT: kaniko-builder
UPLOAD_DIR: /app/uploads
PLATFORM_CREATE_STORAGE_CLASS: "true"
PLATFORM_STORAGE_CLASS: cloudhost-expandable
PLATFORM_STORAGE_PROVISIONER: rancher.io/local-path
ELASTICSEARCH_HOST: elasticsearch.logging.svc.cluster.local
ELASTICSEARCH_AUTO_PORT_FORWARD: "false"
# Mirror prefix for user-app Dockerfiles and managed DB/Redis/RabbitMQ charts
BASE_IMAGE_REGISTRY: registry.abrban.com/proxy-dockerhub/library
# Must match elasticsearch-credentials Secret in logging namespace (not in Helm chart)
ELASTIC_PASSWORD: "CHANGE_VIA_SEALEDSECRET_OR_KUBECTL"
FLUENTBIT_PASSWORD: "CHANGE_VIA_SEALEDSECRET_OR_KUBECTL"
KIBANA_SYSTEM_PASSWORD: "CHANGE_VIA_SEALEDSECRET_OR_KUBECTL"
# Swagger disabled in production unless explicitly enabled
# SWAGGER_ENABLED: "true"
frontend:
enabled: true
replicas: 1
imagePullSecrets:
- name: registry-pull-secret
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
ingress:
enabled: true
className: traefik
frontend:
host: abrban.com
panel:
host: panel.abrban.com
api:
host: api.abrban.com
tls:
enabled: true
clusterIssuer: letsencrypt-prod
migrations:
enabled: true
image: registry.abrban.com/proxy-dockerhub/library/postgres:16-alpine
backups:
postgres:
enabled: true
schedule: "0 3 * * *"
storageSize: 10Gi
retentionDays: 7
monitoring:
enabled: false
@@ -0,0 +1,30 @@
# Example: seal platform secrets for namespace cloudhost.
# Full guide (any environment): RUNBOOK-DEPLOY.fa.md — Phase 3
# Real SealedSecret lives in cloud-host-gitops/sealed-secrets/ — never commit plaintext passwords.
#
# Required keys (must match backend Deployment + validate-production-config):
# postgres-password, jwt-secret, jwt-refresh-secret, cluster-kubeconfig-key, redis-password
#
# Generate (replace CHANGE_ME_* with strong random values):
#
# kubectl -n cloudhost create secret generic abrban-platform-secrets \
# --from-literal=postgres-password='CHANGE_ME_PG' \
# --from-literal=jwt-secret='CHANGE_ME_JWT_32CHARS_MIN' \
# --from-literal=jwt-refresh-secret='CHANGE_ME_REFRESH_32CHARS_MIN' \
# --from-literal=cluster-kubeconfig-key='0123456789abcdef0123456789abcdef' \
# --from-literal=redis-password='CHANGE_ME_REDIS' \
# --dry-run=client -o json \
# | kubeseal \
# --controller-name=sealed-secrets-controller \
# --controller-namespace=kube-system \
# --format yaml \
# > ../cloud-host-gitops/sealed-secrets/abrban-platform-secrets.yaml
#
# Then in platform/values-abrban.yaml:
# secrets:
# existingSecret: abrban-platform-secrets
#
# Apply:
# kubectl apply -f ../cloud-host-gitops/sealed-secrets/abrban-platform-secrets.yaml
#
# Rotate redis-password: update SealedSecret, sync Argo, restart backend + redis pods.
@@ -0,0 +1,20 @@
# Example: seal Elasticsearch stack credentials (namespace logging).
# Full guide (any environment): RUNBOOK-DEPLOY.fa.md — Phase 4
# Apply elasticsearch-stack.yaml FIRST (without inline passwords), then create this Secret.
#
# kubectl -n logging create secret generic elasticsearch-credentials \
# --from-literal=ELASTIC_PASSWORD="$(openssl rand -base64 24)" \
# --from-literal=FLUENTBIT_PASSWORD="$(openssl rand -base64 24)" \
# --dry-run=client -o json \
# | kubeseal \
# --controller-name=sealed-secrets-controller \
# --controller-namespace=kube-system \
# --format yaml \
# > ../cloud-host-gitops/sealed-secrets/elasticsearch-credentials.yaml
#
# Backend must receive the same ELASTIC_* values via backend.env in values-abrban.yaml
# (or a separate SealedSecret referenced with envFrom).
#
# After deploy, verify:
# kubectl -n logging get secret elasticsearch-credentials
# curl -u elastic:$ELASTIC_PASSWORD https://elasticsearch.logging.svc.cluster.local:9200