diff --git a/apps/gitea/README.md b/apps/gitea/README.md new file mode 100644 index 0000000..8e8b947 --- /dev/null +++ b/apps/gitea/README.md @@ -0,0 +1,85 @@ +# Gitea Configuration + +This Gitea deployment uses a hybrid configuration approach combining environment variables with Gitea's self-managed configuration file. + +## Configuration Architecture + +### Environment Variables (gitea.env) +Non-secret configuration is stored in `gitea.env` and automatically loaded via kustomize's `configMapGenerator`. This includes: +- Server settings (domain, URLs, ports) +- Database connection details (except password) +- SMTP settings (except password) +- Service settings (registration, notifications) +- Repository and storage paths + +### Kubernetes Secrets (gitea-secrets) +Sensitive configuration is stored in the `gitea-secrets` secret and managed by the wild-cloud deployment system: +- `adminPassword` - Gitea admin user password +- `secretKey` - Application secret key +- `jwtSecret` - JWT signing secret +- `dbPassword` - Database password +- `smtpPassword` - SMTP authentication password + +Secrets are defined in `secrets.yaml` and listed in `manifest.yaml` under `requiredSecrets`. The `wild-app-deploy` command automatically ensures all required secrets exist in the `gitea-secrets` secret before deployment. + +### Persistent Configuration (app.ini) +Gitea manages its own `app.ini` file on persistent storage for: +- Generated security tokens +- Runtime configuration changes made via web UI +- Database migration state +- User-modified settings + +## How It Works + +1. **Startup**: Kustomize generates a ConfigMap from `gitea.env` +2. **Environment Loading**: Pod loads non-secret config from ConfigMap via `envFrom` +3. **Secret Loading**: Pod loads sensitive config from Kubernetes secrets via `env` +4. **Configuration Merge**: Gitea's environment-to-ini process merges environment variables into `app.ini` +5. **Persistence**: Gitea writes the merged configuration plus generated tokens to persistent storage + +## Making Configuration Changes + +### Non-Secret Settings +1. Edit `gitea.env` with your changes +2. Run `wild-app-deploy gitea` to apply changes +3. Pod will restart and pick up new configuration + +### Secret Settings +1. Edit `secrets.yaml` with your secret values +2. Ensure the secret key is listed in `manifest.yaml` under `requiredSecrets` +3. Run `wild-app-deploy gitea` - this will automatically update the `gitea-secrets` secret and restart the pod + +### Web UI Changes +Configuration changes made through Gitea's admin web interface are automatically persisted to the `app.ini` file on persistent storage and will survive pod restarts. + +## Configuration Precedence + +1. **Kubernetes Secrets** (highest priority) +2. **Environment Variables** (from gitea.env) +3. **Persistent app.ini** (lowest priority) + +Environment variables override file settings, and secrets override everything. + +## Troubleshooting + +### Check Current Configuration +```bash +# View environment variables +kubectl describe pod -n gitea -l app=gitea | grep -A 20 "Environment" + +# View current app.ini +kubectl exec -it deployment/gitea -n gitea -- cat /data/gitea/conf/app.ini +``` + +### Configuration Not Applied +- Verify the ConfigMap was generated: `kubectl get configmap -n gitea` +- Check pod restart: `kubectl get pods -n gitea` +- Review startup logs: `kubectl logs -n gitea -l app=gitea` + + +## External Dependencies + +- **Database**: PostgreSQL instance in `postgres` namespace +- **Storage**: Longhorn distributed storage +- **Ingress**: Traefik with Let's Encrypt certificates +- **DNS**: External-DNS with Cloudflare integration \ No newline at end of file diff --git a/apps/gitea/configmap.yaml b/apps/gitea/configmap.yaml deleted file mode 100644 index 11b40ab..0000000 --- a/apps/gitea/configmap.yaml +++ /dev/null @@ -1,58 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: gitea-config - namespace: gitea -data: - app.ini: | - APP_NAME = {{ .apps.gitea.appName }} - RUN_MODE = {{ .apps.gitea.runMode }} - RUN_USER = git - - [security] - INSTALL_LOCK = true - - [database] - DB_TYPE = postgres - HOST = {{ .apps.gitea.dbHost }}:{{ .apps.gitea.dbPort }} - NAME = {{ .apps.gitea.dbName }} - USER = {{ .apps.gitea.dbUser }} - SSL_MODE = disable - - [server] - DOMAIN = {{ .apps.gitea.domain }} - HTTP_PORT = {{ .apps.gitea.port }} - ROOT_URL = https://{{ .apps.gitea.domain }}/ - DISABLE_SSH = false - SSH_DOMAIN = {{ .apps.gitea.domain }} - SSH_PORT = {{ .apps.gitea.sshPort }} - SSH_LISTEN_PORT = 2222 - LFS_START_SERVER = true - - [service] - DISABLE_REGISTRATION = false - ALLOW_ONLY_EXTERNAL_REGISTRATION = false - ENABLE_NOTIFY_MAIL = false - ENABLE_BASIC_AUTHENTICATION = false - ENABLE_REVERSE_PROXY_AUTHENTICATION = false - ENABLE_CAPTCHA = false - REQUIRE_SIGNIN_VIEW = false - DEFAULT_KEEP_EMAIL_PRIVATE = false - DEFAULT_ALLOW_CREATE_ORGANIZATION = true - DEFAULT_ENABLE_TIMETRACKING = true - NO_REPLY_ADDRESS = noreply.{{ .cloud.domain }} - - [webhook] - ALLOWED_HOST_LIST = * - - [mailer] - ENABLED = false - - [picture] - DISABLE_GRAVATAR = false - ENABLE_FEDERATED_AVATAR = true - - [log] - MODE = console - LEVEL = info - ROOT_PATH = /data/gitea/log \ No newline at end of file diff --git a/apps/gitea/deployment.yaml b/apps/gitea/deployment.yaml index 18fe971..991b312 100644 --- a/apps/gitea/deployment.yaml +++ b/apps/gitea/deployment.yaml @@ -6,10 +6,7 @@ metadata: spec: replicas: 1 strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 0 - maxSurge: 100% + type: Recreate selector: matchLabels: component: web @@ -18,7 +15,7 @@ spec: labels: app: gitea component: web - managedBy: wild-cloud + managedBy: kustomize partOf: wild-cloud spec: securityContext: @@ -28,32 +25,15 @@ spec: - name: gitea image: "{{ .apps.gitea.image }}" imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: gitea-env env: - - name: SSH_LISTEN_PORT - value: "2222" - - name: SSH_PORT - value: "{{ .apps.gitea.sshPort }}" - - name: GITEA_APP_INI - value: /data/gitea/conf/app.ini - - name: GITEA_CUSTOM - value: /data/gitea - - name: GITEA_WORK_DIR - value: /data - - name: GITEA_TEMP - value: /tmp/gitea - - name: TMPDIR - value: /tmp/gitea - - name: HOME - value: /data/gitea/git - - name: GITEA_ADMIN_USERNAME - value: "admin" - name: GITEA_ADMIN_PASSWORD valueFrom: secretKeyRef: name: gitea-secrets key: adminPassword - - name: GITEA_ADMIN_PASSWORD_MODE - value: keepUpdated - name: GITEA__security__SECRET_KEY valueFrom: secretKeyRef: @@ -69,11 +49,16 @@ spec: secretKeyRef: name: gitea-secrets key: dbPassword + - name: GITEA__mailer__PASSWD + valueFrom: + secretKeyRef: + name: gitea-secrets + key: smtpPassword ports: - name: ssh containerPort: 2222 - name: http - containerPort: {{ .apps.gitea.port }} + containerPort: 3000 livenessProbe: failureThreshold: 10 initialDelaySeconds: 200 diff --git a/apps/gitea/gitea.env b/apps/gitea/gitea.env new file mode 100644 index 0000000..b59430c --- /dev/null +++ b/apps/gitea/gitea.env @@ -0,0 +1,64 @@ +SSH_LISTEN_PORT=2222 +SSH_PORT=22 +GITEA_APP_INI=/data/gitea/conf/app.ini +GITEA_CUSTOM=/data/gitea +GITEA_WORK_DIR=/data +GITEA_TEMP=/tmp/gitea +TMPDIR=/tmp/gitea +HOME=/data/gitea/git +GITEA_ADMIN_USERNAME={{ .apps.gitea.adminUser }} +GITEA_ADMIN_PASSWORD_MODE=keepUpdated + +# Core app settings +APP_NAME={{ .apps.gitea.appName }} +RUN_MODE={{ .apps.gitea.runMode }} +RUN_USER=git +WORK_PATH=/data + +# Security settings +GITEA__security__INSTALL_LOCK=true +GITEA__security__PASSWORD_HASH_ALGO=pbkdf2 + +# Database settings (except password which comes from secret) +GITEA__database__DB_TYPE=postgres +GITEA__database__HOST={{ .apps.gitea.dbHost }}:{{ .apps.gitea.dbPort }} +GITEA__database__NAME={{ .apps.gitea.dbName }} +GITEA__database__USER={{ .apps.gitea.dbUser }} +GITEA__database__SSL_MODE=disable +GITEA__database__LOG_SQL=false + +# Server settings +GITEA__server__DOMAIN={{ .apps.gitea.domain }} +GITEA__server__HTTP_PORT={{ .apps.gitea.port }} +GITEA__server__ROOT_URL=https://{{ .apps.gitea.domain }}/ +GITEA__server__DISABLE_SSH=false +GITEA__server__SSH_DOMAIN={{ .apps.gitea.domain }} +GITEA__server__SSH_PORT={{ .apps.gitea.sshPort }} +GITEA__server__SSH_LISTEN_PORT=2222 +GITEA__server__LFS_START_SERVER=true +GITEA__server__OFFLINE_MODE=true + +# Service settings +GITEA__service__REGISTER_EMAIL_CONFIRM=true +GITEA__service__DISABLE_REGISTRATION=false +GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION=false +GITEA__service__ENABLE_NOTIFY_MAIL=true +GITEA__service__ENABLE_BASIC_AUTHENTICATION=false +GITEA__service__ENABLE_REVERSE_PROXY_AUTHENTICATION=false +GITEA__service__ENABLE_CAPTCHA=false +GITEA__service__REQUIRE_SIGNIN_VIEW=false +GITEA__service__DEFAULT_KEEP_EMAIL_PRIVATE=false +GITEA__service__DEFAULT_ALLOW_CREATE_ORGANIZATION=true +GITEA__service__DEFAULT_ENABLE_TIMETRACKING=true +GITEA__service__NO_REPLY_ADDRESS=noreply.localhost + +# Webhook settings +GITEA__webhook__ALLOWED_HOST_LIST=* + +# Mailer settings (enabled via env vars, password from secret) +GITEA__mailer__ENABLED=true +GITEA__mailer__SMTP_ADDR={{ .apps.gitea.smtp.host }} +GITEA__mailer__SMTP_PORT={{ .apps.gitea.smtp.port }} +GITEA__mailer__FROM={{ .apps.gitea.smtp.from }} +GITEA__mailer__USER={{ .apps.gitea.smtp.user }} + diff --git a/apps/gitea/ingress.yaml b/apps/gitea/ingress.yaml index 346ca5c..060ca60 100644 --- a/apps/gitea/ingress.yaml +++ b/apps/gitea/ingress.yaml @@ -4,8 +4,9 @@ metadata: name: gitea-public namespace: gitea annotations: - external-dns.alpha.kubernetes.io/target: "{{ .apps.gitea.domain }}" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" + external-dns.alpha.kubernetes.io/target: "{{ .apps.gitea.domain }}" + external-dns.alpha.kubernetes.io/target: "{{ .cluster.externalDns.target}}" spec: rules: - host: "{{ .apps.gitea.domain }}" @@ -19,6 +20,6 @@ spec: port: number: 3000 tls: - - secretName: wildcard-wild-cloud-tls + - secretName: "{{ .apps.gitea.tlsSecretName }}" hosts: - - "{{ .apps.gitea.domain }}" \ No newline at end of file + - "{{ .apps.gitea.domain }}" diff --git a/apps/gitea/kustomization.yaml b/apps/gitea/kustomization.yaml index 6cde147..225bd78 100644 --- a/apps/gitea/kustomization.yaml +++ b/apps/gitea/kustomization.yaml @@ -13,5 +13,8 @@ resources: - service.yaml - ingress.yaml - pvc.yaml - - configmap.yaml - - db-init-job.yaml \ No newline at end of file + - db-init-job.yaml +configMapGenerator: + - name: gitea-env + envs: + - gitea.env diff --git a/apps/gitea/manifest.yaml b/apps/gitea/manifest.yaml index 3229c2e..ac5b58a 100644 --- a/apps/gitea/manifest.yaml +++ b/apps/gitea/manifest.yaml @@ -1,26 +1,33 @@ name: gitea description: Gitea is a painless self-hosted Git service written in Go -version: 1.0.0 +version: 1.24.3 icon: https://github.com/go-gitea/gitea/raw/main/assets/logo.png requires: - name: postgres defaultConfig: - image: gitea/gitea:1.22.0 + image: gitea/gitea:1.24.3 + appName: Gitea domain: gitea.{{ .cloud.domain }} + tlsSecretName: wildcard-wild-cloud-tls port: 3000 sshPort: 22 storage: 10Gi dbName: gitea dbUser: gitea dbHost: postgres.postgres.svc.cluster.local + adminUser: admin + adminEmail: "admin@{{ .cloud.domain }}" dbPort: 5432 timezone: UTC - adminUser: admin - adminEmail: admin@{{ .cloud.domain }} - appName: Gitea runMode: prod + smtp: + host: TBD + port: 465 + from: no-reply@{{ .cloud.domain }} + user: TBD requiredSecrets: - apps.gitea.adminPassword - apps.gitea.dbPassword - apps.gitea.secretKey - - apps.gitea.jwtSecret \ No newline at end of file + - apps.gitea.jwtSecret + - apps.gitea.smtpPassword