From d1304a263050b716fc157386bee6b6e6738d4eb3 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Wed, 31 Dec 2025 06:53:17 +0000 Subject: [PATCH] v2 app deployment--templating mainly in manifest now. --- ADDING-APPS.md | 143 ++++++++++---- discourse/configmap.yaml | 31 --- discourse/db-init-job.yaml | 10 +- discourse/deployment.yaml | 239 ++++++++---------------- discourse/ingress.yaml | 8 +- discourse/kustomization.yaml | 1 - discourse/manifest.yaml | 36 ++-- discourse/namespace.yaml | 2 +- discourse/pvc.yaml | 36 +++- example-admin/deployment.yaml | 1 - example-admin/ingress.yaml | 5 +- example-admin/manifest.yaml | 3 + example-admin/namespace.yaml | 2 +- example-app/ingress.yaml | 6 +- example-app/manifest.yaml | 3 + example-app/namespace.yaml | 2 +- ghost/db-init-job.yaml | 14 +- ghost/deployment.yaml | 38 ++-- ghost/ingress.yaml | 8 +- ghost/manifest.yaml | 30 +-- ghost/namespace.yaml | 2 +- ghost/pvc.yaml | 2 +- ghost/service.yaml | 2 +- gitea/db-init-job.yaml | 12 +- gitea/deployment.yaml | 12 +- gitea/gitea.env | 30 +-- gitea/ingress.yaml | 8 +- gitea/manifest.yaml | 28 +-- gitea/namespace.yaml | 2 +- gitea/pvc.yaml | 2 +- gitea/service.yaml | 4 +- immich/db-init-job.yaml | 12 +- immich/deployment-machine-learning.yaml | 6 +- immich/deployment-microservices.yaml | 14 +- immich/deployment-server.yaml | 16 +- immich/ingress.yaml | 6 +- immich/manifest.yaml | 20 +- immich/namespace.yaml | 2 +- immich/pvc.yaml | 4 +- immich/service.yaml | 4 +- keila/db-init-job.yaml | 10 +- keila/deployment.yaml | 36 ++-- keila/ingress.yaml | 6 +- keila/manifest.yaml | 30 +-- keila/middleware-cors.yaml | 4 +- keila/namespace.yaml | 2 +- keila/pvc.yaml | 2 +- keila/service.yaml | 2 +- listmonk/db-init-job.yaml | 10 +- listmonk/deployment.yaml | 14 +- listmonk/ingress.yaml | 8 +- listmonk/manifest.yaml | 16 +- listmonk/namespace.yaml | 2 +- listmonk/pvc.yaml | 2 +- loomio/manifest.yaml | 16 +- memcached/deployment.yaml | 20 +- memcached/manifest.yaml | 8 +- memcached/namespace.yaml | 2 +- memcached/service.yaml | 4 +- mysql/manifest.yaml | 6 +- mysql/namespace.yaml | 2 +- mysql/service-headless.yaml | 2 +- mysql/service.yaml | 2 +- mysql/statefulset.yaml | 16 +- open-webui/deployment.yaml | 2 +- open-webui/ingress.yaml | 6 +- open-webui/manifest.yaml | 13 +- open-webui/namespace.yaml | 2 +- openproject/configmap_core.yaml | 24 +-- openproject/configmap_memcached.yaml | 2 +- openproject/db-init-job.yaml | 12 +- openproject/ingress.yaml | 4 +- openproject/manifest.yaml | 22 ++- openproject/namespace.yaml | 2 +- openproject/persistentvolumeclaim.yaml | 2 +- openproject/seeder-job.yaml | 16 +- openproject/web-deployment.yaml | 25 +-- openproject/worker-deployment.yaml | 22 ++- redis/manifest.yaml | 2 +- vllm/deployment.yaml | 24 +-- vllm/ingress.yaml | 6 +- vllm/kustomization.yaml | 2 +- vllm/manifest.yaml | 19 +- vllm/namespace.yaml | 2 +- 84 files changed, 630 insertions(+), 607 deletions(-) delete mode 100644 discourse/configmap.yaml diff --git a/ADDING-APPS.md b/ADDING-APPS.md index 4ce041c..24f30f6 100644 --- a/ADDING-APPS.md +++ b/ADDING-APPS.md @@ -26,8 +26,9 @@ description: Immich is a self-hosted photo and video backup solution that allows version: 1.0.0 icon: https://immich.app/assets/images/logo.png requires: - - name: redis - - name: postgres + - name: pg + alias: db # Use a different reference name in templates + - name: redis # 'alias' and 'installedAs' default to 'name' value defaultConfig: serverImage: ghcr.io/immich-app/immich-server:release mlImage: ghcr.io/immich-app/immich-machine-learning:release @@ -36,13 +37,21 @@ defaultConfig: mlPort: 3003 storage: 250Gi cacheStorage: 10Gi - redisHostname: redis.redis.svc.cluster.local - dbHostname: postgres.postgres.svc.cluster.local - dbUsername: immich + redisHostname: "{{ .apps.redis.host }}" # Can reference 'requires' app configurations + dbHostname: "{{ .apps.pg.host }}" + db: # Configuration can be nested + name: immich + user: immich + host: "{{ .apps.pg.host }}" + port: "{{ .apps.pg.port }}" domain: immich.{{ .cloud.domain }} defaultSecrets: - - apps.immich.dbPassword - - apps.postgres.password + - key: password # Random value will be generated if empty + - key: dbUrl + default: "postgresql://{{ .app.db.user }}:{{ .secrets.dbPassword }}@{{ .app.db.host }}:{{ .app.db.port }}/{{ .app.db.name }}?pool=30" # Can reference secrets and config as long as they have been defined before this line. Reference config with {{ .app.? }} and secrets with {{ .secrets.? }} +requiredSecrets: + - db.password # References postgres app via 'db' alias + - redis.auth # References redis app via 'redis' name (no alias) ``` #### Manifest Fields @@ -53,11 +62,31 @@ defaultSecrets: | `description` | Yes | Brief app description shown in listings | | `version` | Yes | App version (follow upstream versioning) | | `icon` | No | URL to app icon for UI display | -| `requires` | No | List of dependency apps (e.g., `postgres`, `redis`) | +| `requires` | No | List of dependency apps with optional aliases | | `defaultConfig` | Yes | Default configuration values merged into operator's `config.yaml` | -| `defaultSecrets` | No | List of secrets in dotted-path format (e.g., `apps.appname.dbPassword`) | +| `defaultSecrets` | No | This app's secrets (no 'default' = auto-generated) | +| `requiredSecrets` | No | List of secrets from dependency apps (format: `.`) | -**Important:** All configuration keys referenced in templates (via `{{ .apps.appname.key }}`) must be defined in `defaultConfig` or be standard Wild Cloud variables. +**Dependency Configuration:** +- Each dependency in `requires` can have: + - `name`: The actual app name to depend on + - `alias`: Optional reference name for templates (defaults to `name`) + +**Manifest Template Variable Sources:** +1. Standard Wild Cloud variables: `{{ .cloud.* }}`, `{{ .cluster.* }}`, `{{ .operator.* }}` +2. App-specific variables: `{{ .app.* }}` - resolved from current app's config +3. Dependency variables: `{{ .apps..* }}` - resolved using app reference mapping +4. App-specific secrets (in 'defaultSecrets' ONLY): `{{ secrets.* }}` + +**Manifest App Reference Resolution:** +When you use `{{ .apps..* }}` in templates: +1. System checks if `` matches any dependency's `alias` field +2. If no alias match, checks if `` matches any dependency's `name` field +3. Uses the `installedAs` value (automatically added when the app is added) to find actual app configuration in `config.yaml` + +All manifest template variables must be defined in one of these locations. + +**Important:** In the rest of the app templates, ALL configuration keys referenced in templates (via `{{ .key }}`) must be defined in `defaultConfig`. Only the app config is available to app templates. ### Kustomization (`kustomization.yaml`) @@ -111,21 +140,7 @@ This means individual resources can use simple, component-specific selectors lik ### Gomplate Templating -Resource files in this repository are **templates** that get compiled when users add apps via the web app, CLI, or API. Use gomplate syntax to reference configuration: - -```yaml -# Common template variables -domain: {{ .cloud.domain }} # Operator's domain -email: {{ .operator.email }} # Operator's email -image: {{ .apps.myapp.serverImage }} # App-specific config -dbHost: {{ .apps.myapp.dbHostname }} # App-specific config -``` - -**Template variable sources:** -1. Standard Wild Cloud variables (`{{ .cloud.* }}`, `{{ .operator.* }}`) -2. App-specific variables defined in your manifest's `defaultConfig` - -All template variables must be defined in one of these locations. The compiled files are placed in the instance's directory as standard Kubernetes manifests. +Resource files in this repository are **templates** that get compiled when users add apps via the web app, CLI, or API. Only variables defined in the manifest file's 'defaultConfig' section are available to the resource templates. Use gomplate syntax to reference configuration: ### External DNS @@ -133,12 +148,47 @@ Ingress resources should include external-dns annotations for automatic DNS mana ```yaml annotations: - external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/target: {{ .domain }} external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" ``` +Note: 'domain' must be defined in the app manifest's 'defaultConfig' section. + This creates a CNAME from the app subdomain to the cluster domain (e.g., `myapp.cloud.example.com` → `cloud.example.com`). +## App Dependencies and Reference Mapping + +### How Dependency References Work + +When an app depends on other apps, the reference system allows flexibility in naming while maintaining clear relationships: + +1. **Define dependencies** in your manifest with optional aliases: +```yaml +requires: + - name: postgres # Actual app to depend on + alias: db # Optional: how to reference it in templates + - name: redis # No alias means use 'redis' as reference +``` + +2. **At installation time**, the system: + - Prompts user to map dependencies to actual installed apps + - Sets `installedAs` field in the local app manifest to track the mapping + - Example: User might have `postgres-primary` installed, mapped to the `db` dependency + +### Example: Multiple Database Instances + +If a user has multiple PostgreSQL instances: +```yaml +# User's config.yaml +apps: + postgres-primary: + hostname: primary.postgres.svc.cluster.local + postgres-analytics: + hostname: analytics.postgres.svc.cluster.local +``` + +When adding an app that requires postgres, they can choose which instance to use, and the system tracks this in the manifest's `installedAs` field. + ## Database Patterns ### Database Initialization Jobs @@ -211,13 +261,16 @@ spec: ### Secrets Management -Secrets use a **full dotted-path naming convention** to prevent naming conflicts: +Secrets are managed through two mechanisms: default secrets for the app itself and required secrets from dependencies. **In manifest:** ```yaml defaultSecrets: - - apps.myapp.dbPassword - - apps.postgres.password + key: dbPassword # This app's database password + key: apiKey # This app's API key +requiredSecrets: + - db.password # Password from postgres dependency (aliased as 'db') + - redis.auth # Auth from redis dependency ``` **In resources:** @@ -227,14 +280,26 @@ env: valueFrom: secretKeyRef: name: myapp-secrets - key: apps.myapp.dbPassword # Full dotted path, not just "dbPassword" + key: dbPassword # Points to the default secret + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: myapp-secrets + key: db.password # Points to the required secret ``` **Secret workflow:** -1. List secrets in manifest's `defaultSecrets` -2. When adding an app, the system generates random values in the instance's `secrets.yaml` -3. When deploying, the system creates a Kubernetes Secret named `-secrets` -4. Resources reference secrets using full dotted paths +1. Define app's own secrets in `defaultSecrets` (key, default mappings) +2. Reference dependency secrets in `requiredSecrets` (list) +3. When adding an app, the system: + - Generates random values for empty `defaultSecrets` + - Copies referenced secrets from dependencies + - Stores all in the instance's `secrets.yaml` +4. When deploying, creates a Kubernetes Secret named `-secrets` containing: + - All `defaultSecrets` with key format: `` + - All `requiredSecrets` with key format: `.` + +**Key collision handling:** If the same key exists in both `defaultSecrets` and `requiredSecrets`, the `requiredSecrets` value takes precedence. Authors should ensure their local secrets don't collide with their required secrets. **Important:** Never commit `secrets.yaml` to Git. Templates should only reference secrets, never contain actual secret values. @@ -308,9 +373,11 @@ Before submitting a new or modified app, verify: - [ ] **Manifest** - [ ] `name` matches directory name - [ ] All required fields present (`name`, `description`, `version`, `defaultConfig`) - - [ ] All template variables defined in `defaultConfig` or are standard Wild Cloud variables - - [ ] Secrets use dotted-path format (e.g., `apps.appname.secretname`) - - [ ] Dependencies listed in `requires` (if any) + - [ ] All template variables defined in `defaultConfig` + - [ ] `defaultSecrets` uses maps with 'key' and 'default' attributes + - [ ] `requiredSecrets` references use `.` format + - [ ] Dependencies listed in `requires` with optional `alias` fields + - [ ] Manifest template references match dependency aliases or names - [ ] **Kustomization** - [ ] Includes standard Wild Cloud labels with `includeSelectors: true` @@ -318,8 +385,6 @@ Before submitting a new or modified app, verify: - [ ] All resource files listed under `resources:` - [ ] **Resources** - - [ ] All hardcoded values replaced with gomplate variables - - [ ] Secrets reference full dotted paths - [ ] Security contexts on all pods (both pod-level and container-level) - [ ] Simple component labels, no Helm-style labels - [ ] Ingresses include external-dns annotations diff --git a/discourse/configmap.yaml b/discourse/configmap.yaml deleted file mode 100644 index 8f6a46e..0000000 --- a/discourse/configmap.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -# Source: discourse/templates/configmaps.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: discourse - namespace: discourse -data: - DISCOURSE_HOSTNAME: "{{ .apps.discourse.domain }}" - DISCOURSE_SKIP_INSTALL: "no" - DISCOURSE_SITE_NAME: "{{ .apps.discourse.siteName }}" - DISCOURSE_USERNAME: "{{ .apps.discourse.adminUsername }}" - DISCOURSE_EMAIL: "{{ .apps.discourse.adminEmail }}" - - DISCOURSE_REDIS_HOST: "{{ .apps.discourse.redisHostname }}" - DISCOURSE_REDIS_PORT_NUMBER: "6379" - - DISCOURSE_DATABASE_HOST: "{{ .apps.discourse.dbHostname }}" - DISCOURSE_DATABASE_PORT_NUMBER: "5432" - DISCOURSE_DATABASE_NAME: "{{ .apps.discourse.dbName }}" - DISCOURSE_DATABASE_USER: "{{ .apps.discourse.dbUsername }}" - - DISCOURSE_SMTP_HOST: "{{ .apps.discourse.smtp.host }}" - DISCOURSE_SMTP_PORT: "{{ .apps.discourse.smtp.port }}" - DISCOURSE_SMTP_USER: "{{ .apps.discourse.smtp.user }}" - DISCOURSE_SMTP_PROTOCOL: "tls" - DISCOURSE_SMTP_AUTH: "login" - - # DISCOURSE_PRECOMPILE_ASSETS: "false" - # DISCOURSE_SKIP_INSTALL: "no" - # DISCOURSE_SKIP_BOOTSTRAP: "yes" diff --git a/discourse/db-init-job.yaml b/discourse/db-init-job.yaml index 4f2401c..7cbe9b0 100644 --- a/discourse/db-init-job.yaml +++ b/discourse/db-init-job.yaml @@ -27,7 +27,7 @@ spec: readOnlyRootFilesystem: false env: - name: PGHOST - value: "{{ .apps.discourse.dbHostname }}" + value: "{{ .dbHostname }}" - name: PGPORT value: "5432" - name: PGUSER @@ -36,16 +36,16 @@ spec: valueFrom: secretKeyRef: name: discourse-secrets - key: apps.postgres.password + key: postgres.password - name: DISCOURSE_DB_USER - value: "{{ .apps.discourse.dbUsername }}" + value: "{{ .dbUsername }}" - name: DISCOURSE_DB_NAME - value: "{{ .apps.discourse.dbName }}" + value: "{{ .dbName }}" - name: DISCOURSE_DB_PASSWORD valueFrom: secretKeyRef: name: discourse-secrets - key: apps.discourse.dbPassword + key: dbPassword command: - /bin/sh - -c diff --git a/discourse/deployment.yaml b/discourse/deployment.yaml index aaa8040..590de72 100644 --- a/discourse/deployment.yaml +++ b/discourse/deployment.yaml @@ -1,5 +1,4 @@ --- -# Source: discourse/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: @@ -18,219 +17,133 @@ spec: component: web spec: automountServiceAccountToken: false - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - podAffinityTerm: - labelSelector: - matchLabels: - component: web - topologyKey: kubernetes.io/hostname - weight: 1 - serviceAccountName: discourse securityContext: fsGroup: 0 fsGroupChangePolicy: Always - supplementalGroups: [] - sysctls: [] - initContainers: containers: - name: discourse - image: docker.io/bitnami/discourse:3.4.7-debian-12-r0 + image: tiredofit/discourse:latest imagePullPolicy: "IfNotPresent" securityContext: allowPrivilegeEscalation: false capabilities: + drop: + - ALL add: - CHOWN - - SYS_CHROOT + - DAC_OVERRIDE - FOWNER - SETGID - SETUID - - DAC_OVERRIDE - drop: - - ALL privileged: false readOnlyRootFilesystem: false - runAsGroup: 0 runAsNonRoot: false runAsUser: 0 - seLinuxOptions: {} seccompProfile: type: RuntimeDefault env: - - name: BITNAMI_DEBUG - value: "false" - - name: DISCOURSE_PASSWORD + # Admin configuration + - name: ADMIN_USER + value: {{ .adminUsername }} + - name: ADMIN_EMAIL + value: {{ .adminEmail }} + - name: ADMIN_PASS valueFrom: secretKeyRef: name: discourse-secrets - key: apps.discourse.adminPassword - - name: DISCOURSE_PORT_NUMBER - value: "8080" - - name: DISCOURSE_EXTERNAL_HTTP_PORT_NUMBER - value: "80" - - name: DISCOURSE_DATABASE_PASSWORD + key: adminPassword + # Site configuration + - name: SITE_TITLE + value: {{ .siteName }} + - name: HOSTNAME + value: {{ .domain }} + # Database configuration + - name: DB_HOST + value: {{ .dbHostname }} + - name: DB_PORT + value: "{{ .dbPort }}" + - name: DB_NAME + value: {{ .dbName }} + - name: DB_USER + value: {{ .dbUsername }} + - name: DB_PASS valueFrom: secretKeyRef: name: discourse-secrets - key: apps.discourse.dbPassword - - name: POSTGRESQL_CLIENT_CREATE_DATABASE_PASSWORD + key: dbPassword + # Redis configuration + - name: REDIS_HOST + value: {{ .redisHostname }} + - name: REDIS_PASS valueFrom: secretKeyRef: name: discourse-secrets - key: apps.discourse.dbPassword - - name: DISCOURSE_REDIS_PASSWORD + key: redis.password + # SMTP configuration + - name: SMTP_ENABLED + value: "{{ .smtp.enabled }}" + - name: SMTP_HOST + value: {{ .smtp.host }} + - name: SMTP_PORT + value: "{{ .smtp.port }}" + - name: SMTP_USER + value: {{ .smtp.user }} + - name: SMTP_PASS valueFrom: secretKeyRef: name: discourse-secrets - key: apps.redis.password - - name: DISCOURSE_SECRET_KEY_BASE - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.secretKeyBase - - name: DISCOURSE_SMTP_PASSWORD - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.smtpPassword - - name: SMTP_PASSWORD - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.smtpPassword - envFrom: - - configMapRef: - name: discourse + key: smtpPassword + - name: SMTP_TLS + value: "{{ .smtp.tls }}" + # Container timezone + - name: TZ + value: {{ .timezone }} ports: - name: http - containerPort: 8080 + containerPort: 3000 protocol: TCP livenessProbe: - tcpSocket: + httpGet: + path: / port: http - initialDelaySeconds: 500 - periodSeconds: 10 - timeoutSeconds: 5 + initialDelaySeconds: 420 + periodSeconds: 30 + timeoutSeconds: 10 successThreshold: 1 failureThreshold: 6 readinessProbe: httpGet: - path: /srv/status + path: / port: http - initialDelaySeconds: 180 - periodSeconds: 10 - timeoutSeconds: 5 + initialDelaySeconds: 360 + periodSeconds: 30 + timeoutSeconds: 10 successThreshold: 1 failureThreshold: 6 resources: limits: - cpu: 1 - ephemeral-storage: 2Gi - memory: 8Gi # for precompiling assets! + cpu: 2000m + ephemeral-storage: 10Gi + memory: 4Gi requests: - cpu: 750m + cpu: 500m ephemeral-storage: 50Mi memory: 1Gi volumeMounts: - - name: discourse-data - mountPath: /bitnami/discourse - subPath: discourse - - name: sidekiq - image: docker.io/bitnami/discourse:3.4.7-debian-12-r0 - imagePullPolicy: "IfNotPresent" - securityContext: - allowPrivilegeEscalation: false - capabilities: - add: - - CHOWN - - SYS_CHROOT - - FOWNER - - SETGID - - SETUID - - DAC_OVERRIDE - drop: - - ALL - privileged: false - readOnlyRootFilesystem: false - runAsGroup: 0 - runAsNonRoot: false - runAsUser: 0 - seLinuxOptions: {} - seccompProfile: - type: RuntimeDefault - command: - - /opt/bitnami/scripts/discourse/entrypoint.sh - args: - - /opt/bitnami/scripts/discourse-sidekiq/run.sh - env: - - name: BITNAMI_DEBUG - value: "false" - - name: DISCOURSE_PASSWORD - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.adminPassword - - name: DISCOURSE_POSTGRESQL_PASSWORD - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.dbPassword - - name: DISCOURSE_REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.redis.password - - name: DISCOURSE_SECRET_KEY_BASE - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.secretKeyBase - - name: DISCOURSE_SMTP_PASSWORD - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.smtpPassword - - name: SMTP_PASSWORD - valueFrom: - secretKeyRef: - name: discourse-secrets - key: apps.discourse.smtpPassword - envFrom: - - configMapRef: - name: discourse - livenessProbe: - exec: - command: ["/bin/sh", "-c", "pgrep -f ^sidekiq"] - initialDelaySeconds: 500 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 6 - readinessProbe: - exec: - command: ["/bin/sh", "-c", "pgrep -f ^sidekiq"] - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 6 - resources: - limits: - cpu: 500m - ephemeral-storage: 2Gi - memory: 768Mi - requests: - cpu: 375m - ephemeral-storage: 50Mi - memory: 512Mi - volumeMounts: - - name: discourse-data - mountPath: /bitnami/discourse - subPath: discourse + - name: discourse-logs + mountPath: /data/logs + - name: discourse-uploads + mountPath: /data/uploads + - name: discourse-backups + mountPath: /data/backups volumes: - - name: discourse-data + - name: discourse-logs persistentVolumeClaim: - claimName: discourse + claimName: discourse-logs + - name: discourse-uploads + persistentVolumeClaim: + claimName: discourse-uploads + - name: discourse-backups + persistentVolumeClaim: + claimName: discourse-backups diff --git a/discourse/ingress.yaml b/discourse/ingress.yaml index d11ab64..2277b03 100644 --- a/discourse/ingress.yaml +++ b/discourse/ingress.yaml @@ -4,13 +4,13 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: discourse - namespace: "discourse" + namespace: "{{ .namespace }}" annotations: external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" - external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}" + external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}" spec: rules: - - host: "{{ .apps.discourse.domain }}" + - host: "{{ .domain }}" http: paths: - path: / @@ -22,5 +22,5 @@ spec: name: http tls: - hosts: - - "{{ .apps.discourse.domain }}" + - "{{ .domain }}" secretName: wildcard-external-wild-cloud-tls diff --git a/discourse/kustomization.yaml b/discourse/kustomization.yaml index 2f407f4..c33d2e2 100644 --- a/discourse/kustomization.yaml +++ b/discourse/kustomization.yaml @@ -10,7 +10,6 @@ labels: resources: - namespace.yaml - serviceaccount.yaml - - configmap.yaml - pvc.yaml - deployment.yaml - service.yaml diff --git a/discourse/manifest.yaml b/discourse/manifest.yaml index f1e1fe7..5ad33fa 100644 --- a/discourse/manifest.yaml +++ b/discourse/manifest.yaml @@ -1,22 +1,25 @@ name: discourse description: Discourse is a modern, open-source discussion platform designed for online communities and forums. -version: 3.4.7 -icon: https://www.discourse.org/img/icon.png +version: 3.5.3 +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/discourse.svg requires: - name: postgres - name: redis defaultConfig: + namespace: discourse + externalDnsDomain: "{{ .cloud.domain }}" timezone: UTC - port: 8080 + port: 3000 storage: 10Gi - adminEmail: admin@{{ .cloud.domain }} + adminEmail: "{{ .operator.email }}" adminUsername: admin siteName: "Community" domain: discourse.{{ .cloud.domain }} - dbHostname: postgres.postgres.svc.cluster.local + dbHostname: "{{ .apps.postgres.host }}" + dbPort: "{{ .apps.postgres.port }}" dbUsername: discourse dbName: discourse - redisHostname: redis.redis.svc.cluster.local + redisHostname: "{{ .apps.redis.host }}" tlsSecretName: wildcard-wild-cloud-tls smtp: enabled: false @@ -24,13 +27,16 @@ defaultConfig: port: "{{ .cloud.smtp.port }}" user: "{{ .cloud.smtp.user }}" from: "{{ .cloud.smtp.from }}" - tls: {{ .cloud.smtp.tls }} - startTls: {{ .cloud.smtp.startTls }} + tls: "{{ .cloud.smtp.tls }}" + startTls: "{{ .cloud.smtp.startTls }}" defaultSecrets: - - - key: apps.discourse.adminPassword - - - key: apps.discourse.dbPassword - - - key: apps.discourse.dbUrl - - - key: apps.redis.password - - - key: apps.discourse.secretKeyBase - - - key: apps.discourse.smtpPassword - - - key: apps.postgres.password \ No newline at end of file + - key: adminPassword + - key: secretKeyBase + default: "{{ random.AlphaNum 64 }}" + - key: smtpPassword + - key: dbPassword + - key: dbUrl + default: "postgres://{{ .app.dbUsername }}:{{ .secrets.dbPassword }}@{{ .app.dbHostname }}:{{ .app.dbPort }}/{{ .app.dbName }}?sslmode=disable" +requiredSecrets: + - postgres.password + - redis.password \ No newline at end of file diff --git a/discourse/namespace.yaml b/discourse/namespace.yaml index 6bd89f9..b7816b8 100644 --- a/discourse/namespace.yaml +++ b/discourse/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: discourse + name: "{{ .namespace }}" diff --git a/discourse/pvc.yaml b/discourse/pvc.yaml index f73bd62..3583078 100644 --- a/discourse/pvc.yaml +++ b/discourse/pvc.yaml @@ -1,13 +1,39 @@ --- -# Source: discourse/templates/pvc.yaml -kind: PersistentVolumeClaim apiVersion: v1 +kind: PersistentVolumeClaim metadata: - name: discourse + name: discourse-logs namespace: discourse spec: accessModes: - - "ReadWriteOnce" + - ReadWriteOnce resources: requests: - storage: "{{ .apps.discourse.storage }}" + storage: 2Gi + storageClassName: longhorn +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: discourse-uploads + namespace: discourse +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .storage }} + storageClassName: longhorn +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: discourse-backups + namespace: discourse +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + storageClassName: longhorn diff --git a/example-admin/deployment.yaml b/example-admin/deployment.yaml index 65cc0a6..35b1ce0 100644 --- a/example-admin/deployment.yaml +++ b/example-admin/deployment.yaml @@ -3,7 +3,6 @@ apiVersion: apps/v1 kind: Deployment metadata: name: example-admin - namespace: example-admin labels: app: example-admin spec: diff --git a/example-admin/ingress.yaml b/example-admin/ingress.yaml index 02e2a83..d395421 100644 --- a/example-admin/ingress.yaml +++ b/example-admin/ingress.yaml @@ -3,10 +3,9 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-admin - namespace: example-admin spec: rules: - - host: example-admin.{{ .cloud.internalDomain }} + - host: "{{ .host }}" http: paths: - path: / @@ -18,5 +17,5 @@ spec: number: 80 tls: - hosts: - - example-admin.{{ .cloud.internalDomain }} + - "{{ .host }}" secretName: wildcard-internal-wild-cloud-tls diff --git a/example-admin/manifest.yaml b/example-admin/manifest.yaml index 755243d..b34c165 100644 --- a/example-admin/manifest.yaml +++ b/example-admin/manifest.yaml @@ -3,4 +3,7 @@ install: true description: An example application that is deployed with internal-only access. version: 1.0.0 defaultConfig: + namespace: example-admin + externalDnsDomain: '{{ .cloud.domain }}' + host: '{{ .host }}' tlsSecretName: wildcard-internal-wild-cloud-tls diff --git a/example-admin/namespace.yaml b/example-admin/namespace.yaml index 2d142cb..b7816b8 100644 --- a/example-admin/namespace.yaml +++ b/example-admin/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: example-admin + name: "{{ .namespace }}" diff --git a/example-app/ingress.yaml b/example-app/ingress.yaml index 018c711..fdc253d 100644 --- a/example-app/ingress.yaml +++ b/example-app/ingress.yaml @@ -4,7 +4,7 @@ kind: Ingress metadata: name: example-app annotations: - external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/target: "{{ .cloud.externalDnsTarget }}" external-dns.alpha.kubernetes.io/cloudflare-proxied: false # Optional: Enable HTTPS redirection @@ -15,7 +15,7 @@ metadata: # traefik.ingress.kubernetes.io/auth-secret: basic-auth spec: rules: - - host: example-app.{{ .cloud.domain }} + - host: "{{ .host }}" http: paths: - path: / @@ -27,5 +27,5 @@ spec: number: 80 tls: - hosts: - - example-app.{{ .cloud.domain }} + - "{{ .host }}" secretName: wildcard-wild-cloud-tls diff --git a/example-app/manifest.yaml b/example-app/manifest.yaml index 20d784f..a486bc5 100644 --- a/example-app/manifest.yaml +++ b/example-app/manifest.yaml @@ -3,4 +3,7 @@ install: true description: An example application that is deployed with public access. version: 1.0.0 defaultConfig: + namespace: example-app + externalDnsDomain: '{{ .cloud.domain }}' + host: example-app.{{ .cloud.domain }} tlsSecretName: wildcard-wild-cloud-tls diff --git a/example-app/namespace.yaml b/example-app/namespace.yaml index 3ddeaab..b7816b8 100644 --- a/example-app/namespace.yaml +++ b/example-app/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: example-app + name: "{{ .namespace }}" diff --git a/ghost/db-init-job.yaml b/ghost/db-init-job.yaml index 066cfe5..7e0fd02 100644 --- a/ghost/db-init-job.yaml +++ b/ghost/db-init-job.yaml @@ -12,7 +12,7 @@ spec: spec: containers: - name: db-init - image: {{ .apps.mysql.image }} + image: mysql:9.1.0 command: ["/bin/bash", "-c"] args: - | @@ -27,18 +27,18 @@ spec: valueFrom: secretKeyRef: name: mysql-secrets - key: apps.mysql.rootPassword + key: rootPassword - name: DB_HOSTNAME - value: "{{ .apps.ghost.dbHost }}" + value: "{{ .dbHost }}" - name: DB_PORT - value: "{{ .apps.ghost.dbPort }}" + value: "{{ .dbPort }}" - name: DB_DATABASE_NAME - value: "{{ .apps.ghost.dbName }}" + value: "{{ .dbName }}" - name: DB_USERNAME - value: "{{ .apps.ghost.dbUser }}" + value: "{{ .dbUser }}" - name: DB_PASSWORD valueFrom: secretKeyRef: name: ghost-secrets - key: apps.ghost.dbPassword + key: dbPassword restartPolicy: OnFailure \ No newline at end of file diff --git a/ghost/deployment.yaml b/ghost/deployment.yaml index 3679adb..f89071f 100644 --- a/ghost/deployment.yaml +++ b/ghost/deployment.yaml @@ -17,10 +17,10 @@ spec: spec: containers: - name: ghost - image: {{ .apps.ghost.image }} + image: {{ .image }} ports: - name: http - containerPort: {{ .apps.ghost.port }} + containerPort: {{ .port }} protocol: TCP env: - name: BITNAMI_DEBUG @@ -28,33 +28,33 @@ spec: - name: ALLOW_EMPTY_PASSWORD value: "yes" - name: GHOST_DATABASE_HOST - value: {{ .apps.ghost.dbHost }} + value: {{ .dbHost }} - name: GHOST_DATABASE_PORT_NUMBER - value: "{{ .apps.ghost.dbPort }}" + value: "{{ .dbPort }}" - name: GHOST_DATABASE_NAME - value: {{ .apps.ghost.dbName }} + value: {{ .dbName }} - name: GHOST_DATABASE_USER - value: {{ .apps.ghost.dbUser }} + value: {{ .dbUser }} - name: GHOST_DATABASE_PASSWORD valueFrom: secretKeyRef: name: ghost-secrets - key: apps.ghost.dbPassword + key: dbPassword - name: GHOST_HOST - value: {{ .apps.ghost.domain }} + value: {{ .domain }} - name: GHOST_PORT_NUMBER - value: "{{ .apps.ghost.port }}" + value: "{{ .port }}" - name: GHOST_USERNAME - value: {{ .apps.ghost.adminUser }} + value: {{ .adminUser }} - name: GHOST_PASSWORD valueFrom: secretKeyRef: name: ghost-secrets - key: apps.ghost.adminPassword + key: adminPassword - name: GHOST_EMAIL - value: {{ .apps.ghost.adminEmail }} + value: {{ .adminEmail }} - name: GHOST_BLOG_TITLE - value: {{ .apps.ghost.blogTitle }} + value: {{ .blogTitle }} - name: GHOST_ENABLE_HTTPS value: "yes" - name: GHOST_EXTERNAL_HTTP_PORT_NUMBER @@ -66,18 +66,18 @@ spec: - name: GHOST_SMTP_SERVICE value: SMTP - name: GHOST_SMTP_HOST - value: {{ .apps.ghost.smtp.host }} + value: {{ .smtp.host }} - name: GHOST_SMTP_PORT - value: "{{ .apps.ghost.smtp.port }}" + value: "{{ .smtp.port }}" - name: GHOST_SMTP_USER - value: {{ .apps.ghost.smtp.user }} + value: {{ .smtp.user }} - name: GHOST_SMTP_PASSWORD valueFrom: secretKeyRef: name: ghost-secrets - key: apps.ghost.smtpPassword + key: smtpPassword - name: GHOST_SMTP_FROM_ADDRESS - value: {{ .apps.ghost.smtp.from }} + value: {{ .smtp.from }} resources: limits: cpu: 375m @@ -92,7 +92,7 @@ spec: mountPath: /bitnami/ghost livenessProbe: tcpSocket: - port: {{ .apps.ghost.port }} + port: {{ .port }} initialDelaySeconds: 120 timeoutSeconds: 5 periodSeconds: 10 diff --git a/ghost/ingress.yaml b/ghost/ingress.yaml index 2fc0cac..02e7f96 100644 --- a/ghost/ingress.yaml +++ b/ghost/ingress.yaml @@ -7,12 +7,12 @@ metadata: kubernetes.io/ingress.class: "traefik" cert-manager.io/cluster-issuer: "letsencrypt-prod" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" - external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} external-dns.alpha.kubernetes.io/ttl: "60" traefik.ingress.kubernetes.io/redirect-entry-point: https spec: rules: - - host: {{ .apps.ghost.domain }} + - host: {{ .domain }} http: paths: - path: / @@ -24,5 +24,5 @@ spec: number: 80 tls: - hosts: - - {{ .apps.ghost.domain }} - secretName: {{ .apps.ghost.tlsSecretName }} \ No newline at end of file + - {{ .domain }} + secretName: {{ .tlsSecretName }} \ No newline at end of file diff --git a/ghost/manifest.yaml b/ghost/manifest.yaml index 8adbb52..7225814 100644 --- a/ghost/manifest.yaml +++ b/ghost/manifest.yaml @@ -1,10 +1,13 @@ name: ghost -description: Ghost is a powerful app for new-media creators to publish, share, and grow a business around their content. +description: Ghost is a powerful app for new-media creators to publish, share, and + grow a business around their content. version: 5.118.1 -icon: https://ghost.org/images/logos/ghost-logo-orb.png +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/ghost.png requires: - - name: mysql +- name: mysql defaultConfig: + namespace: ghost + externalDnsDomain: '{{ .cloud.domain }}' image: docker.io/bitnami/ghost:5.118.1-debian-12-r0 domain: ghost.{{ .cloud.domain }} tlsSecretName: wildcard-wild-cloud-tls @@ -15,16 +18,17 @@ defaultConfig: dbName: ghost dbUser: ghost adminUser: admin - adminEmail: "admin@{{ .cloud.domain }}" - blogTitle: "My Blog" + adminEmail: {{ .operator.email }} + blogTitle: My Blog timezone: UTC - tlsSecretName: wildcard-wild-cloud-tls smtp: - host: "{{ .cloud.smtp.host }}" - port: "{{ .cloud.smtp.port }}" - from: "{{ .cloud.smtp.from }}" - user: "{{ .cloud.smtp.user }}" + host: '{{ .cloud.smtp.host }}' + port: '{{ .cloud.smtp.port }}' + from: '{{ .cloud.smtp.from }}' + user: '{{ .cloud.smtp.user }}' defaultSecrets: - - key: apps.ghost.adminPassword - - key: apps.ghost.dbPassword - - key: apps.ghost.smtpPassword \ No newline at end of file +- key: adminPassword +- key: dbPassword +- key: smtpPassword +requiredSecrets: +- mysql.rootPassword diff --git a/ghost/namespace.yaml b/ghost/namespace.yaml index 9cf06a2..ef059b8 100644 --- a/ghost/namespace.yaml +++ b/ghost/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: ghost \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/ghost/pvc.yaml b/ghost/pvc.yaml index 9417048..0079693 100644 --- a/ghost/pvc.yaml +++ b/ghost/pvc.yaml @@ -8,4 +8,4 @@ spec: - ReadWriteOnce resources: requests: - storage: {{ .apps.ghost.storage }} \ No newline at end of file + storage: {{ .storage }} \ No newline at end of file diff --git a/ghost/service.yaml b/ghost/service.yaml index 0d9bc7c..d230d9a 100644 --- a/ghost/service.yaml +++ b/ghost/service.yaml @@ -9,6 +9,6 @@ spec: - name: http port: 80 protocol: TCP - targetPort: {{ .apps.ghost.port }} + targetPort: {{ .port }} selector: component: web \ No newline at end of file diff --git a/gitea/db-init-job.yaml b/gitea/db-init-job.yaml index d9a3454..26c81a5 100644 --- a/gitea/db-init-job.yaml +++ b/gitea/db-init-job.yaml @@ -12,7 +12,7 @@ spec: spec: containers: - name: db-init - image: {{ .apps.postgres.image }} + image: postgres:17 command: ["/bin/bash", "-c"] args: - | @@ -36,16 +36,16 @@ spec: valueFrom: secretKeyRef: name: postgres-secrets - key: apps.postgres.password + key: password - name: DB_HOSTNAME - value: "{{ .apps.gitea.dbHost }}" + value: "{{ .dbHost }}" - name: DB_DATABASE_NAME - value: "{{ .apps.gitea.dbName }}" + value: "{{ .dbName }}" - name: DB_USERNAME - value: "{{ .apps.gitea.dbUser }}" + value: "{{ .dbUser }}" - name: DB_PASSWORD valueFrom: secretKeyRef: name: gitea-secrets - key: apps.gitea.dbPassword + key: dbPassword restartPolicy: OnFailure \ No newline at end of file diff --git a/gitea/deployment.yaml b/gitea/deployment.yaml index 906afb9..9fee93f 100644 --- a/gitea/deployment.yaml +++ b/gitea/deployment.yaml @@ -23,7 +23,7 @@ spec: terminationGracePeriodSeconds: 60 containers: - name: gitea - image: "{{ .apps.gitea.image }}" + image: "{{ .image }}" imagePullPolicy: IfNotPresent envFrom: - configMapRef: @@ -33,27 +33,27 @@ spec: valueFrom: secretKeyRef: name: gitea-secrets - key: apps.gitea.adminPassword + key: adminPassword - name: GITEA__security__SECRET_KEY valueFrom: secretKeyRef: name: gitea-secrets - key: apps.gitea.secretKey + key: secretKey - name: GITEA__security__INTERNAL_TOKEN valueFrom: secretKeyRef: name: gitea-secrets - key: apps.gitea.jwtSecret + key: jwtSecret - name: GITEA__database__PASSWD valueFrom: secretKeyRef: name: gitea-secrets - key: apps.gitea.dbPassword + key: dbPassword - name: GITEA__mailer__PASSWD valueFrom: secretKeyRef: name: gitea-secrets - key: apps.gitea.smtpPassword + key: smtpPassword ports: - name: ssh containerPort: 2222 diff --git a/gitea/gitea.env b/gitea/gitea.env index ef12236..e67fe5e 100644 --- a/gitea/gitea.env +++ b/gitea/gitea.env @@ -3,12 +3,12 @@ SSH_PORT=22 GITEA_WORK_DIR=/data GITEA_TEMP=/tmp/gitea TMPDIR=/tmp/gitea -GITEA_ADMIN_USERNAME={{ .apps.gitea.adminUser }} +GITEA_ADMIN_USERNAME={{ .adminUser }} GITEA_ADMIN_PASSWORD_MODE=keepUpdated # Core app settings -GITEA____APP_NAME={{ .apps.gitea.appName }} -GITEA____RUN_MODE={{ .apps.gitea.runMode }} +GITEA____APP_NAME={{ .appName }} +GITEA____RUN_MODE={{ .runMode }} GITEA____RUN_USER=git # Security settings @@ -17,19 +17,19 @@ 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__HOST={{ .dbHost }}:{{ .dbPort }} +GITEA__database__NAME={{ .dbName }} +GITEA__database__USER={{ .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__DOMAIN={{ .domain }} +GITEA__server__HTTP_PORT={{ .port }} +GITEA__server__ROOT_URL=https://{{ .domain }}/ GITEA__server__DISABLE_SSH=false -GITEA__server__SSH_DOMAIN={{ .apps.gitea.domain }} -GITEA__server__SSH_PORT={{ .apps.gitea.sshPort }} +GITEA__server__SSH_DOMAIN={{ .domain }} +GITEA__server__SSH_PORT={{ .sshPort }} GITEA__server__SSH_LISTEN_PORT=2222 GITEA__server__LFS_START_SERVER=true GITEA__server__OFFLINE_MODE=true @@ -53,8 +53,8 @@ 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 }} +GITEA__mailer__SMTP_ADDR={{ .smtp.host }} +GITEA__mailer__SMTP_PORT={{ .smtp.port }} +GITEA__mailer__FROM={{ .smtp.from }} +GITEA__mailer__USER={{ .smtp.user }} diff --git a/gitea/ingress.yaml b/gitea/ingress.yaml index db32452..862bcbe 100644 --- a/gitea/ingress.yaml +++ b/gitea/ingress.yaml @@ -5,10 +5,10 @@ metadata: namespace: gitea annotations: external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" - external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}" + external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}" spec: rules: - - host: "{{ .apps.gitea.domain }}" + - host: "{{ .domain }}" http: paths: - path: / @@ -19,6 +19,6 @@ spec: port: number: 3000 tls: - - secretName: "{{ .apps.gitea.tlsSecretName }}" + - secretName: "{{ .tlsSecretName }}" hosts: - - "{{ .apps.gitea.domain }}" + - "{{ .domain }}" diff --git a/gitea/manifest.yaml b/gitea/manifest.yaml index d1efb54..335367e 100644 --- a/gitea/manifest.yaml +++ b/gitea/manifest.yaml @@ -1,10 +1,12 @@ name: gitea description: Gitea is a painless self-hosted Git service written in Go version: 1.24.3 -icon: https://github.com/go-gitea/gitea/raw/main/assets/logo.png +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gitea.svg requires: - - name: postgres +- name: postgres defaultConfig: + namespace: gitea + externalDnsDomain: '{{ .cloud.domain }}' image: gitea/gitea:1.24.3 appName: Gitea domain: gitea.{{ .cloud.domain }} @@ -16,18 +18,20 @@ defaultConfig: dbUser: gitea dbHost: postgres.postgres.svc.cluster.local adminUser: admin - adminEmail: "admin@{{ .cloud.domain }}" + adminEmail: "{{ .operator.email }}" dbPort: 5432 timezone: UTC runMode: prod smtp: - host: "{{ .cloud.smtp.host }}" - port: "{{ .cloud.smtp.port }}" - user: "{{ .cloud.smtp.user }}" - from: "{{ .cloud.smtp.from }}" + host: '{{ .cloud.smtp.host }}' + port: '{{ .cloud.smtp.port }}' + user: '{{ .cloud.smtp.user }}' + from: '{{ .cloud.smtp.from }}' defaultSecrets: - - key: apps.gitea.adminPassword - - key: apps.gitea.dbPassword - - key: apps.gitea.secretKey - - key: apps.gitea.jwtSecret - - key: apps.gitea.smtpPassword +- key: adminPassword +- key: dbPassword +- key: secretKey +- key: jwtSecret +- key: smtpPassword +requiredSecrets: +- postgres.password diff --git a/gitea/namespace.yaml b/gitea/namespace.yaml index d884423..ef059b8 100644 --- a/gitea/namespace.yaml +++ b/gitea/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: gitea \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/gitea/pvc.yaml b/gitea/pvc.yaml index da95a6b..9164b64 100644 --- a/gitea/pvc.yaml +++ b/gitea/pvc.yaml @@ -9,4 +9,4 @@ spec: storageClassName: longhorn resources: requests: - storage: "{{ .apps.gitea.storage }}" \ No newline at end of file + storage: "{{ .storage }}" \ No newline at end of file diff --git a/gitea/service.yaml b/gitea/service.yaml index 7bac6b2..4d358af 100644 --- a/gitea/service.yaml +++ b/gitea/service.yaml @@ -8,7 +8,7 @@ spec: ports: - name: http port: 3000 - targetPort: {{ .apps.gitea.port }} + targetPort: {{ .port }} selector: component: web --- @@ -21,7 +21,7 @@ spec: type: LoadBalancer ports: - name: ssh - port: {{ .apps.gitea.sshPort }} + port: {{ .sshPort }} targetPort: 2222 protocol: TCP selector: diff --git a/immich/db-init-job.yaml b/immich/db-init-job.yaml index bb540cc..5e63d5d 100644 --- a/immich/db-init-job.yaml +++ b/immich/db-init-job.yaml @@ -7,7 +7,7 @@ spec: spec: containers: - name: db-init - image: {{ .apps.postgres.image }} + image: postgres:17 command: ["/bin/bash", "-c"] args: - | @@ -53,16 +53,16 @@ spec: valueFrom: secretKeyRef: name: immich-secrets - key: apps.postgres.password + key: postgres.password - name: DB_HOSTNAME - value: "{{ .apps.immich.dbHostname }}" + value: "{{ .dbHostname }}" - name: DB_DATABASE_NAME - value: "{{ .apps.immich.dbUsername }}" + value: "{{ .dbUsername }}" - name: DB_USERNAME - value: "{{ .apps.immich.dbUsername }}" + value: "{{ .dbUsername }}" - name: DB_PASSWORD valueFrom: secretKeyRef: name: immich-secrets - key: apps.immich.dbPassword + key: dbPassword restartPolicy: OnFailure diff --git a/immich/deployment-machine-learning.yaml b/immich/deployment-machine-learning.yaml index c93b434..9a6598d 100644 --- a/immich/deployment-machine-learning.yaml +++ b/immich/deployment-machine-learning.yaml @@ -15,14 +15,14 @@ spec: component: machine-learning spec: containers: - - image: "{{ .apps.immich.mlImage }}" + - image: "{{ .mlImage }}" name: immich-machine-learning ports: - - containerPort: {{ .apps.immich.mlPort }} + - containerPort: {{ .mlPort }} protocol: TCP env: - name: TZ - value: "{{ .apps.immich.timezone }}" + value: "{{ .timezone }}" volumeMounts: - mountPath: /cache name: immich-cache diff --git a/immich/deployment-microservices.yaml b/immich/deployment-microservices.yaml index 53651a0..191b332 100644 --- a/immich/deployment-microservices.yaml +++ b/immich/deployment-microservices.yaml @@ -20,27 +20,27 @@ spec: component: microservices spec: containers: - - image: "{{ .apps.immich.serverImage }}" + - image: "{{ .serverImage }}" name: immich-microservices env: - name: REDIS_HOSTNAME - value: "{{ .apps.immich.redisHostname }}" + value: "{{ .redisHostname }}" - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: immich-secrets - key: apps.redis.password + key: redis.password - name: DB_HOSTNAME - value: "{{ .apps.immich.dbHostname }}" + value: "{{ .dbHostname }}" - name: DB_USERNAME - value: "{{ .apps.immich.dbUsername }}" + value: "{{ .dbUsername }}" - name: DB_PASSWORD valueFrom: secretKeyRef: name: immich-secrets - key: apps.immich.dbPassword + key: dbPassword - name: TZ - value: "{{ .apps.immich.timezone }}" + value: "{{ .timezone }}" - name: IMMICH_WORKERS_EXCLUDE value: api volumeMounts: diff --git a/immich/deployment-server.yaml b/immich/deployment-server.yaml index e43c2d6..311131f 100644 --- a/immich/deployment-server.yaml +++ b/immich/deployment-server.yaml @@ -20,30 +20,30 @@ spec: component: server spec: containers: - - image: "{{ .apps.immich.serverImage }}" + - image: "{{ .serverImage }}" name: immich-server ports: - - containerPort: {{ .apps.immich.serverPort }} + - containerPort: {{ .serverPort }} protocol: TCP env: - name: REDIS_HOSTNAME - value: "{{ .apps.immich.redisHostname }}" + value: "{{ .redisHostname }}" - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: immich-secrets - key: apps.redis.password + key: redis.password - name: DB_HOSTNAME - value: "{{ .apps.immich.dbHostname }}" + value: "{{ .dbHostname }}" - name: DB_USERNAME - value: "{{ .apps.immich.dbUsername }}" + value: "{{ .dbUsername }}" - name: DB_PASSWORD valueFrom: secretKeyRef: name: immich-secrets - key: apps.immich.dbPassword + key: dbPassword - name: TZ - value: "{{ .apps.immich.timezone }}" + value: "{{ .timezone }}" - name: IMMICH_WORKERS_EXCLUDE value: microservices volumeMounts: diff --git a/immich/ingress.yaml b/immich/ingress.yaml index b4e57b4..c5826db 100644 --- a/immich/ingress.yaml +++ b/immich/ingress.yaml @@ -4,11 +4,11 @@ kind: Ingress metadata: name: immich-public annotations: - external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}" + external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" spec: rules: - - host: "{{ .apps.immich.domain }}" + - host: "{{ .domain }}" http: paths: - path: / @@ -21,4 +21,4 @@ spec: tls: - secretName: wildcard-wild-cloud-tls hosts: - - "{{ .apps.immich.domain }}" + - "{{ .domain }}" diff --git a/immich/manifest.yaml b/immich/manifest.yaml index e21bc0a..b80b865 100644 --- a/immich/manifest.yaml +++ b/immich/manifest.yaml @@ -1,12 +1,15 @@ name: immich install: true -description: Immich is a self-hosted photo and video backup solution that allows you to store, manage, and share your media files securely. -version: 1.0.0 -icon: https://immich.app/assets/images/logo.png +description: Immich is a self-hosted photo and video backup solution that allows you + to store, manage, and share your media files securely. +version: release +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/immich.svg requires: - - name: redis - - name: postgres +- name: redis +- name: postgres defaultConfig: + namespace: immich + externalDnsDomain: '{{ .cloud.domain }}' serverImage: ghcr.io/immich-app/immich-server:release mlImage: ghcr.io/immich-app/immich-machine-learning:release timezone: UTC @@ -20,6 +23,7 @@ defaultConfig: domain: immich.{{ .cloud.domain }} tlsSecretName: wildcard-wild-cloud-tls defaultSecrets: - - key: apps.immich.dbPassword - - key: apps.postgres.password - - key: apps.redis.password +- key: dbPassword +requiredSecrets: +- redis.password +- postgres.password diff --git a/immich/namespace.yaml b/immich/namespace.yaml index 7829a88..ef059b8 100644 --- a/immich/namespace.yaml +++ b/immich/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: immich \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/immich/pvc.yaml b/immich/pvc.yaml index 33eb69f..7c10d66 100644 --- a/immich/pvc.yaml +++ b/immich/pvc.yaml @@ -9,7 +9,7 @@ spec: - ReadWriteOnce resources: requests: - storage: {{ .apps.immich.storage }} + storage: {{ .storage }} --- apiVersion: v1 kind: PersistentVolumeClaim @@ -21,4 +21,4 @@ spec: - ReadWriteOnce resources: requests: - storage: {{ .apps.immich.cacheStorage }} + storage: {{ .cacheStorage }} diff --git a/immich/service.yaml b/immich/service.yaml index 639f065..aaa1b08 100644 --- a/immich/service.yaml +++ b/immich/service.yaml @@ -9,7 +9,7 @@ metadata: spec: ports: - port: 3001 - targetPort: {{ .apps.immich.serverPort }} + targetPort: {{ .serverPort }} selector: app: immich component: server @@ -25,7 +25,7 @@ metadata: app: immich-machine-learning spec: ports: - - port: {{ .apps.immich.mlPort }} + - port: {{ .mlPort }} selector: app: immich component: machine-learning diff --git a/keila/db-init-job.yaml b/keila/db-init-job.yaml index 01109fc..59a8d3d 100644 --- a/keila/db-init-job.yaml +++ b/keila/db-init-job.yaml @@ -26,23 +26,23 @@ spec: readOnlyRootFilesystem: false env: - name: PGHOST - value: {{ .apps.keila.dbHostname }} + value: {{ .dbHostname }} - name: PGUSER value: postgres - name: PGPASSWORD valueFrom: secretKeyRef: name: keila-secrets - key: apps.postgres.password + key: postgres.password - name: DB_NAME - value: {{ .apps.keila.dbName }} + value: {{ .dbName }} - name: DB_USER - value: {{ .apps.keila.dbUsername }} + value: {{ .dbUsername }} - name: DB_PASSWORD valueFrom: secretKeyRef: name: keila-secrets - key: apps.keila.dbPassword + key: dbPassword command: - /bin/bash - -c diff --git a/keila/deployment.yaml b/keila/deployment.yaml index 232d54b..a5b0678 100644 --- a/keila/deployment.yaml +++ b/keila/deployment.yaml @@ -14,54 +14,54 @@ spec: spec: containers: - name: keila - image: {{ .apps.keila.image }} + image: "{{ .image }}" ports: - - containerPort: {{ .apps.keila.port }} + - containerPort: {{ .port }} env: - name: DB_URL valueFrom: secretKeyRef: name: keila-secrets - key: apps.keila.dbUrl + key: dbUrl - name: URL_HOST - value: {{ .apps.keila.domain }} + value: "{{ .domain }}" - name: URL_SCHEMA value: https - name: URL_PORT value: "443" - name: PORT - value: "{{ .apps.keila.port }}" + value: "{{ .port }}" - name: SECRET_KEY_BASE valueFrom: secretKeyRef: name: keila-secrets - key: apps.keila.secretKeyBase + key: secretKeyBase - name: MAILER_SMTP_HOST - value: {{ .apps.keila.smtp.host }} + value: "{{ .smtp.host }}" - name: MAILER_SMTP_PORT - value: "{{ .apps.keila.smtp.port }}" + value: "{{ .smtp.port }}" - name: MAILER_ENABLE_SSL - value: "{{ .apps.keila.smtp.tls }}" + value: "{{ .smtp.tls }}" - name: MAILER_ENABLE_STARTTLS - value: "{{ .apps.keila.smtp.startTls }}" + value: "{{ .smtp.startTls }}" - name: MAILER_SMTP_USER - value: {{ .apps.keila.smtp.user }} + value: "{{ .smtp.user }}" - name: MAILER_SMTP_PASSWORD valueFrom: secretKeyRef: name: keila-secrets - key: apps.keila.smtpPassword + key: smtpPassword - name: MAILER_SMTP_FROM_EMAIL - value: {{ .apps.keila.smtp.from }} + value: "{{ .smtp.from }}" - name: DISABLE_REGISTRATION - value: "{{ .apps.keila.disableRegistration }}" + value: "{{ .disableRegistration }}" - name: KEILA_USER - value: "{{ .apps.keila.adminUser }}" + value: "{{ .adminUser }}" - name: KEILA_PASSWORD valueFrom: secretKeyRef: name: keila-secrets - key: apps.keila.adminPassword + key: adminPassword - name: USER_CONTENT_DIR value: /var/lib/keila/uploads volumeMounts: @@ -70,13 +70,13 @@ spec: livenessProbe: httpGet: path: / - port: {{ .apps.keila.port }} + port: {{ .port }} initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: / - port: {{ .apps.keila.port }} + port: {{ .port }} initialDelaySeconds: 5 periodSeconds: 5 volumes: diff --git a/keila/ingress.yaml b/keila/ingress.yaml index 0c93a9e..1f22453 100644 --- a/keila/ingress.yaml +++ b/keila/ingress.yaml @@ -5,12 +5,12 @@ metadata: annotations: traefik.ingress.kubernetes.io/router.tls: "true" traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt - external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" traefik.ingress.kubernetes.io/router.middlewares: keila-cors@kubernetescrd spec: rules: - - host: {{ .apps.keila.domain }} + - host: {{ .domain }} http: paths: - path: / @@ -23,4 +23,4 @@ spec: tls: - secretName: "wildcard-wild-cloud-tls" hosts: - - "{{ .apps.keila.domain }}" + - "{{ .domain }}" diff --git a/keila/manifest.yaml b/keila/manifest.yaml index 1ed7870..9004ec3 100644 --- a/keila/manifest.yaml +++ b/keila/manifest.yaml @@ -1,15 +1,18 @@ name: keila description: Keila is an open-source email marketing platform that allows you to send newsletters and manage mailing lists with privacy and control. -version: 1.0.0 -icon: https://www.keila.io/images/logo.svg +version: 0.17.1 +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/keila.svg requires: - name: postgres defaultConfig: - image: pentacent/keila:latest + namespace: keila + externalDnsDomain: "{{ .cloud.domain }}" + image: pentacent/keila:0.17.1 port: 4000 storage: 1Gi domain: keila.{{ .cloud.domain }} - dbHostname: postgres.postgres.svc.cluster.local + dbHostname: "{{ .apps.postgres.host }}" + dbPort: "{{ .apps.postgres.port }}" dbName: keila dbUsername: keila disableRegistration: "true" @@ -20,12 +23,15 @@ defaultConfig: port: "{{ .cloud.smtp.port }}" from: "{{ .cloud.smtp.from }}" user: "{{ .cloud.smtp.user }}" - tls: {{ .cloud.smtp.tls }} - startTls: {{ .cloud.smtp.startTls }} + tls: "{{ .cloud.smtp.tls }}" + startTls: "{{ .cloud.smtp.startTls }}" defaultSecrets: - - key: apps.keila.secretKeyBase - - key: apps.keila.dbPassword - - key: apps.keila.dbUrl - - key: apps.keila.adminPassword - - key: apps.keila.smtpPassword - - key: apps.postgres.password \ No newline at end of file + - key: secretKeyBase + default: "{{ random.AlphaNum 64 }}" + - key: dbPassword + - key: dbUrl + default: "postgres://{{ .app.dbUsername }}:{{ .secrets.dbPassword }}@{{ .app.dbHostname }}:{{ .app.dbPort }}/keila?sslmode=disable" + - key: adminPassword + - key: smtpPassword +requiredSecrets: + - postgres.password \ No newline at end of file diff --git a/keila/middleware-cors.yaml b/keila/middleware-cors.yaml index 599e5c2..ff831e3 100644 --- a/keila/middleware-cors.yaml +++ b/keila/middleware-cors.yaml @@ -21,8 +21,8 @@ spec: - "OPTIONS" accessControlAllowOriginList: - "http://localhost:1313" - - "https://*.{{ .cloud.domain }}" - - "https://{{ .cloud.domain }}" + - "https://*.{{ .externalDnsDomain }}" + - "https://{{ .externalDnsDomain }}" accessControlExposeHeaders: - "*" accessControlMaxAge: 86400 \ No newline at end of file diff --git a/keila/namespace.yaml b/keila/namespace.yaml index 73d5f12..ef059b8 100644 --- a/keila/namespace.yaml +++ b/keila/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: keila \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/keila/pvc.yaml b/keila/pvc.yaml index 2becff2..9dea2b8 100644 --- a/keila/pvc.yaml +++ b/keila/pvc.yaml @@ -7,4 +7,4 @@ spec: - ReadWriteOnce resources: requests: - storage: {{ .apps.keila.storage }} \ No newline at end of file + storage: {{ .storage }} \ No newline at end of file diff --git a/keila/service.yaml b/keila/service.yaml index 6800006..94d3a86 100644 --- a/keila/service.yaml +++ b/keila/service.yaml @@ -7,5 +7,5 @@ spec: component: web ports: - port: 80 - targetPort: {{ .apps.keila.port }} + targetPort: {{ .port }} protocol: TCP \ No newline at end of file diff --git a/listmonk/db-init-job.yaml b/listmonk/db-init-job.yaml index 5ca2eae..0d536d7 100644 --- a/listmonk/db-init-job.yaml +++ b/listmonk/db-init-job.yaml @@ -28,23 +28,23 @@ spec: readOnlyRootFilesystem: false env: - name: PGHOST - value: {{ .apps.listmonk.dbHost }} + value: {{ .dbHost }} - name: PGUSER value: postgres - name: PGPASSWORD valueFrom: secretKeyRef: name: listmonk-secrets - key: apps.postgres.password + key: postgres.password - name: DB_NAME - value: {{ .apps.listmonk.dbName }} + value: {{ .dbName }} - name: DB_USER - value: {{ .apps.listmonk.dbUser }} + value: {{ .dbUser }} - name: DB_PASSWORD valueFrom: secretKeyRef: name: listmonk-secrets - key: apps.listmonk.dbPassword + key: dbPassword command: - /bin/bash - -c diff --git a/listmonk/deployment.yaml b/listmonk/deployment.yaml index b67c999..749af51 100644 --- a/listmonk/deployment.yaml +++ b/listmonk/deployment.yaml @@ -30,21 +30,23 @@ spec: env: - name: LISTMONK_app__address value: "0.0.0.0:9000" + - name: LISTMONK_app__root_url + value: "{{ .rootUrl }}" - name: LISTMONK_db__host - value: {{ .apps.listmonk.dbHost }} + value: {{ .dbHost }} - name: LISTMONK_db__port - value: "{{ .apps.listmonk.dbPort }}" + value: "{{ .dbPort }}" - name: LISTMONK_db__user - value: {{ .apps.listmonk.dbUser }} + value: {{ .dbUser }} - name: LISTMONK_db__database - value: {{ .apps.listmonk.dbName }} + value: {{ .dbName }} - name: LISTMONK_db__ssl_mode - value: {{ .apps.listmonk.dbSSLMode }} + value: {{ .dbSSLMode }} - name: LISTMONK_db__password valueFrom: secretKeyRef: name: listmonk-secrets - key: apps.listmonk.dbPassword + key: dbPassword resources: limits: cpu: 500m diff --git a/listmonk/ingress.yaml b/listmonk/ingress.yaml index e63de9e..e73bd7a 100644 --- a/listmonk/ingress.yaml +++ b/listmonk/ingress.yaml @@ -6,16 +6,16 @@ metadata: annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls: "true" - external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" spec: ingressClassName: traefik tls: - hosts: - - {{ .apps.listmonk.domain }} - secretName: {{ .apps.listmonk.tlsSecretName }} + - {{ .domain }} + secretName: {{ .tlsSecretName }} rules: - - host: {{ .apps.listmonk.domain }} + - host: {{ .domain }} http: paths: - path: / diff --git a/listmonk/manifest.yaml b/listmonk/manifest.yaml index 09bb9dd..7435b69 100644 --- a/listmonk/manifest.yaml +++ b/listmonk/manifest.yaml @@ -1,11 +1,15 @@ name: listmonk -description: Listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. +description: Listmonk is a standalone, self-hosted, newsletter and mailing list manager. + It is fast, feature-rich, and packed into a single binary. version: 5.0.3 icon: https://listmonk.app/static/images/logo.svg requires: - - name: postgres +- name: postgres defaultConfig: + namespace: listmonk + externalDnsDomain: '{{ .cloud.domain }}' domain: listmonk.{{ .cloud.domain }} + rootUrl: https://listmonk.{{ .cloud.domain }} tlsSecretName: wildcard-wild-cloud-tls storage: 1Gi dbHost: postgres.postgres.svc.cluster.local @@ -15,6 +19,8 @@ defaultConfig: dbSSLMode: disable timezone: UTC defaultSecrets: - - key: apps.listmonk.dbPassword - - key: apps.listmonk.dbUrl - - key: apps.postgres.password \ No newline at end of file +- key: dbPassword +- key: dbUrl + default: 'postgres://{{ .app.dbUser }}:{{ .secrets.dbPassword }}@{{ .app.dbHost }}:{{ .app.dbPort }}/{{ .app.dbName }}?sslmode={{ .app.dbSSLMode }}' +requiredSecrets: +- postgres.password diff --git a/listmonk/namespace.yaml b/listmonk/namespace.yaml index b7fe900..ef059b8 100644 --- a/listmonk/namespace.yaml +++ b/listmonk/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: listmonk \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/listmonk/pvc.yaml b/listmonk/pvc.yaml index 926bf1e..d11e371 100644 --- a/listmonk/pvc.yaml +++ b/listmonk/pvc.yaml @@ -8,4 +8,4 @@ spec: - ReadWriteOnce resources: requests: - storage: {{ .apps.listmonk.storage }} \ No newline at end of file + storage: {{ .storage }} \ No newline at end of file diff --git a/loomio/manifest.yaml b/loomio/manifest.yaml index 8dbbbd0..5778baa 100644 --- a/loomio/manifest.yaml +++ b/loomio/manifest.yaml @@ -1,27 +1,27 @@ name: loomio description: Loomio is a collaborative decision-making tool that makes it easy for groups to make decisions together version: 3.0.11 -icon: https://www.loomio.com/favicon.ico +icon: https://www.loomio.com/brand/logo_gold.svg requires: - name: postgres installed_as: postgres - name: redis defaultConfig: namespace: loomio - externalDnsDomain: {{ .cloud.domain }} + externalDnsDomain: "{{ .cloud.domain }}" image: loomio/loomio:v3.0.11 workerImage: loomio/loomio:v3.0.11 appName: Loomio - domain: loomio.{{ .cloud.domain }} + domain: "loomio.{{ .cloud.domain }}" tlsSecretName: wildcard-wild-cloud-tls port: 3000 storage: uploads: 5Gi files: 5Gi plugins: 1Gi - redisUrl: {{ .apps.redis.uri }} - adminEmail: "admin@{{ .cloud.domain }}" - supportEmail: "support@{{ .cloud.domain }}" + redisUrl: "{{ .apps.redis.uri }}" + adminEmail: "{{ .operator.email }}" + supportEmail: "{{ .operator.email }}" forceSSL: "1" useRackAttack: "1" pumaWorkers: "2" @@ -31,8 +31,8 @@ defaultConfig: db: name: loomio user: loomio - host: {{ .apps.postgres.host }} - port: {{ .apps.postgres.port }} + host: "{{ .apps.postgres.host }}" + port: "{{ .apps.postgres.port }}" smtp: auth: plain domain: "{{ .cloud.domain }}" diff --git a/memcached/deployment.yaml b/memcached/deployment.yaml index 25db50f..5b153b2 100644 --- a/memcached/deployment.yaml +++ b/memcached/deployment.yaml @@ -3,7 +3,7 @@ kind: Deployment metadata: name: memcached spec: - replicas: {{ .apps.memcached.replicas }} + replicas: {{ .replicas }} selector: matchLabels: component: cache @@ -14,24 +14,24 @@ spec: spec: containers: - name: memcached - image: {{ .apps.memcached.image }} + image: "{{ .image }}" ports: - - containerPort: {{ .apps.memcached.port }} + - containerPort: {{ .port }} name: memcached args: - -m - - {{ .apps.memcached.memoryLimit }} + - "{{ .memoryLimit }}" - -c - - "{{ .apps.memcached.maxConnections }}" + - "{{ .maxConnections }}" - -p - - "{{ .apps.memcached.port }}" + - "{{ .port }}" resources: requests: - memory: {{ .apps.memcached.resources.requests.memory }} - cpu: {{ .apps.memcached.resources.requests.cpu }} + memory: "{{ .resources.requests.memory }}" + cpu: "{{ .resources.requests.cpu }}" limits: - memory: {{ .apps.memcached.resources.limits.memory }} - cpu: {{ .apps.memcached.resources.limits.cpu }} + memory: "{{ .resources.limits.memory }}" + cpu: "{{ .resources.limits.cpu }}" securityContext: runAsNonRoot: true runAsUser: 11211 diff --git a/memcached/manifest.yaml b/memcached/manifest.yaml index b1fba9e..c512286 100644 --- a/memcached/manifest.yaml +++ b/memcached/manifest.yaml @@ -1,9 +1,11 @@ name: memcached -description: Memcached is an in-memory key-value store for small chunks of arbitrary data, commonly used as a cache layer. +description: Memcached is an in-memory key-value store for small chunks of arbitrary + data, commonly used as a cache layer. version: 1.6.32 -icon: https://memcached.org/memcached-logo.png +icon: https://www.vectorlogo.zone/logos/memcached/memcached-icon.svg requires: [] defaultConfig: + namespace: memcached image: memcached:1.6.32-alpine port: 11211 memoryLimit: 64m @@ -16,4 +18,4 @@ defaultConfig: limits: memory: 128Mi cpu: 200m -defaultSecrets: [] \ No newline at end of file +defaultSecrets: [] diff --git a/memcached/namespace.yaml b/memcached/namespace.yaml index 76b7af5..ef059b8 100644 --- a/memcached/namespace.yaml +++ b/memcached/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: memcached \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/memcached/service.yaml b/memcached/service.yaml index 883f1b3..92f8d75 100644 --- a/memcached/service.yaml +++ b/memcached/service.yaml @@ -4,8 +4,8 @@ metadata: name: memcached spec: ports: - - port: {{ .apps.memcached.port }} - targetPort: {{ .apps.memcached.port }} + - port: {{ .port }} + targetPort: {{ .port }} protocol: TCP name: memcached selector: diff --git a/mysql/manifest.yaml b/mysql/manifest.yaml index b5efbdf..8c4aca7 100644 --- a/mysql/manifest.yaml +++ b/mysql/manifest.yaml @@ -4,6 +4,8 @@ version: 9.1.0 icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png requires: [] defaultConfig: + namespace: mysql + externalDnsDomain: '{{ .cloud.domain }}' image: mysql:9.1.0 port: 3306 storage: 20Gi @@ -13,5 +15,5 @@ defaultConfig: timezone: UTC enableSSL: false defaultSecrets: - - key: apps.mysql.rootPassword - - key: apps.mysql.password \ No newline at end of file +- key: rootPassword +- key: password diff --git a/mysql/namespace.yaml b/mysql/namespace.yaml index c31f271..ef059b8 100644 --- a/mysql/namespace.yaml +++ b/mysql/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: mysql \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/mysql/service-headless.yaml b/mysql/service-headless.yaml index 06b2b36..9882959 100644 --- a/mysql/service-headless.yaml +++ b/mysql/service-headless.yaml @@ -9,7 +9,7 @@ spec: publishNotReadyAddresses: true ports: - name: mysql - port: {{ .apps.mysql.port }} + port: {{ .port }} protocol: TCP targetPort: mysql selector: diff --git a/mysql/service.yaml b/mysql/service.yaml index 38e53a0..a385378 100644 --- a/mysql/service.yaml +++ b/mysql/service.yaml @@ -7,7 +7,7 @@ spec: type: ClusterIP ports: - name: mysql - port: {{ .apps.mysql.port }} + port: {{ .port }} protocol: TCP targetPort: mysql selector: diff --git a/mysql/statefulset.yaml b/mysql/statefulset.yaml index 527e222..3386c72 100644 --- a/mysql/statefulset.yaml +++ b/mysql/statefulset.yaml @@ -29,7 +29,7 @@ spec: type: RuntimeDefault containers: - name: mysql - image: {{ .apps.mysql.image }} + image: {{ .image }} imagePullPolicy: IfNotPresent securityContext: allowPrivilegeEscalation: false @@ -42,21 +42,21 @@ spec: valueFrom: secretKeyRef: name: mysql-secrets - key: apps.mysql.rootPassword + key: rootPassword - name: MYSQL_USER - value: {{ .apps.mysql.user }} + value: {{ .user }} - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: mysql-secrets - key: apps.mysql.password + key: password - name: MYSQL_DATABASE - value: {{ .apps.mysql.dbName }} + value: {{ .dbName }} - name: TZ - value: {{ .apps.mysql.timezone }} + value: {{ .timezone }} ports: - name: mysql - containerPort: {{ .apps.mysql.port }} + containerPort: {{ .port }} protocol: TCP livenessProbe: exec: @@ -113,4 +113,4 @@ spec: - ReadWriteOnce resources: requests: - storage: {{ .apps.mysql.storage }} \ No newline at end of file + storage: {{ .storage }} \ No newline at end of file diff --git a/open-webui/deployment.yaml b/open-webui/deployment.yaml index 1721522..1fc9b3a 100644 --- a/open-webui/deployment.yaml +++ b/open-webui/deployment.yaml @@ -45,7 +45,7 @@ spec: valueFrom: secretKeyRef: name: open-webui-secrets - key: apps.openWebui.secretKey + key: openWebui.secretKey volumeMounts: - name: data mountPath: /app/backend/data diff --git a/open-webui/ingress.yaml b/open-webui/ingress.yaml index 2af0ff8..3deb83f 100644 --- a/open-webui/ingress.yaml +++ b/open-webui/ingress.yaml @@ -4,12 +4,12 @@ kind: Ingress metadata: name: open-webui annotations: - external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" traefik.ingress.kubernetes.io/router.middlewares: crowdsec-crowdsec-bouncer@kubernetescrd,crowdsec-rate-limit@kubernetescrd spec: rules: - - host: {{ .apps.open-webui.domain }} + - host: {{ .domain }} http: paths: - path: / @@ -22,4 +22,4 @@ spec: tls: - secretName: wildcard-wild-cloud-tls hosts: - - {{ .apps.open-webui.domain }} \ No newline at end of file + - {{ .domain }} \ No newline at end of file diff --git a/open-webui/manifest.yaml b/open-webui/manifest.yaml index 6cd78dd..98a5017 100644 --- a/open-webui/manifest.yaml +++ b/open-webui/manifest.yaml @@ -1,17 +1,18 @@ name: openWebui -description: Open WebUI is a comprehensive, open-source web interface for AI models. Features a user-friendly design, supports various LLM runners, and operates entirely offline. Perfect for creating a ChatGPT-like experience with local or hosted models. +description: Open WebUI is a comprehensive, open-source web interface for AI models. + Features a user-friendly design, supports various LLM runners, and operates entirely + offline. Perfect for creating a ChatGPT-like experience with local or hosted models. version: 0.4.5 -icon: https://docs.openwebui.com/assets/logo-dark.png +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/open-webui.svg requires: [] defaultConfig: + namespace: open-webui + externalDnsDomain: '{{ .cloud.domain }}' image: ghcr.io/open-webui/open-webui:main port: 8080 storage: 10Gi domain: chat.{{ .cloud.domain }} - # vLLM integration - connect to existing vLLM service vllmApiUrl: http://vllm-service.llm.svc.cluster.local:8000/v1 - # Authentication settings enableAuth: true enableSignup: false -defaultSecrets: - - key: apps.openWebui.secretKey \ No newline at end of file +defaultSecrets: [] diff --git a/open-webui/namespace.yaml b/open-webui/namespace.yaml index 9c1a599..ef059b8 100644 --- a/open-webui/namespace.yaml +++ b/open-webui/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: open-webui \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/openproject/configmap_core.yaml b/openproject/configmap_core.yaml index 92ff304..6d3cbe5 100644 --- a/openproject/configmap_core.yaml +++ b/openproject/configmap_core.yaml @@ -5,17 +5,17 @@ kind: "ConfigMap" metadata: name: "openproject-core" data: - DATABASE_HOST: "{{ .apps.openproject.dbHostname }}" + DATABASE_HOST: "{{ .dbHostname }}" DATABASE_PORT: "5432" - DATABASE_URL: "postgresql://{{ .apps.openproject.dbUsername }}@{{ .apps.openproject.dbHostname }}:5432/{{ .apps.openproject.dbName }}" - OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: "{{ .apps.openproject.adminPasswordReset }}" - OPENPROJECT_SEED_ADMIN_USER_NAME: "{{ .apps.openproject.adminUserName }}" - OPENPROJECT_SEED_ADMIN_USER_MAIL: "{{ .apps.openproject.adminUserEmail }}" - OPENPROJECT_HTTPS: "{{ .apps.openproject.https }}" - OPENPROJECT_SEED_LOCALE: "{{ .apps.openproject.seedLocale }}" - OPENPROJECT_HOST__NAME: "{{ .apps.openproject.domain }}" - OPENPROJECT_HSTS: "{{ .apps.openproject.hsts }}" - OPENPROJECT_RAILS__CACHE__STORE: "{{ .apps.openproject.cacheStore }}" - OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "{{ .apps.openproject.railsRelativeUrlRoot }}" - POSTGRES_STATEMENT_TIMEOUT: "{{ .apps.openproject.postgresStatementTimeout }}" + DATABASE_URL: "postgresql://{{ .dbUsername }}@{{ .dbHostname }}:5432/{{ .dbName }}" + OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: "{{ .adminPasswordReset }}" + OPENPROJECT_SEED_ADMIN_USER_NAME: "{{ .adminUserName }}" + OPENPROJECT_SEED_ADMIN_USER_MAIL: "{{ .adminUserEmail }}" + OPENPROJECT_HTTPS: "{{ .https }}" + OPENPROJECT_SEED_LOCALE: "{{ .seedLocale }}" + OPENPROJECT_HOST__NAME: "{{ .domain }}" + OPENPROJECT_HSTS: "{{ .hsts }}" + OPENPROJECT_RAILS__CACHE__STORE: "{{ .cacheStore }}" + OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "{{ .railsRelativeUrlRoot }}" + POSTGRES_STATEMENT_TIMEOUT: "{{ .postgresStatementTimeout }}" ... diff --git a/openproject/configmap_memcached.yaml b/openproject/configmap_memcached.yaml index 8b7a4f7..12f5d8c 100644 --- a/openproject/configmap_memcached.yaml +++ b/openproject/configmap_memcached.yaml @@ -5,5 +5,5 @@ kind: "ConfigMap" metadata: name: "openproject-memcached" data: - OPENPROJECT_CACHE__MEMCACHE__SERVER: "{{ .apps.openproject.memcachedHostname }}:{{ .apps.openproject.memcachedPort }}" + OPENPROJECT_CACHE__MEMCACHE__SERVER: "{{ .memcachedHostname }}:{{ .memcachedPort }}" ... diff --git a/openproject/db-init-job.yaml b/openproject/db-init-job.yaml index e20f516..00eb86f 100644 --- a/openproject/db-init-job.yaml +++ b/openproject/db-init-job.yaml @@ -12,7 +12,7 @@ spec: spec: containers: - name: db-init - image: {{ .apps.postgres.image }} + image: postgres:17 command: ["/bin/bash", "-c"] args: - | @@ -36,16 +36,16 @@ spec: valueFrom: secretKeyRef: name: postgres-secrets - key: apps.postgres.password + key: password - name: DB_HOSTNAME - value: "{{ .apps.openproject.dbHostname }}" + value: "{{ .dbHostname }}" - name: DB_DATABASE_NAME - value: "{{ .apps.openproject.dbName }}" + value: "{{ .dbName }}" - name: DB_USERNAME - value: "{{ .apps.openproject.dbUsername }}" + value: "{{ .dbUsername }}" - name: DB_PASSWORD valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.dbPassword + key: dbPassword restartPolicy: OnFailure \ No newline at end of file diff --git a/openproject/ingress.yaml b/openproject/ingress.yaml index f412068..97fe393 100644 --- a/openproject/ingress.yaml +++ b/openproject/ingress.yaml @@ -7,10 +7,10 @@ metadata: spec: tls: - hosts: - - "{{ .apps.openproject.domain }}" + - "{{ .domain }}" secretName: "wildcard-wild-cloud-tls" rules: - - host: "{{ .apps.openproject.domain }}" + - host: "{{ .domain }}" http: paths: - path: / diff --git a/openproject/manifest.yaml b/openproject/manifest.yaml index fa2248f..48bf900 100644 --- a/openproject/manifest.yaml +++ b/openproject/manifest.yaml @@ -1,11 +1,14 @@ name: openproject -description: OpenProject is an open-source project management software that provides comprehensive features for project planning, tracking, and collaboration. +description: OpenProject is an open-source project management software that provides + comprehensive features for project planning, tracking, and collaboration. version: 16.1.1 -icon: https://www.openproject.org/assets/images/openproject-logo.png +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/openproject.svg requires: - - name: postgres - - name: memcached +- name: postgres +- name: memcached defaultConfig: + namespace: openproject + externalDnsDomain: '{{ .cloud.domain }}' serverImage: openproject/openproject:16.1.1-slim timezone: UTC serverPort: 8080 @@ -20,14 +23,15 @@ defaultConfig: hsts: true seedLocale: en adminUserName: OpenProject Admin - adminUserEmail: "{{ .operator.email }}" + adminUserEmail: '{{ .operator.email }}' adminPasswordReset: true postgresStatementTimeout: 120s tmpVolumesStorage: 2Gi tlsSecretName: wildcard-wild-cloud-tls cacheStore: memcache - railsRelativeUrlRoot: "" + railsRelativeUrlRoot: '' defaultSecrets: - - key: apps.openproject.dbPassword - - key: apps.openproject.adminPassword - - key: apps.postgres.password +- key: dbPassword +- key: adminPassword +requiredSecrets: +- postgres.password diff --git a/openproject/namespace.yaml b/openproject/namespace.yaml index 7a93fae..ef059b8 100644 --- a/openproject/namespace.yaml +++ b/openproject/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: openproject \ No newline at end of file + name: "{{ .namespace }}" \ No newline at end of file diff --git a/openproject/persistentvolumeclaim.yaml b/openproject/persistentvolumeclaim.yaml index f4fa35a..2cfbe69 100644 --- a/openproject/persistentvolumeclaim.yaml +++ b/openproject/persistentvolumeclaim.yaml @@ -8,5 +8,5 @@ spec: accessModes: [ReadWriteMany] resources: requests: - storage: "{{ .apps.openproject.storage }}" + storage: "{{ .storage }}" ... diff --git a/openproject/seeder-job.yaml b/openproject/seeder-job.yaml index 8501815..28a865e 100644 --- a/openproject/seeder-job.yaml +++ b/openproject/seeder-job.yaml @@ -27,7 +27,7 @@ spec: accessModes: ["ReadWriteOnce"] resources: requests: - storage: {{ .apps.openproject.tmpVolumesStorage }} + storage: {{ .tmpVolumesStorage }} - name: app-tmp # we can't use emptyDir due to the sticky bit / world writable issue # see: https://github.com/kubernetes/kubernetes/issues/110835 @@ -39,13 +39,13 @@ spec: accessModes: ["ReadWriteOnce"] resources: requests: - storage: {{ .apps.openproject.tmpVolumesStorage }} + storage: {{ .tmpVolumesStorage }} - name: "data" persistentVolumeClaim: claimName: openproject initContainers: - name: check-db-ready - image: "{{ .apps.postgres.image }}" + image: "postgres:17" imagePullPolicy: Always command: [ 'sh', @@ -62,12 +62,12 @@ spec: valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.dbPassword + key: dbPassword - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.adminPassword + key: adminPassword resources: limits: memory: 200Mi @@ -91,7 +91,7 @@ spec: type: RuntimeDefault containers: - name: seeder - image: "{{ .apps.openproject.serverImage }}" + image: "{{ .serverImage }}" imagePullPolicy: Always args: - bash @@ -106,12 +106,12 @@ spec: valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.dbPassword + key: dbPassword - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.adminPassword + key: adminPassword resources: limits: memory: 512Mi diff --git a/openproject/web-deployment.yaml b/openproject/web-deployment.yaml index 7eb1321..b628493 100644 --- a/openproject/web-deployment.yaml +++ b/openproject/web-deployment.yaml @@ -43,7 +43,7 @@ spec: accessModes: ["ReadWriteOnce"] resources: requests: - storage: {{ .apps.openproject.tmpVolumesStorage }} + storage: {{ .tmpVolumesStorage }} - name: app-tmp # we can't use emptyDir due to the sticky bit / world writable issue # see: https://github.com/kubernetes/kubernetes/issues/110835 @@ -55,12 +55,12 @@ spec: accessModes: ["ReadWriteOnce"] resources: requests: - storage: {{ .apps.openproject.tmpVolumesStorage }} + storage: {{ .tmpVolumesStorage }} - name: "data" persistentVolumeClaim: claimName: openproject initContainers: - - name: wait-for-db + - name: wait-for-db securityContext: allowPrivilegeEscalation: false capabilities: @@ -72,8 +72,13 @@ spec: runAsUser: 1000 seccompProfile: type: RuntimeDefault - image: {{ .apps.openproject.serverImage }} + image: postgres:17 imagePullPolicy: Always + command: [ + 'sh', + '-c', + 'until pg_isready -h $DATABASE_HOST -p $DATABASE_PORT; do echo "waiting for database $DATABASE_HOST:$DATABASE_PORT"; sleep 2; done; echo "Database is ready!"' + ] envFrom: - configMapRef: name: openproject-core @@ -84,14 +89,12 @@ spec: valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.dbPassword + key: dbPassword - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.adminPassword - args: - - /app/docker/prod/wait-for-db + key: adminPassword resources: limits: memory: 1Gi @@ -115,7 +118,7 @@ spec: runAsUser: 1000 seccompProfile: type: RuntimeDefault - image: {{ .apps.openproject.serverImage }} + image: {{ .serverImage }} imagePullPolicy: Always envFrom: - configMapRef: @@ -127,12 +130,12 @@ spec: valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.dbPassword + key: dbPassword - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.adminPassword + key: adminPassword args: - /app/docker/prod/web volumeMounts: diff --git a/openproject/worker-deployment.yaml b/openproject/worker-deployment.yaml index fc6cc22..c9247de 100644 --- a/openproject/worker-deployment.yaml +++ b/openproject/worker-deployment.yaml @@ -43,7 +43,7 @@ spec: accessModes: ["ReadWriteOnce"] resources: requests: - storage: {{ .apps.openproject.tmpVolumesStorage }} + storage: {{ .tmpVolumesStorage }} - name: app-tmp # we can't use emptyDir due to the sticky bit / world writable issue # see: https://github.com/kubernetes/kubernetes/issues/110835 @@ -55,7 +55,7 @@ spec: accessModes: ["ReadWriteOnce"] resources: requests: - storage: {{ .apps.openproject.tmpVolumesStorage }} + storage: {{ .tmpVolumesStorage }} - name: "data" persistentVolumeClaim: claimName: openproject @@ -72,8 +72,13 @@ spec: runAsUser: 1000 seccompProfile: type: RuntimeDefault - image: {{ .apps.openproject.serverImage }} + image: postgres:17 imagePullPolicy: Always + command: [ + 'sh', + '-c', + 'until pg_isready -h $DATABASE_HOST -p $DATABASE_PORT; do echo "waiting for database $DATABASE_HOST:$DATABASE_PORT"; sleep 2; done; echo "Database is ready!"' + ] envFrom: - configMapRef: name: openproject-core @@ -84,15 +89,12 @@ spec: valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.dbPassword + key: dbPassword - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.adminPassword - args: - - bash - - /app/docker/prod/wait-for-db + key: adminPassword resources: limits: memory: 1Gi @@ -116,7 +118,7 @@ spec: runAsUser: 1000 seccompProfile: type: RuntimeDefault - image: {{ .apps.openproject.serverImage }} + image: {{ .serverImage }} imagePullPolicy: Always envFrom: - configMapRef: @@ -132,7 +134,7 @@ spec: valueFrom: secretKeyRef: name: openproject-secrets - key: apps.openproject.dbPassword + key: dbPassword - name: "OPENPROJECT_GOOD_JOB_QUEUES" value: "" volumeMounts: diff --git a/redis/manifest.yaml b/redis/manifest.yaml index b0bf720..9de23e9 100644 --- a/redis/manifest.yaml +++ b/redis/manifest.yaml @@ -2,7 +2,7 @@ name: redis install: true description: Redis is an open source, in-memory data structure store, used as a database, cache and message broker. version: 1.0.0 -icon: +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/redis.svg defaultConfig: namespace: redis image: redis:alpine diff --git a/vllm/deployment.yaml b/vllm/deployment.yaml index b366638..d553cf0 100644 --- a/vllm/deployment.yaml +++ b/vllm/deployment.yaml @@ -19,10 +19,10 @@ spec: seccompProfile: type: RuntimeDefault nodeSelector: - nvidia.com/gpu.product: "{{ .apps.vllm.gpuProduct }}" + nvidia.com/gpu.product: "{{ .gpuProduct }}" containers: - name: vllm - image: "{{ .apps.vllm.image }}" + image: "{{ .image }}" imagePullPolicy: IfNotPresent securityContext: allowPrivilegeEscalation: false @@ -31,10 +31,10 @@ spec: - ALL readOnlyRootFilesystem: false args: - - --model={{ .apps.vllm.model }} - - --max-model-len={{ .apps.vllm.maxModelLen }} - - --tensor-parallel-size={{ .apps.vllm.tensorParallelSize }} - - --gpu-memory-utilization={{ .apps.vllm.gpuMemoryUtilization }} + - --model={{ .model }} + - --max-model-len={{ .maxModelLen }} + - --tensor-parallel-size={{ .tensorParallelSize }} + - --gpu-memory-utilization={{ .gpuMemoryUtilization }} {{- if .apps.vllm.enforceEager }} - --enforce-eager=True {{- end }} @@ -48,13 +48,13 @@ spec: containerPort: 8000 resources: requests: - cpu: "{{ .apps.vllm.cpuRequest }}" - memory: "{{ .apps.vllm.memoryRequest }}" - nvidia.com/gpu: {{ .apps.vllm.gpuCount }} + cpu: "{{ .cpuRequest }}" + memory: "{{ .memoryRequest }}" + nvidia.com/gpu: {{ .gpuCount }} limits: - cpu: "{{ .apps.vllm.cpuLimit }}" - memory: "{{ .apps.vllm.memoryLimit }}" - nvidia.com/gpu: {{ .apps.vllm.gpuCount }} + cpu: "{{ .cpuLimit }}" + memory: "{{ .memoryLimit }}" + nvidia.com/gpu: {{ .gpuCount }} readinessProbe: httpGet: path: /v1/models diff --git a/vllm/ingress.yaml b/vllm/ingress.yaml index 5135d2d..5713eb2 100644 --- a/vllm/ingress.yaml +++ b/vllm/ingress.yaml @@ -3,13 +3,13 @@ kind: Ingress metadata: name: vllm annotations: - external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" traefik.ingress.kubernetes.io/router.tls: "true" traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt spec: rules: - - host: {{ .apps.vllm.domain }} + - host: {{ .domain }} http: paths: - path: / @@ -21,5 +21,5 @@ spec: number: 8000 tls: - hosts: - - {{ .apps.vllm.domain }} + - {{ .domain }} secretName: vllm-tls \ No newline at end of file diff --git a/vllm/kustomization.yaml b/vllm/kustomization.yaml index 6f45422..6e02eb5 100644 --- a/vllm/kustomization.yaml +++ b/vllm/kustomization.yaml @@ -1,6 +1,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -namespace: {{ .apps.vllm.namespace }} +namespace: {{ .namespace }} labels: - includeSelectors: true pairs: diff --git a/vllm/manifest.yaml b/vllm/manifest.yaml index 89d88fb..22e1fc6 100644 --- a/vllm/manifest.yaml +++ b/vllm/manifest.yaml @@ -1,21 +1,22 @@ name: vllm -description: vLLM is a fast and easy-to-use library for LLM inference and serving with OpenAI-compatible API +description: vLLM is a fast and easy-to-use library for LLM inference and serving + with OpenAI-compatible API version: 0.5.4 -icon: https://raw.githubusercontent.com/vllm-project/vllm/main/docs/source/assets/logos/vllm-logo-text-light.png +icon: https://unpkg.com/@lobehub/icons-static-png@latest/dark/vllm.png requires: [] defaultConfig: image: vllm/vllm-openai:v0.5.4 model: Qwen/Qwen2.5-7B-Instruct maxModelLen: 8192 tensorParallelSize: 1 - gpuMemoryUtilization: 0.90 + gpuMemoryUtilization: 0.9 enforceEager: true - gpuProduct: "RTX 4090" - cpuRequest: "4" - cpuLimit: "8" - memoryRequest: "16Gi" - memoryLimit: "24Gi" + gpuProduct: RTX 4090 + cpuRequest: '4' + cpuLimit: '8' + memoryRequest: 16Gi + memoryLimit: 24Gi gpuCount: 1 domain: vllm.{{ .cloud.domain }} namespace: llm -defaultSecrets: [] \ No newline at end of file +defaultSecrets: [] diff --git a/vllm/namespace.yaml b/vllm/namespace.yaml index 8fc7d02..6990999 100644 --- a/vllm/namespace.yaml +++ b/vllm/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: {{ .apps.vllm.namespace }} \ No newline at end of file + name: {{ .namespace }} \ No newline at end of file