v2 app deployment--templating mainly in manifest now.

This commit is contained in:
2025-12-31 06:53:17 +00:00
parent 8818d822cf
commit d1304a2630
84 changed files with 630 additions and 607 deletions

View File

@@ -26,8 +26,9 @@ description: Immich is a self-hosted photo and video backup solution that allows
version: 1.0.0 version: 1.0.0
icon: https://immich.app/assets/images/logo.png icon: https://immich.app/assets/images/logo.png
requires: requires:
- name: redis - name: pg
- name: postgres alias: db # Use a different reference name in templates
- name: redis # 'alias' and 'installedAs' default to 'name' value
defaultConfig: defaultConfig:
serverImage: ghcr.io/immich-app/immich-server:release serverImage: ghcr.io/immich-app/immich-server:release
mlImage: ghcr.io/immich-app/immich-machine-learning:release mlImage: ghcr.io/immich-app/immich-machine-learning:release
@@ -36,13 +37,21 @@ defaultConfig:
mlPort: 3003 mlPort: 3003
storage: 250Gi storage: 250Gi
cacheStorage: 10Gi cacheStorage: 10Gi
redisHostname: redis.redis.svc.cluster.local redisHostname: "{{ .apps.redis.host }}" # Can reference 'requires' app configurations
dbHostname: postgres.postgres.svc.cluster.local dbHostname: "{{ .apps.pg.host }}"
dbUsername: immich db: # Configuration can be nested
name: immich
user: immich
host: "{{ .apps.pg.host }}"
port: "{{ .apps.pg.port }}"
domain: immich.{{ .cloud.domain }} domain: immich.{{ .cloud.domain }}
defaultSecrets: defaultSecrets:
- apps.immich.dbPassword - key: password # Random value will be generated if empty
- apps.postgres.password - 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 #### Manifest Fields
@@ -53,11 +62,31 @@ defaultSecrets:
| `description` | Yes | Brief app description shown in listings | | `description` | Yes | Brief app description shown in listings |
| `version` | Yes | App version (follow upstream versioning) | | `version` | Yes | App version (follow upstream versioning) |
| `icon` | No | URL to app icon for UI display | | `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` | | `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: `<app-ref>.<key>`) |
**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.<ref>.* }}` - resolved using app reference mapping
4. App-specific secrets (in 'defaultSecrets' ONLY): `{{ secrets.* }}`
**Manifest App Reference Resolution:**
When you use `{{ .apps.<ref>.* }}` in templates:
1. System checks if `<ref>` matches any dependency's `alias` field
2. If no alias match, checks if `<ref>` 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`) ### Kustomization (`kustomization.yaml`)
@@ -111,21 +140,7 @@ This means individual resources can use simple, component-specific selectors lik
### Gomplate Templating ### 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: 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:
```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.
### External DNS ### External DNS
@@ -133,12 +148,47 @@ Ingress resources should include external-dns annotations for automatic DNS mana
```yaml ```yaml
annotations: annotations:
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} external-dns.alpha.kubernetes.io/target: {{ .domain }}
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" 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`). 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 Patterns
### Database Initialization Jobs ### Database Initialization Jobs
@@ -211,13 +261,16 @@ spec:
### Secrets Management ### 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:** **In manifest:**
```yaml ```yaml
defaultSecrets: defaultSecrets:
- apps.myapp.dbPassword key: dbPassword # This app's database password
- apps.postgres.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:** **In resources:**
@@ -227,14 +280,26 @@ env:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: myapp-secrets 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:** **Secret workflow:**
1. List secrets in manifest's `defaultSecrets` 1. Define app's own secrets in `defaultSecrets` (key, default mappings)
2. When adding an app, the system generates random values in the instance's `secrets.yaml` 2. Reference dependency secrets in `requiredSecrets` (list)
3. When deploying, the system creates a Kubernetes Secret named `<app-name>-secrets` 3. When adding an app, the system:
4. Resources reference secrets using full dotted paths - 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 `<app-name>-secrets` containing:
- All `defaultSecrets` with key format: `<key>`
- All `requiredSecrets` with key format: `<app-ref>.<key>`
**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. **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** - [ ] **Manifest**
- [ ] `name` matches directory name - [ ] `name` matches directory name
- [ ] All required fields present (`name`, `description`, `version`, `defaultConfig`) - [ ] All required fields present (`name`, `description`, `version`, `defaultConfig`)
- [ ] All template variables defined in `defaultConfig` or are standard Wild Cloud variables - [ ] All template variables defined in `defaultConfig`
- [ ] Secrets use dotted-path format (e.g., `apps.appname.secretname`) - [ ] `defaultSecrets` uses maps with 'key' and 'default' attributes
- [ ] Dependencies listed in `requires` (if any) - [ ] `requiredSecrets` references use `<app-ref>.<key>` format
- [ ] Dependencies listed in `requires` with optional `alias` fields
- [ ] Manifest template references match dependency aliases or names
- [ ] **Kustomization** - [ ] **Kustomization**
- [ ] Includes standard Wild Cloud labels with `includeSelectors: true` - [ ] 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:` - [ ] All resource files listed under `resources:`
- [ ] **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) - [ ] Security contexts on all pods (both pod-level and container-level)
- [ ] Simple component labels, no Helm-style labels - [ ] Simple component labels, no Helm-style labels
- [ ] Ingresses include external-dns annotations - [ ] Ingresses include external-dns annotations

View File

@@ -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"

View File

@@ -27,7 +27,7 @@ spec:
readOnlyRootFilesystem: false readOnlyRootFilesystem: false
env: env:
- name: PGHOST - name: PGHOST
value: "{{ .apps.discourse.dbHostname }}" value: "{{ .dbHostname }}"
- name: PGPORT - name: PGPORT
value: "5432" value: "5432"
- name: PGUSER - name: PGUSER
@@ -36,16 +36,16 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: apps.postgres.password key: postgres.password
- name: DISCOURSE_DB_USER - name: DISCOURSE_DB_USER
value: "{{ .apps.discourse.dbUsername }}" value: "{{ .dbUsername }}"
- name: DISCOURSE_DB_NAME - name: DISCOURSE_DB_NAME
value: "{{ .apps.discourse.dbName }}" value: "{{ .dbName }}"
- name: DISCOURSE_DB_PASSWORD - name: DISCOURSE_DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: apps.discourse.dbPassword key: dbPassword
command: command:
- /bin/sh - /bin/sh
- -c - -c

View File

@@ -1,5 +1,4 @@
--- ---
# Source: discourse/templates/deployment.yaml
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
@@ -18,219 +17,133 @@ spec:
component: web component: web
spec: spec:
automountServiceAccountToken: false automountServiceAccountToken: false
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels:
component: web
topologyKey: kubernetes.io/hostname
weight: 1
serviceAccountName: discourse serviceAccountName: discourse
securityContext: securityContext:
fsGroup: 0 fsGroup: 0
fsGroupChangePolicy: Always fsGroupChangePolicy: Always
supplementalGroups: []
sysctls: []
initContainers:
containers: containers:
- name: discourse - name: discourse
image: docker.io/bitnami/discourse:3.4.7-debian-12-r0 image: tiredofit/discourse:latest
imagePullPolicy: "IfNotPresent" imagePullPolicy: "IfNotPresent"
securityContext: securityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities: capabilities:
drop:
- ALL
add: add:
- CHOWN - CHOWN
- SYS_CHROOT - DAC_OVERRIDE
- FOWNER - FOWNER
- SETGID - SETGID
- SETUID - SETUID
- DAC_OVERRIDE
drop:
- ALL
privileged: false privileged: false
readOnlyRootFilesystem: false readOnlyRootFilesystem: false
runAsGroup: 0
runAsNonRoot: false runAsNonRoot: false
runAsUser: 0 runAsUser: 0
seLinuxOptions: {}
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
env: env:
- name: BITNAMI_DEBUG # Admin configuration
value: "false" - name: ADMIN_USER
- name: DISCOURSE_PASSWORD value: {{ .adminUsername }}
- name: ADMIN_EMAIL
value: {{ .adminEmail }}
- name: ADMIN_PASS
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: apps.discourse.adminPassword key: adminPassword
- name: DISCOURSE_PORT_NUMBER # Site configuration
value: "8080" - name: SITE_TITLE
- name: DISCOURSE_EXTERNAL_HTTP_PORT_NUMBER value: {{ .siteName }}
value: "80" - name: HOSTNAME
- name: DISCOURSE_DATABASE_PASSWORD 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: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: apps.discourse.dbPassword key: dbPassword
- name: POSTGRESQL_CLIENT_CREATE_DATABASE_PASSWORD # Redis configuration
- name: REDIS_HOST
value: {{ .redisHostname }}
- name: REDIS_PASS
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: apps.discourse.dbPassword key: redis.password
- name: DISCOURSE_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: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: apps.redis.password key: smtpPassword
- name: DISCOURSE_SECRET_KEY_BASE - name: SMTP_TLS
valueFrom: value: "{{ .smtp.tls }}"
secretKeyRef: # Container timezone
name: discourse-secrets - name: TZ
key: apps.discourse.secretKeyBase value: {{ .timezone }}
- 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
ports: ports:
- name: http - name: http
containerPort: 8080 containerPort: 3000
protocol: TCP protocol: TCP
livenessProbe: livenessProbe:
tcpSocket: httpGet:
path: /
port: http port: http
initialDelaySeconds: 500 initialDelaySeconds: 420
periodSeconds: 10 periodSeconds: 30
timeoutSeconds: 5 timeoutSeconds: 10
successThreshold: 1 successThreshold: 1
failureThreshold: 6 failureThreshold: 6
readinessProbe: readinessProbe:
httpGet: httpGet:
path: /srv/status path: /
port: http port: http
initialDelaySeconds: 180 initialDelaySeconds: 360
periodSeconds: 10 periodSeconds: 30
timeoutSeconds: 5 timeoutSeconds: 10
successThreshold: 1 successThreshold: 1
failureThreshold: 6 failureThreshold: 6
resources: resources:
limits: limits:
cpu: 1 cpu: 2000m
ephemeral-storage: 2Gi ephemeral-storage: 10Gi
memory: 8Gi # for precompiling assets! memory: 4Gi
requests: requests:
cpu: 750m cpu: 500m
ephemeral-storage: 50Mi ephemeral-storage: 50Mi
memory: 1Gi memory: 1Gi
volumeMounts: volumeMounts:
- name: discourse-data - name: discourse-logs
mountPath: /bitnami/discourse mountPath: /data/logs
subPath: discourse - name: discourse-uploads
- name: sidekiq mountPath: /data/uploads
image: docker.io/bitnami/discourse:3.4.7-debian-12-r0 - name: discourse-backups
imagePullPolicy: "IfNotPresent" mountPath: /data/backups
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
volumes: volumes:
- name: discourse-data - name: discourse-logs
persistentVolumeClaim: persistentVolumeClaim:
claimName: discourse claimName: discourse-logs
- name: discourse-uploads
persistentVolumeClaim:
claimName: discourse-uploads
- name: discourse-backups
persistentVolumeClaim:
claimName: discourse-backups

View File

@@ -4,13 +4,13 @@ apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: discourse name: discourse
namespace: "discourse" namespace: "{{ .namespace }}"
annotations: annotations:
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}" external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}"
spec: spec:
rules: rules:
- host: "{{ .apps.discourse.domain }}" - host: "{{ .domain }}"
http: http:
paths: paths:
- path: / - path: /
@@ -22,5 +22,5 @@ spec:
name: http name: http
tls: tls:
- hosts: - hosts:
- "{{ .apps.discourse.domain }}" - "{{ .domain }}"
secretName: wildcard-external-wild-cloud-tls secretName: wildcard-external-wild-cloud-tls

View File

@@ -10,7 +10,6 @@ labels:
resources: resources:
- namespace.yaml - namespace.yaml
- serviceaccount.yaml - serviceaccount.yaml
- configmap.yaml
- pvc.yaml - pvc.yaml
- deployment.yaml - deployment.yaml
- service.yaml - service.yaml

View File

@@ -1,22 +1,25 @@
name: discourse name: discourse
description: Discourse is a modern, open-source discussion platform designed for online communities and forums. description: Discourse is a modern, open-source discussion platform designed for online communities and forums.
version: 3.4.7 version: 3.5.3
icon: https://www.discourse.org/img/icon.png icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/discourse.svg
requires: requires:
- name: postgres - name: postgres
- name: redis - name: redis
defaultConfig: defaultConfig:
namespace: discourse
externalDnsDomain: "{{ .cloud.domain }}"
timezone: UTC timezone: UTC
port: 8080 port: 3000
storage: 10Gi storage: 10Gi
adminEmail: admin@{{ .cloud.domain }} adminEmail: "{{ .operator.email }}"
adminUsername: admin adminUsername: admin
siteName: "Community" siteName: "Community"
domain: discourse.{{ .cloud.domain }} domain: discourse.{{ .cloud.domain }}
dbHostname: postgres.postgres.svc.cluster.local dbHostname: "{{ .apps.postgres.host }}"
dbPort: "{{ .apps.postgres.port }}"
dbUsername: discourse dbUsername: discourse
dbName: discourse dbName: discourse
redisHostname: redis.redis.svc.cluster.local redisHostname: "{{ .apps.redis.host }}"
tlsSecretName: wildcard-wild-cloud-tls tlsSecretName: wildcard-wild-cloud-tls
smtp: smtp:
enabled: false enabled: false
@@ -24,13 +27,16 @@ defaultConfig:
port: "{{ .cloud.smtp.port }}" port: "{{ .cloud.smtp.port }}"
user: "{{ .cloud.smtp.user }}" user: "{{ .cloud.smtp.user }}"
from: "{{ .cloud.smtp.from }}" from: "{{ .cloud.smtp.from }}"
tls: {{ .cloud.smtp.tls }} tls: "{{ .cloud.smtp.tls }}"
startTls: {{ .cloud.smtp.startTls }} startTls: "{{ .cloud.smtp.startTls }}"
defaultSecrets: defaultSecrets:
- - key: apps.discourse.adminPassword - key: adminPassword
- - key: apps.discourse.dbPassword - key: secretKeyBase
- - key: apps.discourse.dbUrl default: "{{ random.AlphaNum 64 }}"
- - key: apps.redis.password - key: smtpPassword
- - key: apps.discourse.secretKeyBase - key: dbPassword
- - key: apps.discourse.smtpPassword - key: dbUrl
- - key: apps.postgres.password default: "postgres://{{ .app.dbUsername }}:{{ .secrets.dbPassword }}@{{ .app.dbHostname }}:{{ .app.dbPort }}/{{ .app.dbName }}?sslmode=disable"
requiredSecrets:
- postgres.password
- redis.password

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: discourse name: "{{ .namespace }}"

View File

@@ -1,13 +1,39 @@
--- ---
# Source: discourse/templates/pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1 apiVersion: v1
kind: PersistentVolumeClaim
metadata: metadata:
name: discourse name: discourse-logs
namespace: discourse namespace: discourse
spec: spec:
accessModes: accessModes:
- "ReadWriteOnce" - ReadWriteOnce
resources: resources:
requests: 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

View File

@@ -3,7 +3,6 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: example-admin name: example-admin
namespace: example-admin
labels: labels:
app: example-admin app: example-admin
spec: spec:

View File

@@ -3,10 +3,9 @@ apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: example-admin name: example-admin
namespace: example-admin
spec: spec:
rules: rules:
- host: example-admin.{{ .cloud.internalDomain }} - host: "{{ .host }}"
http: http:
paths: paths:
- path: / - path: /
@@ -18,5 +17,5 @@ spec:
number: 80 number: 80
tls: tls:
- hosts: - hosts:
- example-admin.{{ .cloud.internalDomain }} - "{{ .host }}"
secretName: wildcard-internal-wild-cloud-tls secretName: wildcard-internal-wild-cloud-tls

View File

@@ -3,4 +3,7 @@ install: true
description: An example application that is deployed with internal-only access. description: An example application that is deployed with internal-only access.
version: 1.0.0 version: 1.0.0
defaultConfig: defaultConfig:
namespace: example-admin
externalDnsDomain: '{{ .cloud.domain }}'
host: '{{ .host }}'
tlsSecretName: wildcard-internal-wild-cloud-tls tlsSecretName: wildcard-internal-wild-cloud-tls

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: example-admin name: "{{ .namespace }}"

View File

@@ -4,7 +4,7 @@ kind: Ingress
metadata: metadata:
name: example-app name: example-app
annotations: 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 external-dns.alpha.kubernetes.io/cloudflare-proxied: false
# Optional: Enable HTTPS redirection # Optional: Enable HTTPS redirection
@@ -15,7 +15,7 @@ metadata:
# traefik.ingress.kubernetes.io/auth-secret: basic-auth # traefik.ingress.kubernetes.io/auth-secret: basic-auth
spec: spec:
rules: rules:
- host: example-app.{{ .cloud.domain }} - host: "{{ .host }}"
http: http:
paths: paths:
- path: / - path: /
@@ -27,5 +27,5 @@ spec:
number: 80 number: 80
tls: tls:
- hosts: - hosts:
- example-app.{{ .cloud.domain }} - "{{ .host }}"
secretName: wildcard-wild-cloud-tls secretName: wildcard-wild-cloud-tls

View File

@@ -3,4 +3,7 @@ install: true
description: An example application that is deployed with public access. description: An example application that is deployed with public access.
version: 1.0.0 version: 1.0.0
defaultConfig: defaultConfig:
namespace: example-app
externalDnsDomain: '{{ .cloud.domain }}'
host: example-app.{{ .cloud.domain }}
tlsSecretName: wildcard-wild-cloud-tls tlsSecretName: wildcard-wild-cloud-tls

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: example-app name: "{{ .namespace }}"

View File

@@ -12,7 +12,7 @@ spec:
spec: spec:
containers: containers:
- name: db-init - name: db-init
image: {{ .apps.mysql.image }} image: mysql:9.1.0
command: ["/bin/bash", "-c"] command: ["/bin/bash", "-c"]
args: args:
- | - |
@@ -27,18 +27,18 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: mysql-secrets name: mysql-secrets
key: apps.mysql.rootPassword key: rootPassword
- name: DB_HOSTNAME - name: DB_HOSTNAME
value: "{{ .apps.ghost.dbHost }}" value: "{{ .dbHost }}"
- name: DB_PORT - name: DB_PORT
value: "{{ .apps.ghost.dbPort }}" value: "{{ .dbPort }}"
- name: DB_DATABASE_NAME - name: DB_DATABASE_NAME
value: "{{ .apps.ghost.dbName }}" value: "{{ .dbName }}"
- name: DB_USERNAME - name: DB_USERNAME
value: "{{ .apps.ghost.dbUser }}" value: "{{ .dbUser }}"
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: ghost-secrets name: ghost-secrets
key: apps.ghost.dbPassword key: dbPassword
restartPolicy: OnFailure restartPolicy: OnFailure

View File

@@ -17,10 +17,10 @@ spec:
spec: spec:
containers: containers:
- name: ghost - name: ghost
image: {{ .apps.ghost.image }} image: {{ .image }}
ports: ports:
- name: http - name: http
containerPort: {{ .apps.ghost.port }} containerPort: {{ .port }}
protocol: TCP protocol: TCP
env: env:
- name: BITNAMI_DEBUG - name: BITNAMI_DEBUG
@@ -28,33 +28,33 @@ spec:
- name: ALLOW_EMPTY_PASSWORD - name: ALLOW_EMPTY_PASSWORD
value: "yes" value: "yes"
- name: GHOST_DATABASE_HOST - name: GHOST_DATABASE_HOST
value: {{ .apps.ghost.dbHost }} value: {{ .dbHost }}
- name: GHOST_DATABASE_PORT_NUMBER - name: GHOST_DATABASE_PORT_NUMBER
value: "{{ .apps.ghost.dbPort }}" value: "{{ .dbPort }}"
- name: GHOST_DATABASE_NAME - name: GHOST_DATABASE_NAME
value: {{ .apps.ghost.dbName }} value: {{ .dbName }}
- name: GHOST_DATABASE_USER - name: GHOST_DATABASE_USER
value: {{ .apps.ghost.dbUser }} value: {{ .dbUser }}
- name: GHOST_DATABASE_PASSWORD - name: GHOST_DATABASE_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: ghost-secrets name: ghost-secrets
key: apps.ghost.dbPassword key: dbPassword
- name: GHOST_HOST - name: GHOST_HOST
value: {{ .apps.ghost.domain }} value: {{ .domain }}
- name: GHOST_PORT_NUMBER - name: GHOST_PORT_NUMBER
value: "{{ .apps.ghost.port }}" value: "{{ .port }}"
- name: GHOST_USERNAME - name: GHOST_USERNAME
value: {{ .apps.ghost.adminUser }} value: {{ .adminUser }}
- name: GHOST_PASSWORD - name: GHOST_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: ghost-secrets name: ghost-secrets
key: apps.ghost.adminPassword key: adminPassword
- name: GHOST_EMAIL - name: GHOST_EMAIL
value: {{ .apps.ghost.adminEmail }} value: {{ .adminEmail }}
- name: GHOST_BLOG_TITLE - name: GHOST_BLOG_TITLE
value: {{ .apps.ghost.blogTitle }} value: {{ .blogTitle }}
- name: GHOST_ENABLE_HTTPS - name: GHOST_ENABLE_HTTPS
value: "yes" value: "yes"
- name: GHOST_EXTERNAL_HTTP_PORT_NUMBER - name: GHOST_EXTERNAL_HTTP_PORT_NUMBER
@@ -66,18 +66,18 @@ spec:
- name: GHOST_SMTP_SERVICE - name: GHOST_SMTP_SERVICE
value: SMTP value: SMTP
- name: GHOST_SMTP_HOST - name: GHOST_SMTP_HOST
value: {{ .apps.ghost.smtp.host }} value: {{ .smtp.host }}
- name: GHOST_SMTP_PORT - name: GHOST_SMTP_PORT
value: "{{ .apps.ghost.smtp.port }}" value: "{{ .smtp.port }}"
- name: GHOST_SMTP_USER - name: GHOST_SMTP_USER
value: {{ .apps.ghost.smtp.user }} value: {{ .smtp.user }}
- name: GHOST_SMTP_PASSWORD - name: GHOST_SMTP_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: ghost-secrets name: ghost-secrets
key: apps.ghost.smtpPassword key: smtpPassword
- name: GHOST_SMTP_FROM_ADDRESS - name: GHOST_SMTP_FROM_ADDRESS
value: {{ .apps.ghost.smtp.from }} value: {{ .smtp.from }}
resources: resources:
limits: limits:
cpu: 375m cpu: 375m
@@ -92,7 +92,7 @@ spec:
mountPath: /bitnami/ghost mountPath: /bitnami/ghost
livenessProbe: livenessProbe:
tcpSocket: tcpSocket:
port: {{ .apps.ghost.port }} port: {{ .port }}
initialDelaySeconds: 120 initialDelaySeconds: 120
timeoutSeconds: 5 timeoutSeconds: 5
periodSeconds: 10 periodSeconds: 10

View File

@@ -7,12 +7,12 @@ metadata:
kubernetes.io/ingress.class: "traefik" kubernetes.io/ingress.class: "traefik"
cert-manager.io/cluster-issuer: "letsencrypt-prod" cert-manager.io/cluster-issuer: "letsencrypt-prod"
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" 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" external-dns.alpha.kubernetes.io/ttl: "60"
traefik.ingress.kubernetes.io/redirect-entry-point: https traefik.ingress.kubernetes.io/redirect-entry-point: https
spec: spec:
rules: rules:
- host: {{ .apps.ghost.domain }} - host: {{ .domain }}
http: http:
paths: paths:
- path: / - path: /
@@ -24,5 +24,5 @@ spec:
number: 80 number: 80
tls: tls:
- hosts: - hosts:
- {{ .apps.ghost.domain }} - {{ .domain }}
secretName: {{ .apps.ghost.tlsSecretName }} secretName: {{ .tlsSecretName }}

View File

@@ -1,10 +1,13 @@
name: ghost 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 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: requires:
- name: mysql - name: mysql
defaultConfig: defaultConfig:
namespace: ghost
externalDnsDomain: '{{ .cloud.domain }}'
image: docker.io/bitnami/ghost:5.118.1-debian-12-r0 image: docker.io/bitnami/ghost:5.118.1-debian-12-r0
domain: ghost.{{ .cloud.domain }} domain: ghost.{{ .cloud.domain }}
tlsSecretName: wildcard-wild-cloud-tls tlsSecretName: wildcard-wild-cloud-tls
@@ -15,16 +18,17 @@ defaultConfig:
dbName: ghost dbName: ghost
dbUser: ghost dbUser: ghost
adminUser: admin adminUser: admin
adminEmail: "admin@{{ .cloud.domain }}" adminEmail: {{ .operator.email }}
blogTitle: "My Blog" blogTitle: My Blog
timezone: UTC timezone: UTC
tlsSecretName: wildcard-wild-cloud-tls
smtp: smtp:
host: "{{ .cloud.smtp.host }}" host: '{{ .cloud.smtp.host }}'
port: "{{ .cloud.smtp.port }}" port: '{{ .cloud.smtp.port }}'
from: "{{ .cloud.smtp.from }}" from: '{{ .cloud.smtp.from }}'
user: "{{ .cloud.smtp.user }}" user: '{{ .cloud.smtp.user }}'
defaultSecrets: defaultSecrets:
- key: apps.ghost.adminPassword - key: adminPassword
- key: apps.ghost.dbPassword - key: dbPassword
- key: apps.ghost.smtpPassword - key: smtpPassword
requiredSecrets:
- mysql.rootPassword

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: ghost name: "{{ .namespace }}"

View File

@@ -8,4 +8,4 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: {{ .apps.ghost.storage }} storage: {{ .storage }}

View File

@@ -9,6 +9,6 @@ spec:
- name: http - name: http
port: 80 port: 80
protocol: TCP protocol: TCP
targetPort: {{ .apps.ghost.port }} targetPort: {{ .port }}
selector: selector:
component: web component: web

View File

@@ -12,7 +12,7 @@ spec:
spec: spec:
containers: containers:
- name: db-init - name: db-init
image: {{ .apps.postgres.image }} image: postgres:17
command: ["/bin/bash", "-c"] command: ["/bin/bash", "-c"]
args: args:
- | - |
@@ -36,16 +36,16 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: postgres-secrets name: postgres-secrets
key: apps.postgres.password key: password
- name: DB_HOSTNAME - name: DB_HOSTNAME
value: "{{ .apps.gitea.dbHost }}" value: "{{ .dbHost }}"
- name: DB_DATABASE_NAME - name: DB_DATABASE_NAME
value: "{{ .apps.gitea.dbName }}" value: "{{ .dbName }}"
- name: DB_USERNAME - name: DB_USERNAME
value: "{{ .apps.gitea.dbUser }}" value: "{{ .dbUser }}"
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: gitea-secrets name: gitea-secrets
key: apps.gitea.dbPassword key: dbPassword
restartPolicy: OnFailure restartPolicy: OnFailure

View File

@@ -23,7 +23,7 @@ spec:
terminationGracePeriodSeconds: 60 terminationGracePeriodSeconds: 60
containers: containers:
- name: gitea - name: gitea
image: "{{ .apps.gitea.image }}" image: "{{ .image }}"
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
envFrom: envFrom:
- configMapRef: - configMapRef:
@@ -33,27 +33,27 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: gitea-secrets name: gitea-secrets
key: apps.gitea.adminPassword key: adminPassword
- name: GITEA__security__SECRET_KEY - name: GITEA__security__SECRET_KEY
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: gitea-secrets name: gitea-secrets
key: apps.gitea.secretKey key: secretKey
- name: GITEA__security__INTERNAL_TOKEN - name: GITEA__security__INTERNAL_TOKEN
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: gitea-secrets name: gitea-secrets
key: apps.gitea.jwtSecret key: jwtSecret
- name: GITEA__database__PASSWD - name: GITEA__database__PASSWD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: gitea-secrets name: gitea-secrets
key: apps.gitea.dbPassword key: dbPassword
- name: GITEA__mailer__PASSWD - name: GITEA__mailer__PASSWD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: gitea-secrets name: gitea-secrets
key: apps.gitea.smtpPassword key: smtpPassword
ports: ports:
- name: ssh - name: ssh
containerPort: 2222 containerPort: 2222

View File

@@ -3,12 +3,12 @@ SSH_PORT=22
GITEA_WORK_DIR=/data GITEA_WORK_DIR=/data
GITEA_TEMP=/tmp/gitea GITEA_TEMP=/tmp/gitea
TMPDIR=/tmp/gitea TMPDIR=/tmp/gitea
GITEA_ADMIN_USERNAME={{ .apps.gitea.adminUser }} GITEA_ADMIN_USERNAME={{ .adminUser }}
GITEA_ADMIN_PASSWORD_MODE=keepUpdated GITEA_ADMIN_PASSWORD_MODE=keepUpdated
# Core app settings # Core app settings
GITEA____APP_NAME={{ .apps.gitea.appName }} GITEA____APP_NAME={{ .appName }}
GITEA____RUN_MODE={{ .apps.gitea.runMode }} GITEA____RUN_MODE={{ .runMode }}
GITEA____RUN_USER=git GITEA____RUN_USER=git
# Security settings # Security settings
@@ -17,19 +17,19 @@ GITEA__security__PASSWORD_HASH_ALGO=pbkdf2
# Database settings (except password which comes from secret) # Database settings (except password which comes from secret)
GITEA__database__DB_TYPE=postgres GITEA__database__DB_TYPE=postgres
GITEA__database__HOST={{ .apps.gitea.dbHost }}:{{ .apps.gitea.dbPort }} GITEA__database__HOST={{ .dbHost }}:{{ .dbPort }}
GITEA__database__NAME={{ .apps.gitea.dbName }} GITEA__database__NAME={{ .dbName }}
GITEA__database__USER={{ .apps.gitea.dbUser }} GITEA__database__USER={{ .dbUser }}
GITEA__database__SSL_MODE=disable GITEA__database__SSL_MODE=disable
GITEA__database__LOG_SQL=false GITEA__database__LOG_SQL=false
# Server settings # Server settings
GITEA__server__DOMAIN={{ .apps.gitea.domain }} GITEA__server__DOMAIN={{ .domain }}
GITEA__server__HTTP_PORT={{ .apps.gitea.port }} GITEA__server__HTTP_PORT={{ .port }}
GITEA__server__ROOT_URL=https://{{ .apps.gitea.domain }}/ GITEA__server__ROOT_URL=https://{{ .domain }}/
GITEA__server__DISABLE_SSH=false GITEA__server__DISABLE_SSH=false
GITEA__server__SSH_DOMAIN={{ .apps.gitea.domain }} GITEA__server__SSH_DOMAIN={{ .domain }}
GITEA__server__SSH_PORT={{ .apps.gitea.sshPort }} GITEA__server__SSH_PORT={{ .sshPort }}
GITEA__server__SSH_LISTEN_PORT=2222 GITEA__server__SSH_LISTEN_PORT=2222
GITEA__server__LFS_START_SERVER=true GITEA__server__LFS_START_SERVER=true
GITEA__server__OFFLINE_MODE=true GITEA__server__OFFLINE_MODE=true
@@ -53,8 +53,8 @@ GITEA__webhook__ALLOWED_HOST_LIST=*
# Mailer settings (enabled via env vars, password from secret) # Mailer settings (enabled via env vars, password from secret)
GITEA__mailer__ENABLED=true GITEA__mailer__ENABLED=true
GITEA__mailer__SMTP_ADDR={{ .apps.gitea.smtp.host }} GITEA__mailer__SMTP_ADDR={{ .smtp.host }}
GITEA__mailer__SMTP_PORT={{ .apps.gitea.smtp.port }} GITEA__mailer__SMTP_PORT={{ .smtp.port }}
GITEA__mailer__FROM={{ .apps.gitea.smtp.from }} GITEA__mailer__FROM={{ .smtp.from }}
GITEA__mailer__USER={{ .apps.gitea.smtp.user }} GITEA__mailer__USER={{ .smtp.user }}

View File

@@ -5,10 +5,10 @@ metadata:
namespace: gitea namespace: gitea
annotations: annotations:
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}" external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}"
spec: spec:
rules: rules:
- host: "{{ .apps.gitea.domain }}" - host: "{{ .domain }}"
http: http:
paths: paths:
- path: / - path: /
@@ -19,6 +19,6 @@ spec:
port: port:
number: 3000 number: 3000
tls: tls:
- secretName: "{{ .apps.gitea.tlsSecretName }}" - secretName: "{{ .tlsSecretName }}"
hosts: hosts:
- "{{ .apps.gitea.domain }}" - "{{ .domain }}"

View File

@@ -1,10 +1,12 @@
name: gitea name: gitea
description: Gitea is a painless self-hosted Git service written in Go description: Gitea is a painless self-hosted Git service written in Go
version: 1.24.3 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: requires:
- name: postgres - name: postgres
defaultConfig: defaultConfig:
namespace: gitea
externalDnsDomain: '{{ .cloud.domain }}'
image: gitea/gitea:1.24.3 image: gitea/gitea:1.24.3
appName: Gitea appName: Gitea
domain: gitea.{{ .cloud.domain }} domain: gitea.{{ .cloud.domain }}
@@ -16,18 +18,20 @@ defaultConfig:
dbUser: gitea dbUser: gitea
dbHost: postgres.postgres.svc.cluster.local dbHost: postgres.postgres.svc.cluster.local
adminUser: admin adminUser: admin
adminEmail: "admin@{{ .cloud.domain }}" adminEmail: "{{ .operator.email }}"
dbPort: 5432 dbPort: 5432
timezone: UTC timezone: UTC
runMode: prod runMode: prod
smtp: smtp:
host: "{{ .cloud.smtp.host }}" host: '{{ .cloud.smtp.host }}'
port: "{{ .cloud.smtp.port }}" port: '{{ .cloud.smtp.port }}'
user: "{{ .cloud.smtp.user }}" user: '{{ .cloud.smtp.user }}'
from: "{{ .cloud.smtp.from }}" from: '{{ .cloud.smtp.from }}'
defaultSecrets: defaultSecrets:
- key: apps.gitea.adminPassword - key: adminPassword
- key: apps.gitea.dbPassword - key: dbPassword
- key: apps.gitea.secretKey - key: secretKey
- key: apps.gitea.jwtSecret - key: jwtSecret
- key: apps.gitea.smtpPassword - key: smtpPassword
requiredSecrets:
- postgres.password

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: gitea name: "{{ .namespace }}"

View File

@@ -9,4 +9,4 @@ spec:
storageClassName: longhorn storageClassName: longhorn
resources: resources:
requests: requests:
storage: "{{ .apps.gitea.storage }}" storage: "{{ .storage }}"

View File

@@ -8,7 +8,7 @@ spec:
ports: ports:
- name: http - name: http
port: 3000 port: 3000
targetPort: {{ .apps.gitea.port }} targetPort: {{ .port }}
selector: selector:
component: web component: web
--- ---
@@ -21,7 +21,7 @@ spec:
type: LoadBalancer type: LoadBalancer
ports: ports:
- name: ssh - name: ssh
port: {{ .apps.gitea.sshPort }} port: {{ .sshPort }}
targetPort: 2222 targetPort: 2222
protocol: TCP protocol: TCP
selector: selector:

View File

@@ -7,7 +7,7 @@ spec:
spec: spec:
containers: containers:
- name: db-init - name: db-init
image: {{ .apps.postgres.image }} image: postgres:17
command: ["/bin/bash", "-c"] command: ["/bin/bash", "-c"]
args: args:
- | - |
@@ -53,16 +53,16 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: immich-secrets name: immich-secrets
key: apps.postgres.password key: postgres.password
- name: DB_HOSTNAME - name: DB_HOSTNAME
value: "{{ .apps.immich.dbHostname }}" value: "{{ .dbHostname }}"
- name: DB_DATABASE_NAME - name: DB_DATABASE_NAME
value: "{{ .apps.immich.dbUsername }}" value: "{{ .dbUsername }}"
- name: DB_USERNAME - name: DB_USERNAME
value: "{{ .apps.immich.dbUsername }}" value: "{{ .dbUsername }}"
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: immich-secrets name: immich-secrets
key: apps.immich.dbPassword key: dbPassword
restartPolicy: OnFailure restartPolicy: OnFailure

View File

@@ -15,14 +15,14 @@ spec:
component: machine-learning component: machine-learning
spec: spec:
containers: containers:
- image: "{{ .apps.immich.mlImage }}" - image: "{{ .mlImage }}"
name: immich-machine-learning name: immich-machine-learning
ports: ports:
- containerPort: {{ .apps.immich.mlPort }} - containerPort: {{ .mlPort }}
protocol: TCP protocol: TCP
env: env:
- name: TZ - name: TZ
value: "{{ .apps.immich.timezone }}" value: "{{ .timezone }}"
volumeMounts: volumeMounts:
- mountPath: /cache - mountPath: /cache
name: immich-cache name: immich-cache

View File

@@ -20,27 +20,27 @@ spec:
component: microservices component: microservices
spec: spec:
containers: containers:
- image: "{{ .apps.immich.serverImage }}" - image: "{{ .serverImage }}"
name: immich-microservices name: immich-microservices
env: env:
- name: REDIS_HOSTNAME - name: REDIS_HOSTNAME
value: "{{ .apps.immich.redisHostname }}" value: "{{ .redisHostname }}"
- name: REDIS_PASSWORD - name: REDIS_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: immich-secrets name: immich-secrets
key: apps.redis.password key: redis.password
- name: DB_HOSTNAME - name: DB_HOSTNAME
value: "{{ .apps.immich.dbHostname }}" value: "{{ .dbHostname }}"
- name: DB_USERNAME - name: DB_USERNAME
value: "{{ .apps.immich.dbUsername }}" value: "{{ .dbUsername }}"
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: immich-secrets name: immich-secrets
key: apps.immich.dbPassword key: dbPassword
- name: TZ - name: TZ
value: "{{ .apps.immich.timezone }}" value: "{{ .timezone }}"
- name: IMMICH_WORKERS_EXCLUDE - name: IMMICH_WORKERS_EXCLUDE
value: api value: api
volumeMounts: volumeMounts:

View File

@@ -20,30 +20,30 @@ spec:
component: server component: server
spec: spec:
containers: containers:
- image: "{{ .apps.immich.serverImage }}" - image: "{{ .serverImage }}"
name: immich-server name: immich-server
ports: ports:
- containerPort: {{ .apps.immich.serverPort }} - containerPort: {{ .serverPort }}
protocol: TCP protocol: TCP
env: env:
- name: REDIS_HOSTNAME - name: REDIS_HOSTNAME
value: "{{ .apps.immich.redisHostname }}" value: "{{ .redisHostname }}"
- name: REDIS_PASSWORD - name: REDIS_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: immich-secrets name: immich-secrets
key: apps.redis.password key: redis.password
- name: DB_HOSTNAME - name: DB_HOSTNAME
value: "{{ .apps.immich.dbHostname }}" value: "{{ .dbHostname }}"
- name: DB_USERNAME - name: DB_USERNAME
value: "{{ .apps.immich.dbUsername }}" value: "{{ .dbUsername }}"
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: immich-secrets name: immich-secrets
key: apps.immich.dbPassword key: dbPassword
- name: TZ - name: TZ
value: "{{ .apps.immich.timezone }}" value: "{{ .timezone }}"
- name: IMMICH_WORKERS_EXCLUDE - name: IMMICH_WORKERS_EXCLUDE
value: microservices value: microservices
volumeMounts: volumeMounts:

View File

@@ -4,11 +4,11 @@ kind: Ingress
metadata: metadata:
name: immich-public name: immich-public
annotations: annotations:
external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}" external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}"
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
spec: spec:
rules: rules:
- host: "{{ .apps.immich.domain }}" - host: "{{ .domain }}"
http: http:
paths: paths:
- path: / - path: /
@@ -21,4 +21,4 @@ spec:
tls: tls:
- secretName: wildcard-wild-cloud-tls - secretName: wildcard-wild-cloud-tls
hosts: hosts:
- "{{ .apps.immich.domain }}" - "{{ .domain }}"

View File

@@ -1,12 +1,15 @@
name: immich name: immich
install: true 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. description: Immich is a self-hosted photo and video backup solution that allows you
version: 1.0.0 to store, manage, and share your media files securely.
icon: https://immich.app/assets/images/logo.png version: release
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/immich.svg
requires: requires:
- name: redis - name: redis
- name: postgres - name: postgres
defaultConfig: defaultConfig:
namespace: immich
externalDnsDomain: '{{ .cloud.domain }}'
serverImage: ghcr.io/immich-app/immich-server:release serverImage: ghcr.io/immich-app/immich-server:release
mlImage: ghcr.io/immich-app/immich-machine-learning:release mlImage: ghcr.io/immich-app/immich-machine-learning:release
timezone: UTC timezone: UTC
@@ -20,6 +23,7 @@ defaultConfig:
domain: immich.{{ .cloud.domain }} domain: immich.{{ .cloud.domain }}
tlsSecretName: wildcard-wild-cloud-tls tlsSecretName: wildcard-wild-cloud-tls
defaultSecrets: defaultSecrets:
- key: apps.immich.dbPassword - key: dbPassword
- key: apps.postgres.password requiredSecrets:
- key: apps.redis.password - redis.password
- postgres.password

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: immich name: "{{ .namespace }}"

View File

@@ -9,7 +9,7 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: {{ .apps.immich.storage }} storage: {{ .storage }}
--- ---
apiVersion: v1 apiVersion: v1
kind: PersistentVolumeClaim kind: PersistentVolumeClaim
@@ -21,4 +21,4 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: {{ .apps.immich.cacheStorage }} storage: {{ .cacheStorage }}

View File

@@ -9,7 +9,7 @@ metadata:
spec: spec:
ports: ports:
- port: 3001 - port: 3001
targetPort: {{ .apps.immich.serverPort }} targetPort: {{ .serverPort }}
selector: selector:
app: immich app: immich
component: server component: server
@@ -25,7 +25,7 @@ metadata:
app: immich-machine-learning app: immich-machine-learning
spec: spec:
ports: ports:
- port: {{ .apps.immich.mlPort }} - port: {{ .mlPort }}
selector: selector:
app: immich app: immich
component: machine-learning component: machine-learning

View File

@@ -26,23 +26,23 @@ spec:
readOnlyRootFilesystem: false readOnlyRootFilesystem: false
env: env:
- name: PGHOST - name: PGHOST
value: {{ .apps.keila.dbHostname }} value: {{ .dbHostname }}
- name: PGUSER - name: PGUSER
value: postgres value: postgres
- name: PGPASSWORD - name: PGPASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: keila-secrets name: keila-secrets
key: apps.postgres.password key: postgres.password
- name: DB_NAME - name: DB_NAME
value: {{ .apps.keila.dbName }} value: {{ .dbName }}
- name: DB_USER - name: DB_USER
value: {{ .apps.keila.dbUsername }} value: {{ .dbUsername }}
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: keila-secrets name: keila-secrets
key: apps.keila.dbPassword key: dbPassword
command: command:
- /bin/bash - /bin/bash
- -c - -c

View File

@@ -14,54 +14,54 @@ spec:
spec: spec:
containers: containers:
- name: keila - name: keila
image: {{ .apps.keila.image }} image: "{{ .image }}"
ports: ports:
- containerPort: {{ .apps.keila.port }} - containerPort: {{ .port }}
env: env:
- name: DB_URL - name: DB_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: keila-secrets name: keila-secrets
key: apps.keila.dbUrl key: dbUrl
- name: URL_HOST - name: URL_HOST
value: {{ .apps.keila.domain }} value: "{{ .domain }}"
- name: URL_SCHEMA - name: URL_SCHEMA
value: https value: https
- name: URL_PORT - name: URL_PORT
value: "443" value: "443"
- name: PORT - name: PORT
value: "{{ .apps.keila.port }}" value: "{{ .port }}"
- name: SECRET_KEY_BASE - name: SECRET_KEY_BASE
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: keila-secrets name: keila-secrets
key: apps.keila.secretKeyBase key: secretKeyBase
- name: MAILER_SMTP_HOST - name: MAILER_SMTP_HOST
value: {{ .apps.keila.smtp.host }} value: "{{ .smtp.host }}"
- name: MAILER_SMTP_PORT - name: MAILER_SMTP_PORT
value: "{{ .apps.keila.smtp.port }}" value: "{{ .smtp.port }}"
- name: MAILER_ENABLE_SSL - name: MAILER_ENABLE_SSL
value: "{{ .apps.keila.smtp.tls }}" value: "{{ .smtp.tls }}"
- name: MAILER_ENABLE_STARTTLS - name: MAILER_ENABLE_STARTTLS
value: "{{ .apps.keila.smtp.startTls }}" value: "{{ .smtp.startTls }}"
- name: MAILER_SMTP_USER - name: MAILER_SMTP_USER
value: {{ .apps.keila.smtp.user }} value: "{{ .smtp.user }}"
- name: MAILER_SMTP_PASSWORD - name: MAILER_SMTP_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: keila-secrets name: keila-secrets
key: apps.keila.smtpPassword key: smtpPassword
- name: MAILER_SMTP_FROM_EMAIL - name: MAILER_SMTP_FROM_EMAIL
value: {{ .apps.keila.smtp.from }} value: "{{ .smtp.from }}"
- name: DISABLE_REGISTRATION - name: DISABLE_REGISTRATION
value: "{{ .apps.keila.disableRegistration }}" value: "{{ .disableRegistration }}"
- name: KEILA_USER - name: KEILA_USER
value: "{{ .apps.keila.adminUser }}" value: "{{ .adminUser }}"
- name: KEILA_PASSWORD - name: KEILA_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: keila-secrets name: keila-secrets
key: apps.keila.adminPassword key: adminPassword
- name: USER_CONTENT_DIR - name: USER_CONTENT_DIR
value: /var/lib/keila/uploads value: /var/lib/keila/uploads
volumeMounts: volumeMounts:
@@ -70,13 +70,13 @@ spec:
livenessProbe: livenessProbe:
httpGet: httpGet:
path: / path: /
port: {{ .apps.keila.port }} port: {{ .port }}
initialDelaySeconds: 30 initialDelaySeconds: 30
periodSeconds: 10 periodSeconds: 10
readinessProbe: readinessProbe:
httpGet: httpGet:
path: / path: /
port: {{ .apps.keila.port }} port: {{ .port }}
initialDelaySeconds: 5 initialDelaySeconds: 5
periodSeconds: 5 periodSeconds: 5
volumes: volumes:

View File

@@ -5,12 +5,12 @@ metadata:
annotations: annotations:
traefik.ingress.kubernetes.io/router.tls: "true" traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt 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" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
traefik.ingress.kubernetes.io/router.middlewares: keila-cors@kubernetescrd traefik.ingress.kubernetes.io/router.middlewares: keila-cors@kubernetescrd
spec: spec:
rules: rules:
- host: {{ .apps.keila.domain }} - host: {{ .domain }}
http: http:
paths: paths:
- path: / - path: /
@@ -23,4 +23,4 @@ spec:
tls: tls:
- secretName: "wildcard-wild-cloud-tls" - secretName: "wildcard-wild-cloud-tls"
hosts: hosts:
- "{{ .apps.keila.domain }}" - "{{ .domain }}"

View File

@@ -1,15 +1,18 @@
name: keila 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. 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 version: 0.17.1
icon: https://www.keila.io/images/logo.svg icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/keila.svg
requires: requires:
- name: postgres - name: postgres
defaultConfig: defaultConfig:
image: pentacent/keila:latest namespace: keila
externalDnsDomain: "{{ .cloud.domain }}"
image: pentacent/keila:0.17.1
port: 4000 port: 4000
storage: 1Gi storage: 1Gi
domain: keila.{{ .cloud.domain }} domain: keila.{{ .cloud.domain }}
dbHostname: postgres.postgres.svc.cluster.local dbHostname: "{{ .apps.postgres.host }}"
dbPort: "{{ .apps.postgres.port }}"
dbName: keila dbName: keila
dbUsername: keila dbUsername: keila
disableRegistration: "true" disableRegistration: "true"
@@ -20,12 +23,15 @@ defaultConfig:
port: "{{ .cloud.smtp.port }}" port: "{{ .cloud.smtp.port }}"
from: "{{ .cloud.smtp.from }}" from: "{{ .cloud.smtp.from }}"
user: "{{ .cloud.smtp.user }}" user: "{{ .cloud.smtp.user }}"
tls: {{ .cloud.smtp.tls }} tls: "{{ .cloud.smtp.tls }}"
startTls: {{ .cloud.smtp.startTls }} startTls: "{{ .cloud.smtp.startTls }}"
defaultSecrets: defaultSecrets:
- key: apps.keila.secretKeyBase - key: secretKeyBase
- key: apps.keila.dbPassword default: "{{ random.AlphaNum 64 }}"
- key: apps.keila.dbUrl - key: dbPassword
- key: apps.keila.adminPassword - key: dbUrl
- key: apps.keila.smtpPassword default: "postgres://{{ .app.dbUsername }}:{{ .secrets.dbPassword }}@{{ .app.dbHostname }}:{{ .app.dbPort }}/keila?sslmode=disable"
- key: apps.postgres.password - key: adminPassword
- key: smtpPassword
requiredSecrets:
- postgres.password

View File

@@ -21,8 +21,8 @@ spec:
- "OPTIONS" - "OPTIONS"
accessControlAllowOriginList: accessControlAllowOriginList:
- "http://localhost:1313" - "http://localhost:1313"
- "https://*.{{ .cloud.domain }}" - "https://*.{{ .externalDnsDomain }}"
- "https://{{ .cloud.domain }}" - "https://{{ .externalDnsDomain }}"
accessControlExposeHeaders: accessControlExposeHeaders:
- "*" - "*"
accessControlMaxAge: 86400 accessControlMaxAge: 86400

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: keila name: "{{ .namespace }}"

View File

@@ -7,4 +7,4 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: {{ .apps.keila.storage }} storage: {{ .storage }}

View File

@@ -7,5 +7,5 @@ spec:
component: web component: web
ports: ports:
- port: 80 - port: 80
targetPort: {{ .apps.keila.port }} targetPort: {{ .port }}
protocol: TCP protocol: TCP

View File

@@ -28,23 +28,23 @@ spec:
readOnlyRootFilesystem: false readOnlyRootFilesystem: false
env: env:
- name: PGHOST - name: PGHOST
value: {{ .apps.listmonk.dbHost }} value: {{ .dbHost }}
- name: PGUSER - name: PGUSER
value: postgres value: postgres
- name: PGPASSWORD - name: PGPASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: listmonk-secrets name: listmonk-secrets
key: apps.postgres.password key: postgres.password
- name: DB_NAME - name: DB_NAME
value: {{ .apps.listmonk.dbName }} value: {{ .dbName }}
- name: DB_USER - name: DB_USER
value: {{ .apps.listmonk.dbUser }} value: {{ .dbUser }}
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: listmonk-secrets name: listmonk-secrets
key: apps.listmonk.dbPassword key: dbPassword
command: command:
- /bin/bash - /bin/bash
- -c - -c

View File

@@ -30,21 +30,23 @@ spec:
env: env:
- name: LISTMONK_app__address - name: LISTMONK_app__address
value: "0.0.0.0:9000" value: "0.0.0.0:9000"
- name: LISTMONK_app__root_url
value: "{{ .rootUrl }}"
- name: LISTMONK_db__host - name: LISTMONK_db__host
value: {{ .apps.listmonk.dbHost }} value: {{ .dbHost }}
- name: LISTMONK_db__port - name: LISTMONK_db__port
value: "{{ .apps.listmonk.dbPort }}" value: "{{ .dbPort }}"
- name: LISTMONK_db__user - name: LISTMONK_db__user
value: {{ .apps.listmonk.dbUser }} value: {{ .dbUser }}
- name: LISTMONK_db__database - name: LISTMONK_db__database
value: {{ .apps.listmonk.dbName }} value: {{ .dbName }}
- name: LISTMONK_db__ssl_mode - name: LISTMONK_db__ssl_mode
value: {{ .apps.listmonk.dbSSLMode }} value: {{ .dbSSLMode }}
- name: LISTMONK_db__password - name: LISTMONK_db__password
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: listmonk-secrets name: listmonk-secrets
key: apps.listmonk.dbPassword key: dbPassword
resources: resources:
limits: limits:
cpu: 500m cpu: 500m

View File

@@ -6,16 +6,16 @@ metadata:
annotations: annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true" 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" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
spec: spec:
ingressClassName: traefik ingressClassName: traefik
tls: tls:
- hosts: - hosts:
- {{ .apps.listmonk.domain }} - {{ .domain }}
secretName: {{ .apps.listmonk.tlsSecretName }} secretName: {{ .tlsSecretName }}
rules: rules:
- host: {{ .apps.listmonk.domain }} - host: {{ .domain }}
http: http:
paths: paths:
- path: / - path: /

View File

@@ -1,11 +1,15 @@
name: listmonk 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 version: 5.0.3
icon: https://listmonk.app/static/images/logo.svg icon: https://listmonk.app/static/images/logo.svg
requires: requires:
- name: postgres - name: postgres
defaultConfig: defaultConfig:
namespace: listmonk
externalDnsDomain: '{{ .cloud.domain }}'
domain: listmonk.{{ .cloud.domain }} domain: listmonk.{{ .cloud.domain }}
rootUrl: https://listmonk.{{ .cloud.domain }}
tlsSecretName: wildcard-wild-cloud-tls tlsSecretName: wildcard-wild-cloud-tls
storage: 1Gi storage: 1Gi
dbHost: postgres.postgres.svc.cluster.local dbHost: postgres.postgres.svc.cluster.local
@@ -15,6 +19,8 @@ defaultConfig:
dbSSLMode: disable dbSSLMode: disable
timezone: UTC timezone: UTC
defaultSecrets: defaultSecrets:
- key: apps.listmonk.dbPassword - key: dbPassword
- key: apps.listmonk.dbUrl - key: dbUrl
- key: apps.postgres.password default: 'postgres://{{ .app.dbUser }}:{{ .secrets.dbPassword }}@{{ .app.dbHost }}:{{ .app.dbPort }}/{{ .app.dbName }}?sslmode={{ .app.dbSSLMode }}'
requiredSecrets:
- postgres.password

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: listmonk name: "{{ .namespace }}"

View File

@@ -8,4 +8,4 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: {{ .apps.listmonk.storage }} storage: {{ .storage }}

View File

@@ -1,27 +1,27 @@
name: loomio name: loomio
description: Loomio is a collaborative decision-making tool that makes it easy for groups to make decisions together description: Loomio is a collaborative decision-making tool that makes it easy for groups to make decisions together
version: 3.0.11 version: 3.0.11
icon: https://www.loomio.com/favicon.ico icon: https://www.loomio.com/brand/logo_gold.svg
requires: requires:
- name: postgres - name: postgres
installed_as: postgres installed_as: postgres
- name: redis - name: redis
defaultConfig: defaultConfig:
namespace: loomio namespace: loomio
externalDnsDomain: {{ .cloud.domain }} externalDnsDomain: "{{ .cloud.domain }}"
image: loomio/loomio:v3.0.11 image: loomio/loomio:v3.0.11
workerImage: loomio/loomio:v3.0.11 workerImage: loomio/loomio:v3.0.11
appName: Loomio appName: Loomio
domain: loomio.{{ .cloud.domain }} domain: "loomio.{{ .cloud.domain }}"
tlsSecretName: wildcard-wild-cloud-tls tlsSecretName: wildcard-wild-cloud-tls
port: 3000 port: 3000
storage: storage:
uploads: 5Gi uploads: 5Gi
files: 5Gi files: 5Gi
plugins: 1Gi plugins: 1Gi
redisUrl: {{ .apps.redis.uri }} redisUrl: "{{ .apps.redis.uri }}"
adminEmail: "admin@{{ .cloud.domain }}" adminEmail: "{{ .operator.email }}"
supportEmail: "support@{{ .cloud.domain }}" supportEmail: "{{ .operator.email }}"
forceSSL: "1" forceSSL: "1"
useRackAttack: "1" useRackAttack: "1"
pumaWorkers: "2" pumaWorkers: "2"
@@ -31,8 +31,8 @@ defaultConfig:
db: db:
name: loomio name: loomio
user: loomio user: loomio
host: {{ .apps.postgres.host }} host: "{{ .apps.postgres.host }}"
port: {{ .apps.postgres.port }} port: "{{ .apps.postgres.port }}"
smtp: smtp:
auth: plain auth: plain
domain: "{{ .cloud.domain }}" domain: "{{ .cloud.domain }}"

View File

@@ -3,7 +3,7 @@ kind: Deployment
metadata: metadata:
name: memcached name: memcached
spec: spec:
replicas: {{ .apps.memcached.replicas }} replicas: {{ .replicas }}
selector: selector:
matchLabels: matchLabels:
component: cache component: cache
@@ -14,24 +14,24 @@ spec:
spec: spec:
containers: containers:
- name: memcached - name: memcached
image: {{ .apps.memcached.image }} image: "{{ .image }}"
ports: ports:
- containerPort: {{ .apps.memcached.port }} - containerPort: {{ .port }}
name: memcached name: memcached
args: args:
- -m - -m
- {{ .apps.memcached.memoryLimit }} - "{{ .memoryLimit }}"
- -c - -c
- "{{ .apps.memcached.maxConnections }}" - "{{ .maxConnections }}"
- -p - -p
- "{{ .apps.memcached.port }}" - "{{ .port }}"
resources: resources:
requests: requests:
memory: {{ .apps.memcached.resources.requests.memory }} memory: "{{ .resources.requests.memory }}"
cpu: {{ .apps.memcached.resources.requests.cpu }} cpu: "{{ .resources.requests.cpu }}"
limits: limits:
memory: {{ .apps.memcached.resources.limits.memory }} memory: "{{ .resources.limits.memory }}"
cpu: {{ .apps.memcached.resources.limits.cpu }} cpu: "{{ .resources.limits.cpu }}"
securityContext: securityContext:
runAsNonRoot: true runAsNonRoot: true
runAsUser: 11211 runAsUser: 11211

View File

@@ -1,9 +1,11 @@
name: memcached 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 version: 1.6.32
icon: https://memcached.org/memcached-logo.png icon: https://www.vectorlogo.zone/logos/memcached/memcached-icon.svg
requires: [] requires: []
defaultConfig: defaultConfig:
namespace: memcached
image: memcached:1.6.32-alpine image: memcached:1.6.32-alpine
port: 11211 port: 11211
memoryLimit: 64m memoryLimit: 64m
@@ -16,4 +18,4 @@ defaultConfig:
limits: limits:
memory: 128Mi memory: 128Mi
cpu: 200m cpu: 200m
defaultSecrets: [] defaultSecrets: []

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: memcached name: "{{ .namespace }}"

View File

@@ -4,8 +4,8 @@ metadata:
name: memcached name: memcached
spec: spec:
ports: ports:
- port: {{ .apps.memcached.port }} - port: {{ .port }}
targetPort: {{ .apps.memcached.port }} targetPort: {{ .port }}
protocol: TCP protocol: TCP
name: memcached name: memcached
selector: selector:

View File

@@ -4,6 +4,8 @@ version: 9.1.0
icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png
requires: [] requires: []
defaultConfig: defaultConfig:
namespace: mysql
externalDnsDomain: '{{ .cloud.domain }}'
image: mysql:9.1.0 image: mysql:9.1.0
port: 3306 port: 3306
storage: 20Gi storage: 20Gi
@@ -13,5 +15,5 @@ defaultConfig:
timezone: UTC timezone: UTC
enableSSL: false enableSSL: false
defaultSecrets: defaultSecrets:
- key: apps.mysql.rootPassword - key: rootPassword
- key: apps.mysql.password - key: password

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: mysql name: "{{ .namespace }}"

View File

@@ -9,7 +9,7 @@ spec:
publishNotReadyAddresses: true publishNotReadyAddresses: true
ports: ports:
- name: mysql - name: mysql
port: {{ .apps.mysql.port }} port: {{ .port }}
protocol: TCP protocol: TCP
targetPort: mysql targetPort: mysql
selector: selector:

View File

@@ -7,7 +7,7 @@ spec:
type: ClusterIP type: ClusterIP
ports: ports:
- name: mysql - name: mysql
port: {{ .apps.mysql.port }} port: {{ .port }}
protocol: TCP protocol: TCP
targetPort: mysql targetPort: mysql
selector: selector:

View File

@@ -29,7 +29,7 @@ spec:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: mysql - name: mysql
image: {{ .apps.mysql.image }} image: {{ .image }}
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
securityContext: securityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
@@ -42,21 +42,21 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: mysql-secrets name: mysql-secrets
key: apps.mysql.rootPassword key: rootPassword
- name: MYSQL_USER - name: MYSQL_USER
value: {{ .apps.mysql.user }} value: {{ .user }}
- name: MYSQL_PASSWORD - name: MYSQL_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: mysql-secrets name: mysql-secrets
key: apps.mysql.password key: password
- name: MYSQL_DATABASE - name: MYSQL_DATABASE
value: {{ .apps.mysql.dbName }} value: {{ .dbName }}
- name: TZ - name: TZ
value: {{ .apps.mysql.timezone }} value: {{ .timezone }}
ports: ports:
- name: mysql - name: mysql
containerPort: {{ .apps.mysql.port }} containerPort: {{ .port }}
protocol: TCP protocol: TCP
livenessProbe: livenessProbe:
exec: exec:
@@ -113,4 +113,4 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: {{ .apps.mysql.storage }} storage: {{ .storage }}

View File

@@ -45,7 +45,7 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: open-webui-secrets name: open-webui-secrets
key: apps.openWebui.secretKey key: openWebui.secretKey
volumeMounts: volumeMounts:
- name: data - name: data
mountPath: /app/backend/data mountPath: /app/backend/data

View File

@@ -4,12 +4,12 @@ kind: Ingress
metadata: metadata:
name: open-webui name: open-webui
annotations: annotations:
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
traefik.ingress.kubernetes.io/router.middlewares: crowdsec-crowdsec-bouncer@kubernetescrd,crowdsec-rate-limit@kubernetescrd traefik.ingress.kubernetes.io/router.middlewares: crowdsec-crowdsec-bouncer@kubernetescrd,crowdsec-rate-limit@kubernetescrd
spec: spec:
rules: rules:
- host: {{ .apps.open-webui.domain }} - host: {{ .domain }}
http: http:
paths: paths:
- path: / - path: /
@@ -22,4 +22,4 @@ spec:
tls: tls:
- secretName: wildcard-wild-cloud-tls - secretName: wildcard-wild-cloud-tls
hosts: hosts:
- {{ .apps.open-webui.domain }} - {{ .domain }}

View File

@@ -1,17 +1,18 @@
name: openWebui 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 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: [] requires: []
defaultConfig: defaultConfig:
namespace: open-webui
externalDnsDomain: '{{ .cloud.domain }}'
image: ghcr.io/open-webui/open-webui:main image: ghcr.io/open-webui/open-webui:main
port: 8080 port: 8080
storage: 10Gi storage: 10Gi
domain: chat.{{ .cloud.domain }} domain: chat.{{ .cloud.domain }}
# vLLM integration - connect to existing vLLM service
vllmApiUrl: http://vllm-service.llm.svc.cluster.local:8000/v1 vllmApiUrl: http://vllm-service.llm.svc.cluster.local:8000/v1
# Authentication settings
enableAuth: true enableAuth: true
enableSignup: false enableSignup: false
defaultSecrets: defaultSecrets: []
- key: apps.openWebui.secretKey

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: open-webui name: "{{ .namespace }}"

View File

@@ -5,17 +5,17 @@ kind: "ConfigMap"
metadata: metadata:
name: "openproject-core" name: "openproject-core"
data: data:
DATABASE_HOST: "{{ .apps.openproject.dbHostname }}" DATABASE_HOST: "{{ .dbHostname }}"
DATABASE_PORT: "5432" DATABASE_PORT: "5432"
DATABASE_URL: "postgresql://{{ .apps.openproject.dbUsername }}@{{ .apps.openproject.dbHostname }}:5432/{{ .apps.openproject.dbName }}" DATABASE_URL: "postgresql://{{ .dbUsername }}@{{ .dbHostname }}:5432/{{ .dbName }}"
OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: "{{ .apps.openproject.adminPasswordReset }}" OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: "{{ .adminPasswordReset }}"
OPENPROJECT_SEED_ADMIN_USER_NAME: "{{ .apps.openproject.adminUserName }}" OPENPROJECT_SEED_ADMIN_USER_NAME: "{{ .adminUserName }}"
OPENPROJECT_SEED_ADMIN_USER_MAIL: "{{ .apps.openproject.adminUserEmail }}" OPENPROJECT_SEED_ADMIN_USER_MAIL: "{{ .adminUserEmail }}"
OPENPROJECT_HTTPS: "{{ .apps.openproject.https }}" OPENPROJECT_HTTPS: "{{ .https }}"
OPENPROJECT_SEED_LOCALE: "{{ .apps.openproject.seedLocale }}" OPENPROJECT_SEED_LOCALE: "{{ .seedLocale }}"
OPENPROJECT_HOST__NAME: "{{ .apps.openproject.domain }}" OPENPROJECT_HOST__NAME: "{{ .domain }}"
OPENPROJECT_HSTS: "{{ .apps.openproject.hsts }}" OPENPROJECT_HSTS: "{{ .hsts }}"
OPENPROJECT_RAILS__CACHE__STORE: "{{ .apps.openproject.cacheStore }}" OPENPROJECT_RAILS__CACHE__STORE: "{{ .cacheStore }}"
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "{{ .apps.openproject.railsRelativeUrlRoot }}" OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "{{ .railsRelativeUrlRoot }}"
POSTGRES_STATEMENT_TIMEOUT: "{{ .apps.openproject.postgresStatementTimeout }}" POSTGRES_STATEMENT_TIMEOUT: "{{ .postgresStatementTimeout }}"
... ...

View File

@@ -5,5 +5,5 @@ kind: "ConfigMap"
metadata: metadata:
name: "openproject-memcached" name: "openproject-memcached"
data: data:
OPENPROJECT_CACHE__MEMCACHE__SERVER: "{{ .apps.openproject.memcachedHostname }}:{{ .apps.openproject.memcachedPort }}" OPENPROJECT_CACHE__MEMCACHE__SERVER: "{{ .memcachedHostname }}:{{ .memcachedPort }}"
... ...

View File

@@ -12,7 +12,7 @@ spec:
spec: spec:
containers: containers:
- name: db-init - name: db-init
image: {{ .apps.postgres.image }} image: postgres:17
command: ["/bin/bash", "-c"] command: ["/bin/bash", "-c"]
args: args:
- | - |
@@ -36,16 +36,16 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: postgres-secrets name: postgres-secrets
key: apps.postgres.password key: password
- name: DB_HOSTNAME - name: DB_HOSTNAME
value: "{{ .apps.openproject.dbHostname }}" value: "{{ .dbHostname }}"
- name: DB_DATABASE_NAME - name: DB_DATABASE_NAME
value: "{{ .apps.openproject.dbName }}" value: "{{ .dbName }}"
- name: DB_USERNAME - name: DB_USERNAME
value: "{{ .apps.openproject.dbUsername }}" value: "{{ .dbUsername }}"
- name: DB_PASSWORD - name: DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.dbPassword key: dbPassword
restartPolicy: OnFailure restartPolicy: OnFailure

View File

@@ -7,10 +7,10 @@ metadata:
spec: spec:
tls: tls:
- hosts: - hosts:
- "{{ .apps.openproject.domain }}" - "{{ .domain }}"
secretName: "wildcard-wild-cloud-tls" secretName: "wildcard-wild-cloud-tls"
rules: rules:
- host: "{{ .apps.openproject.domain }}" - host: "{{ .domain }}"
http: http:
paths: paths:
- path: / - path: /

View File

@@ -1,11 +1,14 @@
name: openproject 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 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: requires:
- name: postgres - name: postgres
- name: memcached - name: memcached
defaultConfig: defaultConfig:
namespace: openproject
externalDnsDomain: '{{ .cloud.domain }}'
serverImage: openproject/openproject:16.1.1-slim serverImage: openproject/openproject:16.1.1-slim
timezone: UTC timezone: UTC
serverPort: 8080 serverPort: 8080
@@ -20,14 +23,15 @@ defaultConfig:
hsts: true hsts: true
seedLocale: en seedLocale: en
adminUserName: OpenProject Admin adminUserName: OpenProject Admin
adminUserEmail: "{{ .operator.email }}" adminUserEmail: '{{ .operator.email }}'
adminPasswordReset: true adminPasswordReset: true
postgresStatementTimeout: 120s postgresStatementTimeout: 120s
tmpVolumesStorage: 2Gi tmpVolumesStorage: 2Gi
tlsSecretName: wildcard-wild-cloud-tls tlsSecretName: wildcard-wild-cloud-tls
cacheStore: memcache cacheStore: memcache
railsRelativeUrlRoot: "" railsRelativeUrlRoot: ''
defaultSecrets: defaultSecrets:
- key: apps.openproject.dbPassword - key: dbPassword
- key: apps.openproject.adminPassword - key: adminPassword
- key: apps.postgres.password requiredSecrets:
- postgres.password

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: openproject name: "{{ .namespace }}"

View File

@@ -8,5 +8,5 @@ spec:
accessModes: [ReadWriteMany] accessModes: [ReadWriteMany]
resources: resources:
requests: requests:
storage: "{{ .apps.openproject.storage }}" storage: "{{ .storage }}"
... ...

View File

@@ -27,7 +27,7 @@ spec:
accessModes: ["ReadWriteOnce"] accessModes: ["ReadWriteOnce"]
resources: resources:
requests: requests:
storage: {{ .apps.openproject.tmpVolumesStorage }} storage: {{ .tmpVolumesStorage }}
- name: app-tmp - name: app-tmp
# we can't use emptyDir due to the sticky bit / world writable issue # we can't use emptyDir due to the sticky bit / world writable issue
# see: https://github.com/kubernetes/kubernetes/issues/110835 # see: https://github.com/kubernetes/kubernetes/issues/110835
@@ -39,13 +39,13 @@ spec:
accessModes: ["ReadWriteOnce"] accessModes: ["ReadWriteOnce"]
resources: resources:
requests: requests:
storage: {{ .apps.openproject.tmpVolumesStorage }} storage: {{ .tmpVolumesStorage }}
- name: "data" - name: "data"
persistentVolumeClaim: persistentVolumeClaim:
claimName: openproject claimName: openproject
initContainers: initContainers:
- name: check-db-ready - name: check-db-ready
image: "{{ .apps.postgres.image }}" image: "postgres:17"
imagePullPolicy: Always imagePullPolicy: Always
command: [ command: [
'sh', 'sh',
@@ -62,12 +62,12 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.dbPassword key: dbPassword
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.adminPassword key: adminPassword
resources: resources:
limits: limits:
memory: 200Mi memory: 200Mi
@@ -91,7 +91,7 @@ spec:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: seeder - name: seeder
image: "{{ .apps.openproject.serverImage }}" image: "{{ .serverImage }}"
imagePullPolicy: Always imagePullPolicy: Always
args: args:
- bash - bash
@@ -106,12 +106,12 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.dbPassword key: dbPassword
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.adminPassword key: adminPassword
resources: resources:
limits: limits:
memory: 512Mi memory: 512Mi

View File

@@ -43,7 +43,7 @@ spec:
accessModes: ["ReadWriteOnce"] accessModes: ["ReadWriteOnce"]
resources: resources:
requests: requests:
storage: {{ .apps.openproject.tmpVolumesStorage }} storage: {{ .tmpVolumesStorage }}
- name: app-tmp - name: app-tmp
# we can't use emptyDir due to the sticky bit / world writable issue # we can't use emptyDir due to the sticky bit / world writable issue
# see: https://github.com/kubernetes/kubernetes/issues/110835 # see: https://github.com/kubernetes/kubernetes/issues/110835
@@ -55,12 +55,12 @@ spec:
accessModes: ["ReadWriteOnce"] accessModes: ["ReadWriteOnce"]
resources: resources:
requests: requests:
storage: {{ .apps.openproject.tmpVolumesStorage }} storage: {{ .tmpVolumesStorage }}
- name: "data" - name: "data"
persistentVolumeClaim: persistentVolumeClaim:
claimName: openproject claimName: openproject
initContainers: initContainers:
- name: wait-for-db - name: wait-for-db
securityContext: securityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities: capabilities:
@@ -72,8 +72,13 @@ spec:
runAsUser: 1000 runAsUser: 1000
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
image: {{ .apps.openproject.serverImage }} image: postgres:17
imagePullPolicy: Always 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: envFrom:
- configMapRef: - configMapRef:
name: openproject-core name: openproject-core
@@ -84,14 +89,12 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.dbPassword key: dbPassword
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.adminPassword key: adminPassword
args:
- /app/docker/prod/wait-for-db
resources: resources:
limits: limits:
memory: 1Gi memory: 1Gi
@@ -115,7 +118,7 @@ spec:
runAsUser: 1000 runAsUser: 1000
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
image: {{ .apps.openproject.serverImage }} image: {{ .serverImage }}
imagePullPolicy: Always imagePullPolicy: Always
envFrom: envFrom:
- configMapRef: - configMapRef:
@@ -127,12 +130,12 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.dbPassword key: dbPassword
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.adminPassword key: adminPassword
args: args:
- /app/docker/prod/web - /app/docker/prod/web
volumeMounts: volumeMounts:

View File

@@ -43,7 +43,7 @@ spec:
accessModes: ["ReadWriteOnce"] accessModes: ["ReadWriteOnce"]
resources: resources:
requests: requests:
storage: {{ .apps.openproject.tmpVolumesStorage }} storage: {{ .tmpVolumesStorage }}
- name: app-tmp - name: app-tmp
# we can't use emptyDir due to the sticky bit / world writable issue # we can't use emptyDir due to the sticky bit / world writable issue
# see: https://github.com/kubernetes/kubernetes/issues/110835 # see: https://github.com/kubernetes/kubernetes/issues/110835
@@ -55,7 +55,7 @@ spec:
accessModes: ["ReadWriteOnce"] accessModes: ["ReadWriteOnce"]
resources: resources:
requests: requests:
storage: {{ .apps.openproject.tmpVolumesStorage }} storage: {{ .tmpVolumesStorage }}
- name: "data" - name: "data"
persistentVolumeClaim: persistentVolumeClaim:
claimName: openproject claimName: openproject
@@ -72,8 +72,13 @@ spec:
runAsUser: 1000 runAsUser: 1000
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
image: {{ .apps.openproject.serverImage }} image: postgres:17
imagePullPolicy: Always 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: envFrom:
- configMapRef: - configMapRef:
name: openproject-core name: openproject-core
@@ -84,15 +89,12 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.dbPassword key: dbPassword
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD - name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.adminPassword key: adminPassword
args:
- bash
- /app/docker/prod/wait-for-db
resources: resources:
limits: limits:
memory: 1Gi memory: 1Gi
@@ -116,7 +118,7 @@ spec:
runAsUser: 1000 runAsUser: 1000
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
image: {{ .apps.openproject.serverImage }} image: {{ .serverImage }}
imagePullPolicy: Always imagePullPolicy: Always
envFrom: envFrom:
- configMapRef: - configMapRef:
@@ -132,7 +134,7 @@ spec:
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: openproject-secrets name: openproject-secrets
key: apps.openproject.dbPassword key: dbPassword
- name: "OPENPROJECT_GOOD_JOB_QUEUES" - name: "OPENPROJECT_GOOD_JOB_QUEUES"
value: "" value: ""
volumeMounts: volumeMounts:

View File

@@ -2,7 +2,7 @@ name: redis
install: true install: true
description: Redis is an open source, in-memory data structure store, used as a database, cache and message broker. description: Redis is an open source, in-memory data structure store, used as a database, cache and message broker.
version: 1.0.0 version: 1.0.0
icon: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 85 27"><path fill="#FF4438" fill-rule="evenodd" d="M75.29 13.813c0-2.968 2.2-4.69 4.947-4.69 2.052 0 3.884.99 4.763 3.444-.257 1.245-1.795 2.638-2.455 2.858-.55-1.173-1.172-1.869-1.758-1.869-.733 0-.77.513-.77 1.172 0 .467.134 1.155.295 1.983.243 1.25.548 2.82.548 4.43 0 2.93-2.052 5.092-5.203 5.092-2.885 0-4.48-1.892-5.19-4.913-1.885 3.377-4.641 4.913-6.754 4.913-3.302 0-4.08-2.441-4-4.917-1.328 2.345-3.882 4.917-6.331 4.917-2.501 0-3.384-2.177-3.182-4.712-1.498 2.791-4.208 4.712-6.82 4.712-2.836 0-4.239-2.252-3.785-5.044-1.907 2.344-5.458 5.044-9.149 5.044-4.209 0-6.04-2.27-6.258-5.114-2.031 3.256-4.77 5.224-8.03 5.224-4.709 0-6.393-4.187-6.638-7.611a111 111 0 0 1-6.113 7.464c-.256.257-.476.403-.732.403C1.832 26.6.11 22.862 0 21.47c.723-1.121 5.281-6.13 8.95-10.161 1.29-1.417 2.471-2.714 3.336-3.679-2.247.678-4.564 2.03-7.486 4.132-.513.366-1.942-2.968-1.906-5.533 3.371-2.49 8.5-4.066 12.64-4.066 5.79 0 9.123 3.224 9.123 7.694 0 3.737-3.114 7.84-7.657 7.987-2.362.061-3.876-1.265-4.65-2.902.092 2.532 1.409 5.65 4.943 5.65 3.853 0 5.704-2.326 8.463-5.795q.269-.339.55-.69c2.345-2.895 5.056-5.46 9.013-5.46 2.418 0 4.067 1.503 4.067 3.774 0 2.748-3.224 6.558-7.73 6.558-.77 0-1.472-.101-2.064-.301q-.024.173-.025.338c0 1.282.476 2.052 2.565 2.052 3.077 0 5.971-1.832 9.489-6.119 3.444-4.213 6.045-6.045 8.793-6.045 1.855 0 3.262 1.005 3.883 2.698C57.98 6.283 61.104 2.514 63.75 0c2.601 1.1 4.47 3.26 3.957 3.7-1.942 1.76-8.427 8.83-10.991 13.044-.66 1.099-1.283 2.308-1.283 2.894 0 .55.33.733.696.733 1.76 0 5.289-4.156 8.336-7.746 1.138-1.34 2.209-2.602 3.095-3.539 2.052.843 4.14 2.638 3.627 3.261-2.71 3.224-4.762 5.862-4.762 7.364 0 .403.146.66.696.66 1.026 0 1.978-.916 3.554-2.858.33-.403.732-.403.989.22.696 1.685 1.722 2.601 2.528 2.601.952 0 1.429-.843 1.429-2.125 0-.876-.107-1.895-.2-2.772-.069-.664-.13-1.246-.13-1.624m-59.096-.477c1.942 0 4.067-1.062 4.067-3.224 0-1.312-.814-2.521-2.99-2.89l-.342.535c-1.106 1.729-2.149 3.359-3.2 4.953.63.354 1.427.626 2.465.626m19.638.66c0-.587-.367-.99-.953-.99-1.47 0-3.687 2.063-4.73 4.055.385.15.837.232 1.323.232 2.601 0 4.36-1.978 4.36-3.297m9.636 5.312c0 .66.366 1.1 1.135 1.1 2.382 0 5.35-4.324 5.35-6.083 0-.732-.403-1.172-1.063-1.172-2.162 0-5.422 4.103-5.422 6.155M76.06 6.082c-.843 1.392-2.125 2.968-2.601 3.444-2.199-.916-4.25-2.748-3.957-3.26.806-1.43 2.125-2.968 2.601-3.445 2.198.916 4.25 2.785 3.957 3.261" clip-rule="evenodd"></path></svg> icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/redis.svg
defaultConfig: defaultConfig:
namespace: redis namespace: redis
image: redis:alpine image: redis:alpine

View File

@@ -19,10 +19,10 @@ spec:
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
nodeSelector: nodeSelector:
nvidia.com/gpu.product: "{{ .apps.vllm.gpuProduct }}" nvidia.com/gpu.product: "{{ .gpuProduct }}"
containers: containers:
- name: vllm - name: vllm
image: "{{ .apps.vllm.image }}" image: "{{ .image }}"
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
securityContext: securityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
@@ -31,10 +31,10 @@ spec:
- ALL - ALL
readOnlyRootFilesystem: false readOnlyRootFilesystem: false
args: args:
- --model={{ .apps.vllm.model }} - --model={{ .model }}
- --max-model-len={{ .apps.vllm.maxModelLen }} - --max-model-len={{ .maxModelLen }}
- --tensor-parallel-size={{ .apps.vllm.tensorParallelSize }} - --tensor-parallel-size={{ .tensorParallelSize }}
- --gpu-memory-utilization={{ .apps.vllm.gpuMemoryUtilization }} - --gpu-memory-utilization={{ .gpuMemoryUtilization }}
{{- if .apps.vllm.enforceEager }} {{- if .apps.vllm.enforceEager }}
- --enforce-eager=True - --enforce-eager=True
{{- end }} {{- end }}
@@ -48,13 +48,13 @@ spec:
containerPort: 8000 containerPort: 8000
resources: resources:
requests: requests:
cpu: "{{ .apps.vllm.cpuRequest }}" cpu: "{{ .cpuRequest }}"
memory: "{{ .apps.vllm.memoryRequest }}" memory: "{{ .memoryRequest }}"
nvidia.com/gpu: {{ .apps.vllm.gpuCount }} nvidia.com/gpu: {{ .gpuCount }}
limits: limits:
cpu: "{{ .apps.vllm.cpuLimit }}" cpu: "{{ .cpuLimit }}"
memory: "{{ .apps.vllm.memoryLimit }}" memory: "{{ .memoryLimit }}"
nvidia.com/gpu: {{ .apps.vllm.gpuCount }} nvidia.com/gpu: {{ .gpuCount }}
readinessProbe: readinessProbe:
httpGet: httpGet:
path: /v1/models path: /v1/models

View File

@@ -3,13 +3,13 @@ kind: Ingress
metadata: metadata:
name: vllm name: vllm
annotations: annotations:
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }} external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
traefik.ingress.kubernetes.io/router.tls: "true" traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
spec: spec:
rules: rules:
- host: {{ .apps.vllm.domain }} - host: {{ .domain }}
http: http:
paths: paths:
- path: / - path: /
@@ -21,5 +21,5 @@ spec:
number: 8000 number: 8000
tls: tls:
- hosts: - hosts:
- {{ .apps.vllm.domain }} - {{ .domain }}
secretName: vllm-tls secretName: vllm-tls

View File

@@ -1,6 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
namespace: {{ .apps.vllm.namespace }} namespace: {{ .namespace }}
labels: labels:
- includeSelectors: true - includeSelectors: true
pairs: pairs:

View File

@@ -1,21 +1,22 @@
name: vllm 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 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: [] requires: []
defaultConfig: defaultConfig:
image: vllm/vllm-openai:v0.5.4 image: vllm/vllm-openai:v0.5.4
model: Qwen/Qwen2.5-7B-Instruct model: Qwen/Qwen2.5-7B-Instruct
maxModelLen: 8192 maxModelLen: 8192
tensorParallelSize: 1 tensorParallelSize: 1
gpuMemoryUtilization: 0.90 gpuMemoryUtilization: 0.9
enforceEager: true enforceEager: true
gpuProduct: "RTX 4090" gpuProduct: RTX 4090
cpuRequest: "4" cpuRequest: '4'
cpuLimit: "8" cpuLimit: '8'
memoryRequest: "16Gi" memoryRequest: 16Gi
memoryLimit: "24Gi" memoryLimit: 24Gi
gpuCount: 1 gpuCount: 1
domain: vllm.{{ .cloud.domain }} domain: vllm.{{ .cloud.domain }}
namespace: llm namespace: llm
defaultSecrets: [] defaultSecrets: []

View File

@@ -1,4 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: {{ .apps.vllm.namespace }} name: {{ .namespace }}