Adds is attribute to manifests.

This commit is contained in:
2025-12-31 08:15:17 +00:00
parent d1304a2630
commit 434769ac7a
19 changed files with 305 additions and 90 deletions

View File

@@ -14,7 +14,7 @@ Each app directory must contain:
2. **`kustomization.yaml`** - Kustomize configuration with Wild Cloud labels 2. **`kustomization.yaml`** - Kustomize configuration with Wild Cloud labels
3. **Resource files** - Kubernetes manifests (deployments, services, ingresses, etc.) 3. **Resource files** - Kubernetes manifests (deployments, services, ingresses, etc.)
### App Manifest (`manifest.yaml`) ## App Manifest (`manifest.yaml`)
The manifest defines the app's metadata, dependencies, configuration schema, and secret requirements. The manifest defines the app's metadata, dependencies, configuration schema, and secret requirements.
@@ -22,6 +22,7 @@ This is the contents of an example `manifest.yaml` file for an app named "immich
```yaml ```yaml
name: immich name: immich
is: immich
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 to store, manage, and share your media files securely.
version: 1.0.0 version: 1.0.0
icon: https://immich.app/assets/images/logo.png icon: https://immich.app/assets/images/logo.png
@@ -54,11 +55,12 @@ requiredSecrets:
- redis.auth # References redis app via 'redis' name (no alias) - redis.auth # References redis app via 'redis' name (no alias)
``` ```
#### Manifest Fields ### Manifest Fields
| Field | Required | Description | | Field | Required | Description |
|-------|----------|-------------| |-------|----------|-------------|
| `name` | Yes | App identifier (must match directory name) | | `name` | Yes | App identifier (must match directory name) |
| `is` | Yes | Unique id for this app. Used for `requires` mapping |
| `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 |
@@ -67,18 +69,156 @@ requiredSecrets:
| `defaultSecrets` | No | This app's secrets (no 'default' = auto-generated) | | `defaultSecrets` | No | This app's secrets (no 'default' = auto-generated) |
| `requiredSecrets` | No | List of secrets from dependency apps (format: `<app-ref>.<key>`) | | `requiredSecrets` | No | List of secrets from dependency apps (format: `<app-ref>.<key>`) |
**Dependency Configuration:** ### Dependency Configuration
- Each dependency in `requires` can have: - Each dependency in `requires` can have:
- `name`: The actual app name to depend on - `name`: The app name to depend on (any app with a matching `is` field can satisfy this requirement)
- `alias`: Optional reference name for templates (defaults to `name`) - `alias`: Optional reference name for templates (defaults to `name`)
**Manifest Template Variable Sources:** ### Manifest Template Variables (configuration and secrets)
#### Manifest Template Variable Sources
1. Standard Wild Cloud variables: `{{ .cloud.* }}`, `{{ .cluster.* }}`, `{{ .operator.* }}` 1. Standard Wild Cloud variables: `{{ .cloud.* }}`, `{{ .cluster.* }}`, `{{ .operator.* }}`
2. App-specific variables: `{{ .app.* }}` - resolved from current app's config 2. App-specific variables: `{{ .app.* }}` - resolved from current app's config
3. Dependency variables: `{{ .apps.<ref>.* }}` - resolved using app reference mapping 3. Dependency variables: `{{ .apps.<ref>.* }}` - resolved using app reference mapping
4. App-specific secrets (in 'defaultSecrets' ONLY): `{{ secrets.* }}` 4. App-specific secrets (in 'defaultSecrets' ONLY): `{{ secrets.* }}`
**Manifest App Reference Resolution:** #### Available Configuration Variiables
Here's a comprehensive rundown of all config variables that get set during cluster and service setup in config.yaml:
##### operator (Set during initial setup)
- operator.email - Email for cluster operator/admin
##### cloud (Infrastructure-level settings)
###### DNS Configuration:
- cloud.dns.ip - IP address of the DNS server (Wild Central)
- cloud.dns.externalResolver - External DNS resolver (e.g., 1.1.1.1, 8.8.8.8)
###### Network Configuration:
- cloud.router.ip - Router gateway IP
- cloud.router.dynamicDns - Dynamic DNS hostname (optional)
- cloud.dhcpRange - DHCP range for the network (e.g., "192.168.8.34,192.168.8.79")
- cloud.dnsmasq.interface - Network interface for dnsmasq
###### Domain Configuration:
- cloud.baseDomain - Base domain for the cloud (e.g., "payne.io")
- cloud.domain - Full cloud domain (e.g., "cloud2.payne.io")
- cloud.internalDomain - Internal cluster domain (e.g., "internal.cloud2.payne.io")
###### Storage Configuration (NFS Service):
- cloud.nfs.host - NFS server hostname/IP
- cloud.nfs.mediaPath - NFS export path for media storage
- cloud.nfs.storageCapacity - NFS storage capacity (e.g., "50Gi", "1Ti")
###### Registry Configuration (Docker Registry Service):
- cloud.dockerRegistryHost - Docker registry hostname (e.g., "registry.internal.cloud2.payne.io")
##### SMTP Configuration (SMTP Service):
- cloud.smtp.host - SMTP server hostname
- cloud.smtp.port - SMTP port (typically "465" or "587")
- cloud.smtp.user - SMTP username
- cloud.smtp.from - Default 'from' email address
- cloud.smtp.tls - Enable TLS (true/false)
- cloud.smtp.startTls - Enable STARTTLS (true/false)
###### Backup Configuration:
- cloud.backup.root - Root path for backups
##### cluster (Kubernetes cluster settings)
###### Basic Cluster Info:
- cluster.name - Cluster name identifier
- cluster.hostnamePrefix - Prefix for node hostnames
###### Node Configuration:
- cluster.nodes.talos.version - Talos Linux version (e.g., "v1.11.5")
- cluster.nodes.talos.schematicId - Talos Image Factory schematic ID
- cluster.nodes.control.vip - Virtual IP for control plane
- cluster.nodes.active.* - Individual node configurations with:
- role - "controlplane" or "worker"
- interface - Network interface name
- disk - Disk device path
- currentIp - Current IP address
- targetIp - Target IP address
- configured - Configuration status
- applied - Applied status
- maintenance - Maintenance mode
- schematicId - Node-specific schematic ID
- version - Node-specific Talos version
###### MetalLB Service:
- cluster.ipAddressPool - IP range for MetalLB (e.g., "192.168.8.80-192.168.8.89")
- cluster.loadBalancerIp - Primary load balancer IP (e.g., "192.168.8.80")
###### Cert-Manager Service:
- cluster.certManager.cloudflare.domain - Cloudflare domain for DNS-01 challenge
- cluster.certManager.cloudflare.zoneID - Cloudflare zone ID
###### ExternalDNS Service:
- cluster.externalDns.ownerId - Unique identifier for this cluster's DNS records
###### Docker Registry Service:
- cluster.dockerRegistry.storage - Storage size for registry (e.g., "10Gi")
##### apps (Application configurations)
Each app added to the cluster gets its own section under apps.<app-name> with app-specific configuration from the app's manifest. Common patterns include:
Standard app fields:
- apps.<name>.namespace - Kubernetes namespace
- apps.<name>.domain - App domain (e.g., "ghost.cloud2.payne.io")
- apps.<name>.externalDnsDomain - Domain for external DNS
- apps.<name>.tlsSecretName - TLS certificate secret name
- apps.<name>.image - Container image
- apps.<name>.port - Service port
- apps.<name>.storage - Persistent volume size
- apps.<name>.timezone - Timezone setting
Database-dependent apps:
- apps.<name>.dbHost / dbHostname - Database hostname
- apps.<name>.dbPort - Database port
- apps.<name>.dbName - Database name
- apps.<name>.dbUser / dbUsername - Database user
SMTP-enabled apps:
- apps.<name>.smtp.host - SMTP server
- apps.<name>.smtp.port - SMTP port
- apps.<name>.smtp.user - SMTP username
- apps.<name>.smtp.from - From address
- apps.<name>.smtp.tls - TLS enabled
- apps.<name>.smtp.startTls - STARTTLS enabled
Configuration Flow
1. Initial Setup: operator.email, basic cloud.* settings
2. Cluster Bootstrap: cluster.name, cluster.nodes.* settings
3. Infrastructure Services: Each service prompts for its serviceConfig from its manifest
- MetalLB → cluster.ipAddressPool, cluster.loadBalancerIp
- Cert-Manager → cluster.certManager.*
- ExternalDNS → cluster.externalDns.ownerId
- NFS → cloud.nfs.*
- Docker Registry → cloud.dockerRegistryHost, cluster.dockerRegistry.storage
- SMTP → cloud.smtp.*
4. Apps: Each app adds its configuration under apps.<name>.* based on its manifest
#### Manifest App Reference Resolution:
When you use `{{ .apps.<ref>.* }}` in templates: When you use `{{ .apps.<ref>.* }}` in templates:
1. System checks if `<ref>` matches any dependency's `alias` field 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 2. If no alias match, checks if `<ref>` matches any dependency's `name` field

View File

@@ -19,11 +19,11 @@ spec:
automountServiceAccountToken: false automountServiceAccountToken: false
serviceAccountName: discourse serviceAccountName: discourse
securityContext: securityContext:
fsGroup: 0 fsGroup: 1000
fsGroupChangePolicy: Always fsGroupChangePolicy: Always
containers: containers:
- name: discourse - name: discourse
image: tiredofit/discourse:latest image: discourse/discourse:3.5.3
imagePullPolicy: "IfNotPresent" imagePullPolicy: "IfNotPresent"
securityContext: securityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
@@ -32,10 +32,10 @@ spec:
- ALL - ALL
add: add:
- CHOWN - CHOWN
- DAC_OVERRIDE
- FOWNER - FOWNER
- SETGID - SETGID
- SETUID - SETUID
- DAC_OVERRIDE
privileged: false privileged: false
readOnlyRootFilesystem: false readOnlyRootFilesystem: false
runAsNonRoot: false runAsNonRoot: false
@@ -43,78 +43,68 @@ spec:
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
env: env:
# Admin configuration # Discourse database configuration
- name: ADMIN_USER - name: DISCOURSE_DB_HOST
value: {{ .adminUsername }}
- name: ADMIN_EMAIL
value: {{ .adminEmail }}
- name: ADMIN_PASS
valueFrom:
secretKeyRef:
name: discourse-secrets
key: adminPassword
# Site configuration
- name: SITE_TITLE
value: {{ .siteName }}
- name: HOSTNAME
value: {{ .domain }}
# Database configuration
- name: DB_HOST
value: {{ .dbHostname }} value: {{ .dbHostname }}
- name: DB_PORT - name: DISCOURSE_DB_PORT
value: "{{ .dbPort }}" value: "{{ .dbPort }}"
- name: DB_NAME - name: DISCOURSE_DB_NAME
value: {{ .dbName }} value: {{ .dbName }}
- name: DB_USER - name: DISCOURSE_DB_USERNAME
value: {{ .dbUsername }} value: {{ .dbUsername }}
- name: DB_PASS - name: DISCOURSE_DB_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: dbPassword key: dbPassword
# Redis configuration # Redis configuration
- name: REDIS_HOST - name: DISCOURSE_REDIS_HOST
value: {{ .redisHostname }} value: {{ .redisHostname }}
- name: REDIS_PASS - name: DISCOURSE_REDIS_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: redis.password key: redis.password
# Site configuration
- name: DISCOURSE_HOSTNAME
value: {{ .domain }}
- name: DISCOURSE_DEVELOPER_EMAILS
value: {{ .adminEmail }}
- name: DISCOURSE_SECRET_KEY_BASE
valueFrom:
secretKeyRef:
name: discourse-secrets
key: secretKeyBase
# SMTP configuration # SMTP configuration
- name: SMTP_ENABLED - name: DISCOURSE_SMTP_ADDRESS
value: "{{ .smtp.enabled }}"
- name: SMTP_HOST
value: {{ .smtp.host }} value: {{ .smtp.host }}
- name: SMTP_PORT - name: DISCOURSE_SMTP_PORT
value: "{{ .smtp.port }}" value: "{{ .smtp.port }}"
- name: SMTP_USER - name: DISCOURSE_SMTP_USER_NAME
value: {{ .smtp.user }} value: {{ .smtp.user }}
- name: SMTP_PASS - name: DISCOURSE_SMTP_PASSWORD
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: discourse-secrets name: discourse-secrets
key: smtpPassword key: smtpPassword
- name: SMTP_TLS - name: DISCOURSE_SMTP_ENABLE_START_TLS
value: "{{ .smtp.tls }}" value: "{{ .smtp.startTls }}"
# Container timezone
- name: TZ
value: {{ .timezone }}
ports: ports:
- name: http - name: http
containerPort: 3000 containerPort: 3000
protocol: TCP protocol: TCP
livenessProbe: livenessProbe:
httpGet: httpGet:
path: / path: /srv/status
port: http port: http
initialDelaySeconds: 420 initialDelaySeconds: 500
periodSeconds: 30 periodSeconds: 30
timeoutSeconds: 10 timeoutSeconds: 10
successThreshold: 1 successThreshold: 1
failureThreshold: 6 failureThreshold: 6
readinessProbe: readinessProbe:
httpGet: httpGet:
path: / path: /srv/status
port: http port: http
initialDelaySeconds: 360 initialDelaySeconds: 360
periodSeconds: 30 periodSeconds: 30
@@ -125,25 +115,120 @@ spec:
limits: limits:
cpu: 2000m cpu: 2000m
ephemeral-storage: 10Gi ephemeral-storage: 10Gi
memory: 4Gi memory: 8Gi
requests: requests:
cpu: 500m cpu: 750m
ephemeral-storage: 50Mi ephemeral-storage: 50Mi
memory: 1Gi memory: 1Gi
volumeMounts: volumeMounts:
- name: discourse-logs - name: discourse-data
mountPath: /data/logs mountPath: /shared
- name: discourse-uploads - name: sidekiq
mountPath: /data/uploads image: discourse/discourse:3.5.3
- name: discourse-backups imagePullPolicy: "IfNotPresent"
mountPath: /data/backups securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
add:
- CHOWN
- FOWNER
- SETGID
- SETUID
- DAC_OVERRIDE
privileged: false
readOnlyRootFilesystem: false
runAsNonRoot: false
runAsUser: 0
seccompProfile:
type: RuntimeDefault
command:
- /bin/bash
- -c
- "cd /var/www/discourse && exec bundle exec sidekiq"
env:
# Discourse database configuration
- name: DISCOURSE_DB_HOST
value: {{ .dbHostname }}
- name: DISCOURSE_DB_PORT
value: "{{ .dbPort }}"
- name: DISCOURSE_DB_NAME
value: {{ .dbName }}
- name: DISCOURSE_DB_USERNAME
value: {{ .dbUsername }}
- name: DISCOURSE_DB_PASSWORD
valueFrom:
secretKeyRef:
name: discourse-secrets
key: dbPassword
# Redis configuration
- name: DISCOURSE_REDIS_HOST
value: {{ .redisHostname }}
- name: DISCOURSE_REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: discourse-secrets
key: redis.password
# Site configuration
- name: DISCOURSE_HOSTNAME
value: {{ .domain }}
- name: DISCOURSE_DEVELOPER_EMAILS
value: {{ .adminEmail }}
- name: DISCOURSE_SECRET_KEY_BASE
valueFrom:
secretKeyRef:
name: discourse-secrets
key: secretKeyBase
# SMTP configuration
- name: DISCOURSE_SMTP_ADDRESS
value: {{ .smtp.host }}
- name: DISCOURSE_SMTP_PORT
value: "{{ .smtp.port }}"
- name: DISCOURSE_SMTP_USER_NAME
value: {{ .smtp.user }}
- name: DISCOURSE_SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: discourse-secrets
key: smtpPassword
- name: DISCOURSE_SMTP_ENABLE_START_TLS
value: "{{ .smtp.startTls }}"
livenessProbe:
exec:
command:
- /bin/bash
- -c
- "pgrep -f sidekiq"
initialDelaySeconds: 500
periodSeconds: 30
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 6
readinessProbe:
exec:
command:
- /bin/bash
- -c
- "pgrep -f sidekiq"
initialDelaySeconds: 180
periodSeconds: 30
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 6
resources:
limits:
cpu: 1000m
ephemeral-storage: 2Gi
memory: 1Gi
requests:
cpu: 375m
ephemeral-storage: 50Mi
memory: 512Mi
volumeMounts:
- name: discourse-data
mountPath: /shared
volumes: volumes:
- name: discourse-logs - name: discourse-data
persistentVolumeClaim: persistentVolumeClaim:
claimName: discourse-logs claimName: discourse-data
- name: discourse-uploads
persistentVolumeClaim:
claimName: discourse-uploads
- name: discourse-backups
persistentVolumeClaim:
claimName: discourse-backups

View File

@@ -1,4 +1,5 @@
name: discourse name: discourse
is: 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.5.3 version: 3.5.3
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/discourse.svg icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/discourse.svg

View File

@@ -2,20 +2,7 @@
apiVersion: v1 apiVersion: v1
kind: PersistentVolumeClaim kind: PersistentVolumeClaim
metadata: metadata:
name: discourse-logs name: discourse-data
namespace: discourse
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: longhorn
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: discourse-uploads
namespace: discourse namespace: discourse
spec: spec:
accessModes: accessModes:
@@ -24,16 +11,3 @@ spec:
requests: requests:
storage: {{ .storage }} storage: {{ .storage }}
storageClassName: longhorn storageClassName: longhorn
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: discourse-backups
namespace: discourse
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: longhorn

View File

@@ -1,4 +1,5 @@
name: example-admin name: example-admin
is: example
install: true 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

View File

@@ -1,4 +1,5 @@
name: example-app name: example-app
is: example
install: true 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

View File

@@ -1,4 +1,5 @@
name: ghost name: ghost
is: ghost
description: Ghost is a powerful app for new-media creators to publish, share, and description: Ghost is a powerful app for new-media creators to publish, share, and
grow a business around their content. grow a business around their content.
version: 5.118.1 version: 5.118.1

View File

@@ -1,4 +1,5 @@
name: gitea name: gitea
is: 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://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gitea.svg icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gitea.svg

View File

@@ -1,4 +1,5 @@
name: immich name: immich
is: immich
install: true install: true
description: Immich is a self-hosted photo and video backup solution that allows you description: Immich is a self-hosted photo and video backup solution that allows you
to store, manage, and share your media files securely. to store, manage, and share your media files securely.

View File

@@ -1,4 +1,5 @@
name: keila name: keila
is: 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: 0.17.1 version: 0.17.1
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/keila.svg icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/keila.svg

View File

@@ -1,4 +1,5 @@
name: listmonk name: listmonk
is: listmonk
description: Listmonk is a standalone, self-hosted, newsletter and mailing list manager. description: Listmonk is a standalone, self-hosted, newsletter and mailing list manager.
It is fast, feature-rich, and packed into a single binary. It is fast, feature-rich, and packed into a single binary.
version: 5.0.3 version: 5.0.3

View File

@@ -1,4 +1,5 @@
name: loomio name: loomio
is: 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/brand/logo_gold.svg icon: https://www.loomio.com/brand/logo_gold.svg

View File

@@ -1,4 +1,5 @@
name: memcached name: memcached
is: memcached
description: Memcached is an in-memory key-value store for small chunks of arbitrary description: Memcached is an in-memory key-value store for small chunks of arbitrary
data, commonly used as a cache layer. data, commonly used as a cache layer.
version: 1.6.32 version: 1.6.32

View File

@@ -1,4 +1,5 @@
name: mysql name: mysql
is: mysql
description: MySQL is an open-source relational database management system description: MySQL is an open-source relational database management system
version: 9.1.0 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

View File

@@ -1,4 +1,5 @@
name: openWebui name: open-webui
is: open-webui
description: Open WebUI is a comprehensive, open-source web interface for AI 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 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. offline. Perfect for creating a ChatGPT-like experience with local or hosted models.

View File

@@ -1,4 +1,5 @@
name: openproject name: openproject
is: openproject
description: OpenProject is an open-source project management software that provides description: OpenProject is an open-source project management software that provides
comprehensive features for project planning, tracking, and collaboration. comprehensive features for project planning, tracking, and collaboration.
version: 16.1.1 version: 16.1.1

View File

@@ -1,4 +1,5 @@
name: postgres name: postgres
is: postgres
install: true install: true
description: PostgreSQL is a powerful, open source object-relational database system. description: PostgreSQL is a powerful, open source object-relational database system.
version: 1.0.0 version: 1.0.0

View File

@@ -1,4 +1,5 @@
name: redis name: redis
is: 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

View File

@@ -1,4 +1,5 @@
name: vllm name: vllm
is: vllm
description: vLLM is a fast and easy-to-use library for LLM inference and serving description: vLLM is a fast and easy-to-use library for LLM inference and serving
with OpenAI-compatible API with OpenAI-compatible API
version: 0.5.4 version: 0.5.4