gitdataai/deploy/README.md
2026-05-15 00:50:13 +08:00

6.8 KiB
Raw Blame History

Deploy Helm Chart

Monolithic Helm chart for all backend services.

Services

Service Port(s) Replicas HPA Purpose
app 3000 (HTTP) 2 210 Main API server
gitserver 8021 (HTTP), 2222 (SSH) 1 15 Git HTTP + SSH server
email_worker 8084 (HTTP) 1 disabled Email queue consumer (single instance only)
git_hook 8083 (HTTP) 1 15 Git hook worker pool
metrics_aggregator 9090 (HTTP) 1 15 Prometheus scrape + Loki push
static_server 8081 (HTTP) 1 15 Static file server (avatars, blobs, media)

Prerequisites

The following resources must exist in the cluster before installing the Helm chart. They are not managed by Helm — install, upgrade, and uninstall of the chart will not touch them.

1. Namespace

kubectl create namespace app

2. PVC (aliyun-nfs-app, 200Ti, ReadWriteMany)

kubectl apply -f - <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: shared-data
  namespace: app
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 200Ti
  storageClassName: aliyun-nfs-app
EOF

The chart references this PVC by hardcoded name shared-data. This name is immutable — it cannot be changed via Helm values.

3. ConfigMap

kubectl apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-env
  namespace: app
data:
  APP_REPOS_ROOT: "/data/repos"
  APP_AVATAR_PATH: "/data/avatars"
  STORAGE_PATH: "/data/files"
  STATIC_ROOT: "/data"
  APP_LOG_LEVEL: "info"
  APP_COOKIE_SECURE: "false"
  APP_DOMAIN_URL: "https://your-domain.com"
  APP_DATABASE_URL: "postgres://user:pass@postgres:5432/app"
  APP_REDIS_URL: "redis://redis:6379"
  APP_AI_BASIC_URL: "https://api.openai.com/v1"
  APP_AI_API_KEY: "sk-..."
  APP_SMTP_PASSWORD: "..."
  APP_SESSION_SECRET: "min-32-byte-random-string..."
  APP_SSH_SERVER_PRIVATE_KEY: "<hex-encoded-private-key>"
EOF
Variable Default / Example Required
APP_REPOS_ROOT /data/repos Yes
APP_AVATAR_PATH /data/avatars Yes
STORAGE_PATH /data/files Yes
STATIC_ROOT /data Yes
APP_LOG_LEVEL info No
APP_COOKIE_SECURE false No
APP_DOMAIN_URL https://your-domain.com Yes
APP_DATABASE_URL postgres://... Yes
APP_REDIS_URL redis://... Yes
APP_AI_BASIC_URL https://api.openai.com/v1 Yes
APP_AI_API_KEY sk-... Yes
APP_SMTP_PASSWORD ... Yes
APP_SESSION_SECRET min 32 bytes Yes
APP_SSH_SERVER_PRIVATE_KEY hex-encoded PEM Yes
APP_SSH_PORT 2222 Yes (k8s)

SSH host key: APP_SSH_SERVER_PRIVATE_KEY must be the hex-encoded Ed25519 private key PEM bytes.

ssh-keygen -t ed25519 -f /tmp/ssh_host_key -N ""
hexdump -v -e '/1 "%02x"' < /tmp/ssh_host_key

Session secret: generate 48 random bytes:

openssl rand -base64 48

Override the ConfigMap name with --set configMapName=your-cm-name.

4. Verify prerequisites

kubectl get namespace app
kubectl get pvc -n app shared-data
kubectl get configmap -n app app-env

Quick Start

helm template deploy ./deploy --namespace app --set imageRegistry=ghcr.io/your-org
helm lint ./deploy

# Install
helm upgrade --install deploy ./deploy \
  --namespace app \
  --set imageRegistry=ghcr.io/your-org \
  --set imageTag=v0.2.9

Storage

All services share a single PVC (shared-data) via subPath mounts:

SubPath Mount Used By
repos /data/repos app, gitserver, git-hook
avatars /data/avatars app
files /data/files app
static /data static-server

Pods run as UID/GID 1000 and set fsGroup: 1000 so Git processes can create temporary object directories under bare repositories. If an existing PVC was previously written by another UID, fix ownership once from a maintenance pod:

chown -R 1000:1000 /data/repos
chmod -R u+rwX,g+rwX /data/repos

Autoscaling

All services except email_worker have HPA enabled by default. The email worker is fixed at 1 replica and must not be scaled.

To adjust HPA bounds per service:

--set services.app.autoscaling.maxReplicas=20
--set services.app.autoscaling.targetCPUUtilization=70

To disable HPA for a service:

--set services.git_hook.autoscaling.enabled=false

Ingress

helm upgrade --install deploy ./deploy \
  --namespace app \
  --set ingress.enabled=true \
  --set ingress.className=nginx \
  --set ingress.hosts[0].host=your-domain.com

Dependencies

All services require these to be reachable from the cluster:

  • PostgreSQL (via APP_DATABASE_URL)
  • Redis (via APP_REDIS_URL)
  • Git binary (included in all Docker images)
  • OpenAI-compatible API (via APP_AI_BASIC_URL + APP_AI_API_KEY)
  • Qdrant vector DB (via APP_QDRANT_URL)
  • SMTP server (via APP_SMTP_*)
  • Embedding model (via APP_EMBED_MODEL_*)

Optional dependencies with graceful degradation:

Dependency Variable Fallback
NATS JetStream NATS_URL + NATS_TOKEN Redis queue
Loki LOKI_URL Logs discarded
OTEL Collector OTEL_EXPORTER_OTLP_ENDPOINT Tracing disabled

Production Example

helm upgrade --install deploy ./deploy \
  --namespace app \
  --set imageRegistry=ghcr.io/your-org \
  --set imageTag=v0.2.9 \
  --set services.app.replicas=3 \
  --set services.app.autoscaling.maxReplicas=20 \
  --set ingress.enabled=true \
  --set ingress.className=nginx \
  --set ingress.hosts[0].host=your-domain.com \
  --set configMapName=app-env