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
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.
@@ -22,6 +22,7 @@ This is the contents of an example `manifest.yaml` file for an app named "immich
```yaml
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.
version: 1.0.0
icon: https://immich.app/assets/images/logo.png
@@ -54,11 +55,12 @@ requiredSecrets:
- redis.auth # References redis app via 'redis' name (no alias)
```
#### Manifest Fields
### Manifest Fields
| Field | Required | Description |
|-------|----------|-------------|
| `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 |
| `version` | Yes | App version (follow upstream versioning) |
| `icon` | No | URL to app icon for UI display |
@@ -67,18 +69,156 @@ requiredSecrets:
| `defaultSecrets` | No | This app's secrets (no 'default' = auto-generated) |
| `requiredSecrets` | No | List of secrets from dependency apps (format: `<app-ref>.<key>`) |
**Dependency Configuration:**
### Dependency Configuration
- 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`)
**Manifest Template Variable Sources:**
### Manifest Template Variables (configuration and secrets)
#### 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:**
#### 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:
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

View File

@@ -19,11 +19,11 @@ spec:
automountServiceAccountToken: false
serviceAccountName: discourse
securityContext:
fsGroup: 0
fsGroup: 1000
fsGroupChangePolicy: Always
containers:
- name: discourse
image: tiredofit/discourse:latest
image: discourse/discourse:3.5.3
imagePullPolicy: "IfNotPresent"
securityContext:
allowPrivilegeEscalation: false
@@ -32,10 +32,10 @@ spec:
- ALL
add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
- SETGID
- SETUID
- DAC_OVERRIDE
privileged: false
readOnlyRootFilesystem: false
runAsNonRoot: false
@@ -43,78 +43,68 @@ spec:
seccompProfile:
type: RuntimeDefault
env:
# Admin configuration
- name: ADMIN_USER
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
# Discourse database configuration
- name: DISCOURSE_DB_HOST
value: {{ .dbHostname }}
- name: DB_PORT
- name: DISCOURSE_DB_PORT
value: "{{ .dbPort }}"
- name: DB_NAME
- name: DISCOURSE_DB_NAME
value: {{ .dbName }}
- name: DB_USER
- name: DISCOURSE_DB_USERNAME
value: {{ .dbUsername }}
- name: DB_PASS
- name: DISCOURSE_DB_PASSWORD
valueFrom:
secretKeyRef:
name: discourse-secrets
key: dbPassword
# Redis configuration
- name: REDIS_HOST
- name: DISCOURSE_REDIS_HOST
value: {{ .redisHostname }}
- name: REDIS_PASS
- 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: SMTP_ENABLED
value: "{{ .smtp.enabled }}"
- name: SMTP_HOST
- name: DISCOURSE_SMTP_ADDRESS
value: {{ .smtp.host }}
- name: SMTP_PORT
- name: DISCOURSE_SMTP_PORT
value: "{{ .smtp.port }}"
- name: SMTP_USER
- name: DISCOURSE_SMTP_USER_NAME
value: {{ .smtp.user }}
- name: SMTP_PASS
- name: DISCOURSE_SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: discourse-secrets
key: smtpPassword
- name: SMTP_TLS
value: "{{ .smtp.tls }}"
# Container timezone
- name: TZ
value: {{ .timezone }}
- name: DISCOURSE_SMTP_ENABLE_START_TLS
value: "{{ .smtp.startTls }}"
ports:
- name: http
containerPort: 3000
protocol: TCP
livenessProbe:
httpGet:
path: /
path: /srv/status
port: http
initialDelaySeconds: 420
initialDelaySeconds: 500
periodSeconds: 30
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 6
readinessProbe:
httpGet:
path: /
path: /srv/status
port: http
initialDelaySeconds: 360
periodSeconds: 30
@@ -125,25 +115,120 @@ spec:
limits:
cpu: 2000m
ephemeral-storage: 10Gi
memory: 4Gi
memory: 8Gi
requests:
cpu: 500m
cpu: 750m
ephemeral-storage: 50Mi
memory: 1Gi
volumeMounts:
- name: discourse-logs
mountPath: /data/logs
- name: discourse-uploads
mountPath: /data/uploads
- name: discourse-backups
mountPath: /data/backups
- name: discourse-data
mountPath: /shared
- name: sidekiq
image: discourse/discourse:3.5.3
imagePullPolicy: "IfNotPresent"
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:
- name: discourse-logs
- name: discourse-data
persistentVolumeClaim:
claimName: discourse-logs
- name: discourse-uploads
persistentVolumeClaim:
claimName: discourse-uploads
- name: discourse-backups
persistentVolumeClaim:
claimName: discourse-backups
claimName: discourse-data

View File

@@ -1,4 +1,5 @@
name: discourse
is: discourse
description: Discourse is a modern, open-source discussion platform designed for online communities and forums.
version: 3.5.3
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/discourse.svg

View File

@@ -2,20 +2,7 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: discourse-logs
namespace: discourse
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: longhorn
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: discourse-uploads
name: discourse-data
namespace: discourse
spec:
accessModes:
@@ -24,16 +11,3 @@ spec:
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

@@ -1,4 +1,5 @@
name: example-admin
is: example
install: true
description: An example application that is deployed with internal-only access.
version: 1.0.0

View File

@@ -1,4 +1,5 @@
name: example-app
is: example
install: true
description: An example application that is deployed with public access.
version: 1.0.0

View File

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

View File

@@ -1,4 +1,5 @@
name: gitea
is: gitea
description: Gitea is a painless self-hosted Git service written in Go
version: 1.24.3
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gitea.svg

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
name: loomio
is: loomio
description: Loomio is a collaborative decision-making tool that makes it easy for groups to make decisions together
version: 3.0.11
icon: https://www.loomio.com/brand/logo_gold.svg

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
name: redis
is: redis
install: true
description: Redis is an open source, in-memory data structure store, used as a database, cache and message broker.
version: 1.0.0

View File

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