Compare commits
4 Commits
351f58b80d
...
d1304a2630
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1304a2630 | ||
|
|
8818d822cf | ||
|
|
1b78abbdc4 | ||
|
|
a4db0d0f6a |
145
ADDING-APPS.md
145
ADDING-APPS.md
@@ -26,8 +26,9 @@ description: Immich is a self-hosted photo and video backup solution that allows
|
||||
version: 1.0.0
|
||||
icon: https://immich.app/assets/images/logo.png
|
||||
requires:
|
||||
- name: redis
|
||||
- name: postgres
|
||||
- name: pg
|
||||
alias: db # Use a different reference name in templates
|
||||
- name: redis # 'alias' and 'installedAs' default to 'name' value
|
||||
defaultConfig:
|
||||
serverImage: ghcr.io/immich-app/immich-server:release
|
||||
mlImage: ghcr.io/immich-app/immich-machine-learning:release
|
||||
@@ -36,13 +37,21 @@ defaultConfig:
|
||||
mlPort: 3003
|
||||
storage: 250Gi
|
||||
cacheStorage: 10Gi
|
||||
redisHostname: redis.redis.svc.cluster.local
|
||||
dbHostname: postgres.postgres.svc.cluster.local
|
||||
dbUsername: immich
|
||||
redisHostname: "{{ .apps.redis.host }}" # Can reference 'requires' app configurations
|
||||
dbHostname: "{{ .apps.pg.host }}"
|
||||
db: # Configuration can be nested
|
||||
name: immich
|
||||
user: immich
|
||||
host: "{{ .apps.pg.host }}"
|
||||
port: "{{ .apps.pg.port }}"
|
||||
domain: immich.{{ .cloud.domain }}
|
||||
defaultSecrets:
|
||||
- key: password # Random value will be generated if empty
|
||||
- key: dbUrl
|
||||
default: "postgresql://{{ .app.db.user }}:{{ .secrets.dbPassword }}@{{ .app.db.host }}:{{ .app.db.port }}/{{ .app.db.name }}?pool=30" # Can reference secrets and config as long as they have been defined before this line. Reference config with {{ .app.? }} and secrets with {{ .secrets.? }}
|
||||
requiredSecrets:
|
||||
- apps.immich.dbPassword
|
||||
- apps.postgres.password
|
||||
- db.password # References postgres app via 'db' alias
|
||||
- redis.auth # References redis app via 'redis' name (no alias)
|
||||
```
|
||||
|
||||
#### Manifest Fields
|
||||
@@ -53,11 +62,31 @@ requiredSecrets:
|
||||
| `description` | Yes | Brief app description shown in listings |
|
||||
| `version` | Yes | App version (follow upstream versioning) |
|
||||
| `icon` | No | URL to app icon for UI display |
|
||||
| `requires` | No | List of dependency apps (e.g., `postgres`, `redis`) |
|
||||
| `requires` | No | List of dependency apps with optional aliases |
|
||||
| `defaultConfig` | Yes | Default configuration values merged into operator's `config.yaml` |
|
||||
| `requiredSecrets` | 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`)
|
||||
|
||||
@@ -111,21 +140,7 @@ This means individual resources can use simple, component-specific selectors lik
|
||||
|
||||
### Gomplate Templating
|
||||
|
||||
Resource files in this repository are **templates** that get compiled when users add apps via the web app, CLI, or API. Use gomplate syntax to reference configuration:
|
||||
|
||||
```yaml
|
||||
# Common template variables
|
||||
domain: {{ .cloud.domain }} # Operator's domain
|
||||
email: {{ .operator.email }} # Operator's email
|
||||
image: {{ .apps.myapp.serverImage }} # App-specific config
|
||||
dbHost: {{ .apps.myapp.dbHostname }} # App-specific config
|
||||
```
|
||||
|
||||
**Template variable sources:**
|
||||
1. Standard Wild Cloud variables (`{{ .cloud.* }}`, `{{ .operator.* }}`)
|
||||
2. App-specific variables defined in your manifest's `defaultConfig`
|
||||
|
||||
All template variables must be defined in one of these locations. The compiled files are placed in the instance's directory as standard Kubernetes manifests.
|
||||
Resource files in this repository are **templates** that get compiled when users add apps via the web app, CLI, or API. Only variables defined in the manifest file's 'defaultConfig' section are available to the resource templates. Use gomplate syntax to reference configuration:
|
||||
|
||||
### External DNS
|
||||
|
||||
@@ -133,12 +148,47 @@ Ingress resources should include external-dns annotations for automatic DNS mana
|
||||
|
||||
```yaml
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/target: {{ .domain }}
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
```
|
||||
|
||||
Note: 'domain' must be defined in the app manifest's 'defaultConfig' section.
|
||||
|
||||
This creates a CNAME from the app subdomain to the cluster domain (e.g., `myapp.cloud.example.com` → `cloud.example.com`).
|
||||
|
||||
## App Dependencies and Reference Mapping
|
||||
|
||||
### How Dependency References Work
|
||||
|
||||
When an app depends on other apps, the reference system allows flexibility in naming while maintaining clear relationships:
|
||||
|
||||
1. **Define dependencies** in your manifest with optional aliases:
|
||||
```yaml
|
||||
requires:
|
||||
- name: postgres # Actual app to depend on
|
||||
alias: db # Optional: how to reference it in templates
|
||||
- name: redis # No alias means use 'redis' as reference
|
||||
```
|
||||
|
||||
2. **At installation time**, the system:
|
||||
- Prompts user to map dependencies to actual installed apps
|
||||
- Sets `installedAs` field in the local app manifest to track the mapping
|
||||
- Example: User might have `postgres-primary` installed, mapped to the `db` dependency
|
||||
|
||||
### Example: Multiple Database Instances
|
||||
|
||||
If a user has multiple PostgreSQL instances:
|
||||
```yaml
|
||||
# User's config.yaml
|
||||
apps:
|
||||
postgres-primary:
|
||||
hostname: primary.postgres.svc.cluster.local
|
||||
postgres-analytics:
|
||||
hostname: analytics.postgres.svc.cluster.local
|
||||
```
|
||||
|
||||
When adding an app that requires postgres, they can choose which instance to use, and the system tracks this in the manifest's `installedAs` field.
|
||||
|
||||
## Database Patterns
|
||||
|
||||
### Database Initialization Jobs
|
||||
@@ -177,7 +227,7 @@ When apps need database URLs with embedded credentials, **always use a dedicated
|
||||
key: apps.myapp.dbUrl
|
||||
```
|
||||
|
||||
Add `apps.myapp.dbUrl` to your manifest's `requiredSecrets`, and the system will generate the complete URL with embedded credentials automatically when the app is added.
|
||||
Add `apps.myapp.dbUrl` to your manifest's `defaultSecrets`, and the system will generate the complete URL with embedded credentials automatically when the app is added.
|
||||
|
||||
## Security Requirements
|
||||
|
||||
@@ -211,13 +261,16 @@ spec:
|
||||
|
||||
### Secrets Management
|
||||
|
||||
Secrets use a **full dotted-path naming convention** to prevent naming conflicts:
|
||||
Secrets are managed through two mechanisms: default secrets for the app itself and required secrets from dependencies.
|
||||
|
||||
**In manifest:**
|
||||
```yaml
|
||||
defaultSecrets:
|
||||
key: dbPassword # This app's database password
|
||||
key: apiKey # This app's API key
|
||||
requiredSecrets:
|
||||
- apps.myapp.dbPassword
|
||||
- apps.postgres.password
|
||||
- db.password # Password from postgres dependency (aliased as 'db')
|
||||
- redis.auth # Auth from redis dependency
|
||||
```
|
||||
|
||||
**In resources:**
|
||||
@@ -227,14 +280,26 @@ env:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: myapp-secrets
|
||||
key: apps.myapp.dbPassword # Full dotted path, not just "dbPassword"
|
||||
key: dbPassword # Points to the default secret
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: myapp-secrets
|
||||
key: db.password # Points to the required secret
|
||||
```
|
||||
|
||||
**Secret workflow:**
|
||||
1. List secrets in manifest's `requiredSecrets`
|
||||
2. When adding an app, the system generates random values in the instance's `secrets.yaml`
|
||||
3. When deploying, the system creates a Kubernetes Secret named `<app-name>-secrets`
|
||||
4. Resources reference secrets using full dotted paths
|
||||
1. Define app's own secrets in `defaultSecrets` (key, default mappings)
|
||||
2. Reference dependency secrets in `requiredSecrets` (list)
|
||||
3. When adding an app, the system:
|
||||
- Generates random values for empty `defaultSecrets`
|
||||
- Copies referenced secrets from dependencies
|
||||
- Stores all in the instance's `secrets.yaml`
|
||||
4. When deploying, creates a Kubernetes Secret named `<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.
|
||||
|
||||
@@ -308,9 +373,11 @@ Before submitting a new or modified app, verify:
|
||||
- [ ] **Manifest**
|
||||
- [ ] `name` matches directory name
|
||||
- [ ] All required fields present (`name`, `description`, `version`, `defaultConfig`)
|
||||
- [ ] All template variables defined in `defaultConfig` or are standard Wild Cloud variables
|
||||
- [ ] Secrets use dotted-path format (e.g., `apps.appname.secretname`)
|
||||
- [ ] Dependencies listed in `requires` (if any)
|
||||
- [ ] All template variables defined in `defaultConfig`
|
||||
- [ ] `defaultSecrets` uses maps with 'key' and 'default' attributes
|
||||
- [ ] `requiredSecrets` references use `<app-ref>.<key>` format
|
||||
- [ ] Dependencies listed in `requires` with optional `alias` fields
|
||||
- [ ] Manifest template references match dependency aliases or names
|
||||
|
||||
- [ ] **Kustomization**
|
||||
- [ ] Includes standard Wild Cloud labels with `includeSelectors: true`
|
||||
@@ -318,8 +385,6 @@ Before submitting a new or modified app, verify:
|
||||
- [ ] All resource files listed under `resources:`
|
||||
|
||||
- [ ] **Resources**
|
||||
- [ ] All hardcoded values replaced with gomplate variables
|
||||
- [ ] Secrets reference full dotted paths
|
||||
- [ ] Security contexts on all pods (both pod-level and container-level)
|
||||
- [ ] Simple component labels, no Helm-style labels
|
||||
- [ ] Ingresses include external-dns annotations
|
||||
|
||||
182
CLAUDE.md
182
CLAUDE.md
@@ -1,171 +1,15 @@
|
||||
# CLAUDE.md
|
||||
- @README.md
|
||||
- @ADDING-APPS.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
## IMPORTANT
|
||||
|
||||
## Overview
|
||||
|
||||
This repository contains the Wild Cloud apps directory - a collection of Kubernetes applications packaged as Kustomize configurations. Each app is a self-contained directory with standardized manifests that can be deployed to Wild Cloud clusters using Wild Cloud CLI tools.
|
||||
|
||||
## Repository Architecture
|
||||
|
||||
### App Structure
|
||||
|
||||
Each app follows a strict structure:
|
||||
- **`manifest.yaml`** - App metadata, dependencies, default configuration, and secret requirements
|
||||
- **`kustomization.yaml`** - Kustomize configuration with standard Wild Cloud labels
|
||||
- **Resource files** - Kubernetes objects (deployments, services, ingresses, PVCs, jobs, etc.)
|
||||
|
||||
### Templating System
|
||||
|
||||
Configuration files use **gomplate templating** to reference operator configuration:
|
||||
- Use `{{ .cloud.domain }}` for the operator's domain
|
||||
- Use `{{ .apps.appname.configKey }}` for app-specific configuration
|
||||
- Use `{{ .operator.email }}` for operator email
|
||||
- All template variables must be defined in either the app's `manifest.yaml` under `defaultConfig` or be standard Wild Cloud operator variables
|
||||
|
||||
Templates are compiled when users add apps to their Wild Cloud instance via the web app, CLI, or API.
|
||||
|
||||
### Label Strategy
|
||||
|
||||
Wild Cloud uses a consistent labeling approach powered by Kustomize's `includeSelectors: true` feature:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- includeSelectors: true
|
||||
pairs:
|
||||
app: appname # App name (matches directory)
|
||||
managedBy: kustomize
|
||||
partOf: wild-cloud
|
||||
```
|
||||
|
||||
This automatically applies labels to all resources AND their selectors. Individual resources can use simple component-specific selectors like `component: web` or `component: worker`, and Kustomize will expand them to include the standard Wild Cloud labels.
|
||||
|
||||
**Important:** Do NOT use Helm-style labels (`app.kubernetes.io/name`, `app.kubernetes.io/instance`). Use simple component labels instead.
|
||||
|
||||
## Working with Apps
|
||||
|
||||
### Creating/Modifying Apps
|
||||
|
||||
1. **Manifest fields:**
|
||||
- `name` - Must match directory name
|
||||
- `description` - Brief app description
|
||||
- `version` - App version (follow upstream versioning)
|
||||
- `icon` - URL to app icon
|
||||
- `requires` - List of dependency apps (e.g., `postgres`, `redis`, `memcached`)
|
||||
- `defaultConfig` - Default configuration values (will be added to operator's `config.yaml`)
|
||||
- `requiredSecrets` - List of secrets in dotted path format (e.g., `apps.appname.dbPassword`)
|
||||
|
||||
2. **Kustomization requirements:**
|
||||
- Must include standard Wild Cloud labels with `includeSelectors: true`
|
||||
- Namespace must match app name
|
||||
- List all resource files under `resources:`
|
||||
|
||||
3. **Security contexts:**
|
||||
All pods must comply with Pod Security Standards:
|
||||
```yaml
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 999 # Use appropriate non-root UID
|
||||
runAsGroup: 999
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: [ALL]
|
||||
readOnlyRootFilesystem: false # Set to true when possible
|
||||
```
|
||||
|
||||
### Secrets Management
|
||||
|
||||
Secrets use **full dotted paths** as keys:
|
||||
```yaml
|
||||
env:
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: appname-secrets
|
||||
key: apps.appname.dbPassword # Full path, not just "dbPassword"
|
||||
```
|
||||
|
||||
**Database URL secrets:** When apps need database URLs with embedded credentials, always use a dedicated `dbUrl` secret in `requiredSecrets`. Do NOT try to construct URLs with env var substitution in templates - Kustomize cannot process runtime environment variables.
|
||||
|
||||
### Database Initialization Jobs
|
||||
|
||||
Apps requiring PostgreSQL/MySQL databases should include a `db-init-job.yaml`:
|
||||
- Creates the app database if it doesn't exist
|
||||
- Creates/updates the app user with proper password
|
||||
- Grants appropriate permissions
|
||||
- For PostgreSQL jobs: use `runAsUser: 999` (postgres user)
|
||||
- Include any required database extensions (e.g., Immich requires `vector`, `cube`, `earthdistance`)
|
||||
|
||||
Examples: [immich/db-init-job.yaml](immich/db-init-job.yaml), [gitea/db-init-job.yaml](gitea/db-init-job.yaml)
|
||||
|
||||
### External DNS Configuration
|
||||
|
||||
Ingress resources should include external-dns annotations:
|
||||
```yaml
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
```
|
||||
|
||||
This creates CNAME records pointing app subdomains to the main cluster domain.
|
||||
|
||||
### Converting Helm Charts
|
||||
|
||||
Wild Cloud prefers Kustomize over Helm for transparency and Git-friendliness. To convert a Helm chart:
|
||||
|
||||
```bash
|
||||
helm fetch --untar --untardir charts repo/chart-name
|
||||
helm template --output-dir base --namespace namespace --values values.yaml release-name charts/chart-name
|
||||
cd base/chart-name
|
||||
kustomize create --autodetect
|
||||
```
|
||||
|
||||
Then:
|
||||
1. Add `manifest.yaml`
|
||||
2. Replace hardcoded values with gomplate variables
|
||||
3. Update secrets to use Wild Cloud's dotted-path approach
|
||||
4. Replace Helm labels with simple component labels
|
||||
5. Add standard Wild Cloud labels to `kustomization.yaml`
|
||||
6. Add security contexts to all pods
|
||||
|
||||
## Managing Wild Cloud Apps
|
||||
|
||||
Users can manage apps through:
|
||||
|
||||
1. **Web App**: Navigate to the Apps page in your instance to browse, add, configure, and deploy apps
|
||||
|
||||
2. **CLI**: Use the Wild CLI for terminal-based workflows:
|
||||
- `wild app list` - List all available apps
|
||||
- `wild app add <app-name>` - Add an app (compiles templates, updates config/secrets)
|
||||
- `wild app deploy <app-name>` - Deploy an app to the cluster
|
||||
- `wild app list-deployed` - List deployed apps
|
||||
- `wild app status <app-name>` - Get app status
|
||||
- `wild app delete <app-name>` - Delete an app
|
||||
|
||||
3. **API**: Use the Wild Central API endpoints for automation:
|
||||
- `GET /api/v1/apps/available` - List all available apps
|
||||
- `GET /api/v1/apps/available/{app-name}` - Get app details
|
||||
- `POST /api/v1/instances/{instance-name}/apps` - Add an app (compiles templates, updates config/secrets)
|
||||
- `POST /api/v1/instances/{instance-name}/apps/{app-name}/deploy` - Deploy an app to the cluster
|
||||
- `GET /api/v1/instances/{instance-name}/apps` - List deployed apps
|
||||
- `GET /api/v1/instances/{instance-name}/apps/{app-name}/status` - Get app status
|
||||
|
||||
## Validation
|
||||
|
||||
Before submitting changes:
|
||||
1. Ensure `manifest.yaml` has all required fields
|
||||
2. Verify `kustomization.yaml` includes standard Wild Cloud labels
|
||||
3. Check all templates use valid configuration paths defined in `defaultConfig`
|
||||
4. Confirm secrets use full dotted-path keys
|
||||
5. Verify all pods have proper security contexts
|
||||
6. Test template compilation works with sample operator config
|
||||
|
||||
## Examples of Well-Structured Apps
|
||||
|
||||
- **immich** - Multi-deployment app with database init, multiple services, PostgreSQL extensions
|
||||
- **openproject** - App with multiple dependencies (postgres, memcached), configmap-based configuration
|
||||
- **gitea** - Standard app with database init, PVC for storage
|
||||
- When adding a new app to the directory, check to make sure you are adding the latest app version.
|
||||
- Use traefik for ingress.
|
||||
- Use postgres for database if supported.
|
||||
- Keep config key naming (including nesting) consistent with other apps.
|
||||
- Don't use helm
|
||||
- If the app requires a specific platform (amd64, arm64, etc.), make sure it is called out in the manifest and the k8s tags are set
|
||||
- when developing a new app:
|
||||
- test with:
|
||||
- reset to a fresh state between tests:
|
||||
- secrets.yaml is not checked in and any values unrelated to your current task should be preserved
|
||||
|
||||
@@ -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"
|
||||
@@ -27,7 +27,7 @@ spec:
|
||||
readOnlyRootFilesystem: false
|
||||
env:
|
||||
- name: PGHOST
|
||||
value: "{{ .apps.discourse.dbHostname }}"
|
||||
value: "{{ .dbHostname }}"
|
||||
- name: PGPORT
|
||||
value: "5432"
|
||||
- name: PGUSER
|
||||
@@ -36,16 +36,16 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.postgres.password
|
||||
key: postgres.password
|
||||
- name: DISCOURSE_DB_USER
|
||||
value: "{{ .apps.discourse.dbUsername }}"
|
||||
value: "{{ .dbUsername }}"
|
||||
- name: DISCOURSE_DB_NAME
|
||||
value: "{{ .apps.discourse.dbName }}"
|
||||
value: "{{ .dbName }}"
|
||||
- name: DISCOURSE_DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.dbPassword
|
||||
key: dbPassword
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
---
|
||||
# Source: discourse/templates/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -18,219 +17,133 @@ spec:
|
||||
component: web
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
component: web
|
||||
topologyKey: kubernetes.io/hostname
|
||||
weight: 1
|
||||
|
||||
serviceAccountName: discourse
|
||||
securityContext:
|
||||
fsGroup: 0
|
||||
fsGroupChangePolicy: Always
|
||||
supplementalGroups: []
|
||||
sysctls: []
|
||||
initContainers:
|
||||
containers:
|
||||
- name: discourse
|
||||
image: docker.io/bitnami/discourse:3.4.7-debian-12-r0
|
||||
image: tiredofit/discourse:latest
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
add:
|
||||
- CHOWN
|
||||
- SYS_CHROOT
|
||||
- DAC_OVERRIDE
|
||||
- FOWNER
|
||||
- SETGID
|
||||
- SETUID
|
||||
- DAC_OVERRIDE
|
||||
drop:
|
||||
- ALL
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: false
|
||||
runAsGroup: 0
|
||||
runAsNonRoot: false
|
||||
runAsUser: 0
|
||||
seLinuxOptions: {}
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
env:
|
||||
- name: BITNAMI_DEBUG
|
||||
value: "false"
|
||||
- name: DISCOURSE_PASSWORD
|
||||
# Admin configuration
|
||||
- name: ADMIN_USER
|
||||
value: {{ .adminUsername }}
|
||||
- name: ADMIN_EMAIL
|
||||
value: {{ .adminEmail }}
|
||||
- name: ADMIN_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.adminPassword
|
||||
- name: DISCOURSE_PORT_NUMBER
|
||||
value: "8080"
|
||||
- name: DISCOURSE_EXTERNAL_HTTP_PORT_NUMBER
|
||||
value: "80"
|
||||
- name: DISCOURSE_DATABASE_PASSWORD
|
||||
key: adminPassword
|
||||
# Site configuration
|
||||
- name: SITE_TITLE
|
||||
value: {{ .siteName }}
|
||||
- name: HOSTNAME
|
||||
value: {{ .domain }}
|
||||
# Database configuration
|
||||
- name: DB_HOST
|
||||
value: {{ .dbHostname }}
|
||||
- name: DB_PORT
|
||||
value: "{{ .dbPort }}"
|
||||
- name: DB_NAME
|
||||
value: {{ .dbName }}
|
||||
- name: DB_USER
|
||||
value: {{ .dbUsername }}
|
||||
- name: DB_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.dbPassword
|
||||
- name: POSTGRESQL_CLIENT_CREATE_DATABASE_PASSWORD
|
||||
key: dbPassword
|
||||
# Redis configuration
|
||||
- name: REDIS_HOST
|
||||
value: {{ .redisHostname }}
|
||||
- name: REDIS_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.dbPassword
|
||||
- name: DISCOURSE_REDIS_PASSWORD
|
||||
key: redis.password
|
||||
# SMTP configuration
|
||||
- name: SMTP_ENABLED
|
||||
value: "{{ .smtp.enabled }}"
|
||||
- name: SMTP_HOST
|
||||
value: {{ .smtp.host }}
|
||||
- name: SMTP_PORT
|
||||
value: "{{ .smtp.port }}"
|
||||
- name: SMTP_USER
|
||||
value: {{ .smtp.user }}
|
||||
- name: SMTP_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.redis.password
|
||||
- name: DISCOURSE_SECRET_KEY_BASE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.secretKeyBase
|
||||
- name: DISCOURSE_SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.smtpPassword
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.smtpPassword
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: discourse
|
||||
key: smtpPassword
|
||||
- name: SMTP_TLS
|
||||
value: "{{ .smtp.tls }}"
|
||||
# Container timezone
|
||||
- name: TZ
|
||||
value: {{ .timezone }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
containerPort: 3000
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 500
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
initialDelaySeconds: 420
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /srv/status
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 180
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
initialDelaySeconds: 360
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 10
|
||||
successThreshold: 1
|
||||
failureThreshold: 6
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1
|
||||
ephemeral-storage: 2Gi
|
||||
memory: 8Gi # for precompiling assets!
|
||||
cpu: 2000m
|
||||
ephemeral-storage: 10Gi
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 750m
|
||||
cpu: 500m
|
||||
ephemeral-storage: 50Mi
|
||||
memory: 1Gi
|
||||
volumeMounts:
|
||||
- name: discourse-data
|
||||
mountPath: /bitnami/discourse
|
||||
subPath: discourse
|
||||
- name: sidekiq
|
||||
image: docker.io/bitnami/discourse:3.4.7-debian-12-r0
|
||||
imagePullPolicy: "IfNotPresent"
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
add:
|
||||
- CHOWN
|
||||
- SYS_CHROOT
|
||||
- FOWNER
|
||||
- SETGID
|
||||
- SETUID
|
||||
- DAC_OVERRIDE
|
||||
drop:
|
||||
- ALL
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: false
|
||||
runAsGroup: 0
|
||||
runAsNonRoot: false
|
||||
runAsUser: 0
|
||||
seLinuxOptions: {}
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
command:
|
||||
- /opt/bitnami/scripts/discourse/entrypoint.sh
|
||||
args:
|
||||
- /opt/bitnami/scripts/discourse-sidekiq/run.sh
|
||||
env:
|
||||
- name: BITNAMI_DEBUG
|
||||
value: "false"
|
||||
- name: DISCOURSE_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.adminPassword
|
||||
- name: DISCOURSE_POSTGRESQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.dbPassword
|
||||
- name: DISCOURSE_REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.redis.password
|
||||
- name: DISCOURSE_SECRET_KEY_BASE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.secretKeyBase
|
||||
- name: DISCOURSE_SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.smtpPassword
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: discourse-secrets
|
||||
key: apps.discourse.smtpPassword
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: discourse
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["/bin/sh", "-c", "pgrep -f ^sidekiq"]
|
||||
initialDelaySeconds: 500
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
successThreshold: 1
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["/bin/sh", "-c", "pgrep -f ^sidekiq"]
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
successThreshold: 1
|
||||
failureThreshold: 6
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
ephemeral-storage: 2Gi
|
||||
memory: 768Mi
|
||||
requests:
|
||||
cpu: 375m
|
||||
ephemeral-storage: 50Mi
|
||||
memory: 512Mi
|
||||
volumeMounts:
|
||||
- name: discourse-data
|
||||
mountPath: /bitnami/discourse
|
||||
subPath: discourse
|
||||
- name: discourse-logs
|
||||
mountPath: /data/logs
|
||||
- name: discourse-uploads
|
||||
mountPath: /data/uploads
|
||||
- name: discourse-backups
|
||||
mountPath: /data/backups
|
||||
volumes:
|
||||
- name: discourse-data
|
||||
- name: discourse-logs
|
||||
persistentVolumeClaim:
|
||||
claimName: discourse
|
||||
claimName: discourse-logs
|
||||
- name: discourse-uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: discourse-uploads
|
||||
- name: discourse-backups
|
||||
persistentVolumeClaim:
|
||||
claimName: discourse-backups
|
||||
|
||||
@@ -4,13 +4,13 @@ apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: discourse
|
||||
namespace: "discourse"
|
||||
namespace: "{{ .namespace }}"
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}"
|
||||
external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}"
|
||||
spec:
|
||||
rules:
|
||||
- host: "{{ .apps.discourse.domain }}"
|
||||
- host: "{{ .domain }}"
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -22,5 +22,5 @@ spec:
|
||||
name: http
|
||||
tls:
|
||||
- hosts:
|
||||
- "{{ .apps.discourse.domain }}"
|
||||
- "{{ .domain }}"
|
||||
secretName: wildcard-external-wild-cloud-tls
|
||||
|
||||
@@ -10,7 +10,6 @@ labels:
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- serviceaccount.yaml
|
||||
- configmap.yaml
|
||||
- pvc.yaml
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
name: discourse
|
||||
description: Discourse is a modern, open-source discussion platform designed for online communities and forums.
|
||||
version: 3.4.7
|
||||
icon: https://www.discourse.org/img/icon.png
|
||||
version: 3.5.3
|
||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/discourse.svg
|
||||
requires:
|
||||
- name: postgres
|
||||
- name: redis
|
||||
defaultConfig:
|
||||
namespace: discourse
|
||||
externalDnsDomain: "{{ .cloud.domain }}"
|
||||
timezone: UTC
|
||||
port: 8080
|
||||
port: 3000
|
||||
storage: 10Gi
|
||||
adminEmail: admin@{{ .cloud.domain }}
|
||||
adminEmail: "{{ .operator.email }}"
|
||||
adminUsername: admin
|
||||
siteName: "Community"
|
||||
domain: discourse.{{ .cloud.domain }}
|
||||
dbHostname: postgres.postgres.svc.cluster.local
|
||||
dbHostname: "{{ .apps.postgres.host }}"
|
||||
dbPort: "{{ .apps.postgres.port }}"
|
||||
dbUsername: discourse
|
||||
dbName: discourse
|
||||
redisHostname: redis.redis.svc.cluster.local
|
||||
redisHostname: "{{ .apps.redis.host }}"
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
smtp:
|
||||
enabled: false
|
||||
@@ -24,13 +27,16 @@ defaultConfig:
|
||||
port: "{{ .cloud.smtp.port }}"
|
||||
user: "{{ .cloud.smtp.user }}"
|
||||
from: "{{ .cloud.smtp.from }}"
|
||||
tls: {{ .cloud.smtp.tls }}
|
||||
startTls: {{ .cloud.smtp.startTls }}
|
||||
tls: "{{ .cloud.smtp.tls }}"
|
||||
startTls: "{{ .cloud.smtp.startTls }}"
|
||||
defaultSecrets:
|
||||
- key: adminPassword
|
||||
- key: secretKeyBase
|
||||
default: "{{ random.AlphaNum 64 }}"
|
||||
- key: smtpPassword
|
||||
- key: dbPassword
|
||||
- key: dbUrl
|
||||
default: "postgres://{{ .app.dbUsername }}:{{ .secrets.dbPassword }}@{{ .app.dbHostname }}:{{ .app.dbPort }}/{{ .app.dbName }}?sslmode=disable"
|
||||
requiredSecrets:
|
||||
- apps.discourse.adminPassword
|
||||
- apps.discourse.dbPassword
|
||||
- apps.discourse.dbUrl
|
||||
- apps.redis.password
|
||||
- apps.discourse.secretKeyBase
|
||||
- apps.discourse.smtpPassword
|
||||
- apps.postgres.password
|
||||
- postgres.password
|
||||
- redis.password
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: discourse
|
||||
name: "{{ .namespace }}"
|
||||
|
||||
@@ -1,13 +1,39 @@
|
||||
---
|
||||
# Source: discourse/templates/pvc.yaml
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: discourse
|
||||
name: discourse-logs
|
||||
namespace: discourse
|
||||
spec:
|
||||
accessModes:
|
||||
- "ReadWriteOnce"
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: "{{ .apps.discourse.storage }}"
|
||||
storage: 2Gi
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: discourse-uploads
|
||||
namespace: discourse
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .storage }}
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: discourse-backups
|
||||
namespace: discourse
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
storageClassName: longhorn
|
||||
|
||||
@@ -3,7 +3,6 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: example-admin
|
||||
namespace: example-admin
|
||||
labels:
|
||||
app: example-admin
|
||||
spec:
|
||||
|
||||
@@ -3,10 +3,9 @@ apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-admin
|
||||
namespace: example-admin
|
||||
spec:
|
||||
rules:
|
||||
- host: example-admin.{{ .cloud.internalDomain }}
|
||||
- host: "{{ .host }}"
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -18,5 +17,5 @@ spec:
|
||||
number: 80
|
||||
tls:
|
||||
- hosts:
|
||||
- example-admin.{{ .cloud.internalDomain }}
|
||||
- "{{ .host }}"
|
||||
secretName: wildcard-internal-wild-cloud-tls
|
||||
|
||||
@@ -3,4 +3,7 @@ install: true
|
||||
description: An example application that is deployed with internal-only access.
|
||||
version: 1.0.0
|
||||
defaultConfig:
|
||||
namespace: example-admin
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
host: '{{ .host }}'
|
||||
tlsSecretName: wildcard-internal-wild-cloud-tls
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: example-admin
|
||||
name: "{{ .namespace }}"
|
||||
|
||||
@@ -4,7 +4,7 @@ kind: Ingress
|
||||
metadata:
|
||||
name: example-app
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/target: "{{ .cloud.externalDnsTarget }}"
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: false
|
||||
|
||||
# Optional: Enable HTTPS redirection
|
||||
@@ -15,7 +15,7 @@ metadata:
|
||||
# traefik.ingress.kubernetes.io/auth-secret: basic-auth
|
||||
spec:
|
||||
rules:
|
||||
- host: example-app.{{ .cloud.domain }}
|
||||
- host: "{{ .host }}"
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -27,5 +27,5 @@ spec:
|
||||
number: 80
|
||||
tls:
|
||||
- hosts:
|
||||
- example-app.{{ .cloud.domain }}
|
||||
- "{{ .host }}"
|
||||
secretName: wildcard-wild-cloud-tls
|
||||
|
||||
@@ -3,4 +3,7 @@ install: true
|
||||
description: An example application that is deployed with public access.
|
||||
version: 1.0.0
|
||||
defaultConfig:
|
||||
namespace: example-app
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
host: example-app.{{ .cloud.domain }}
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: example-app
|
||||
name: "{{ .namespace }}"
|
||||
|
||||
@@ -12,7 +12,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: db-init
|
||||
image: {{ .apps.mysql.image }}
|
||||
image: mysql:9.1.0
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
@@ -27,18 +27,18 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysql-secrets
|
||||
key: apps.mysql.rootPassword
|
||||
key: rootPassword
|
||||
- name: DB_HOSTNAME
|
||||
value: "{{ .apps.ghost.dbHost }}"
|
||||
value: "{{ .dbHost }}"
|
||||
- name: DB_PORT
|
||||
value: "{{ .apps.ghost.dbPort }}"
|
||||
value: "{{ .dbPort }}"
|
||||
- name: DB_DATABASE_NAME
|
||||
value: "{{ .apps.ghost.dbName }}"
|
||||
value: "{{ .dbName }}"
|
||||
- name: DB_USERNAME
|
||||
value: "{{ .apps.ghost.dbUser }}"
|
||||
value: "{{ .dbUser }}"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ghost-secrets
|
||||
key: apps.ghost.dbPassword
|
||||
key: dbPassword
|
||||
restartPolicy: OnFailure
|
||||
@@ -17,10 +17,10 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: ghost
|
||||
image: {{ .apps.ghost.image }}
|
||||
image: {{ .image }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .apps.ghost.port }}
|
||||
containerPort: {{ .port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: BITNAMI_DEBUG
|
||||
@@ -28,33 +28,33 @@ spec:
|
||||
- name: ALLOW_EMPTY_PASSWORD
|
||||
value: "yes"
|
||||
- name: GHOST_DATABASE_HOST
|
||||
value: {{ .apps.ghost.dbHost }}
|
||||
value: {{ .dbHost }}
|
||||
- name: GHOST_DATABASE_PORT_NUMBER
|
||||
value: "{{ .apps.ghost.dbPort }}"
|
||||
value: "{{ .dbPort }}"
|
||||
- name: GHOST_DATABASE_NAME
|
||||
value: {{ .apps.ghost.dbName }}
|
||||
value: {{ .dbName }}
|
||||
- name: GHOST_DATABASE_USER
|
||||
value: {{ .apps.ghost.dbUser }}
|
||||
value: {{ .dbUser }}
|
||||
- name: GHOST_DATABASE_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ghost-secrets
|
||||
key: apps.ghost.dbPassword
|
||||
key: dbPassword
|
||||
- name: GHOST_HOST
|
||||
value: {{ .apps.ghost.domain }}
|
||||
value: {{ .domain }}
|
||||
- name: GHOST_PORT_NUMBER
|
||||
value: "{{ .apps.ghost.port }}"
|
||||
value: "{{ .port }}"
|
||||
- name: GHOST_USERNAME
|
||||
value: {{ .apps.ghost.adminUser }}
|
||||
value: {{ .adminUser }}
|
||||
- name: GHOST_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ghost-secrets
|
||||
key: apps.ghost.adminPassword
|
||||
key: adminPassword
|
||||
- name: GHOST_EMAIL
|
||||
value: {{ .apps.ghost.adminEmail }}
|
||||
value: {{ .adminEmail }}
|
||||
- name: GHOST_BLOG_TITLE
|
||||
value: {{ .apps.ghost.blogTitle }}
|
||||
value: {{ .blogTitle }}
|
||||
- name: GHOST_ENABLE_HTTPS
|
||||
value: "yes"
|
||||
- name: GHOST_EXTERNAL_HTTP_PORT_NUMBER
|
||||
@@ -66,18 +66,18 @@ spec:
|
||||
- name: GHOST_SMTP_SERVICE
|
||||
value: SMTP
|
||||
- name: GHOST_SMTP_HOST
|
||||
value: {{ .apps.ghost.smtp.host }}
|
||||
value: {{ .smtp.host }}
|
||||
- name: GHOST_SMTP_PORT
|
||||
value: "{{ .apps.ghost.smtp.port }}"
|
||||
value: "{{ .smtp.port }}"
|
||||
- name: GHOST_SMTP_USER
|
||||
value: {{ .apps.ghost.smtp.user }}
|
||||
value: {{ .smtp.user }}
|
||||
- name: GHOST_SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ghost-secrets
|
||||
key: apps.ghost.smtpPassword
|
||||
key: smtpPassword
|
||||
- name: GHOST_SMTP_FROM_ADDRESS
|
||||
value: {{ .apps.ghost.smtp.from }}
|
||||
value: {{ .smtp.from }}
|
||||
resources:
|
||||
limits:
|
||||
cpu: 375m
|
||||
@@ -92,7 +92,7 @@ spec:
|
||||
mountPath: /bitnami/ghost
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: {{ .apps.ghost.port }}
|
||||
port: {{ .port }}
|
||||
initialDelaySeconds: 120
|
||||
timeoutSeconds: 5
|
||||
periodSeconds: 10
|
||||
|
||||
@@ -7,12 +7,12 @@ metadata:
|
||||
kubernetes.io/ingress.class: "traefik"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
|
||||
external-dns.alpha.kubernetes.io/ttl: "60"
|
||||
traefik.ingress.kubernetes.io/redirect-entry-point: https
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ .apps.ghost.domain }}
|
||||
- host: {{ .domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -24,5 +24,5 @@ spec:
|
||||
number: 80
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .apps.ghost.domain }}
|
||||
secretName: {{ .apps.ghost.tlsSecretName }}
|
||||
- {{ .domain }}
|
||||
secretName: {{ .tlsSecretName }}
|
||||
@@ -1,10 +1,13 @@
|
||||
name: ghost
|
||||
description: Ghost is a powerful app for new-media creators to publish, share, and grow a business around their content.
|
||||
description: Ghost is a powerful app for new-media creators to publish, share, and
|
||||
grow a business around their content.
|
||||
version: 5.118.1
|
||||
icon: https://ghost.org/images/logos/ghost-logo-orb.png
|
||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/ghost.png
|
||||
requires:
|
||||
- name: mysql
|
||||
- name: mysql
|
||||
defaultConfig:
|
||||
namespace: ghost
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
image: docker.io/bitnami/ghost:5.118.1-debian-12-r0
|
||||
domain: ghost.{{ .cloud.domain }}
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
@@ -15,16 +18,17 @@ defaultConfig:
|
||||
dbName: ghost
|
||||
dbUser: ghost
|
||||
adminUser: admin
|
||||
adminEmail: "admin@{{ .cloud.domain }}"
|
||||
blogTitle: "My Blog"
|
||||
adminEmail: {{ .operator.email }}
|
||||
blogTitle: My Blog
|
||||
timezone: UTC
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
smtp:
|
||||
host: "{{ .cloud.smtp.host }}"
|
||||
port: "{{ .cloud.smtp.port }}"
|
||||
from: "{{ .cloud.smtp.from }}"
|
||||
user: "{{ .cloud.smtp.user }}"
|
||||
host: '{{ .cloud.smtp.host }}'
|
||||
port: '{{ .cloud.smtp.port }}'
|
||||
from: '{{ .cloud.smtp.from }}'
|
||||
user: '{{ .cloud.smtp.user }}'
|
||||
defaultSecrets:
|
||||
- key: adminPassword
|
||||
- key: dbPassword
|
||||
- key: smtpPassword
|
||||
requiredSecrets:
|
||||
- apps.ghost.adminPassword
|
||||
- apps.ghost.dbPassword
|
||||
- apps.ghost.smtpPassword
|
||||
- mysql.rootPassword
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ghost
|
||||
name: "{{ .namespace }}"
|
||||
@@ -8,4 +8,4 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.ghost.storage }}
|
||||
storage: {{ .storage }}
|
||||
@@ -9,6 +9,6 @@ spec:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: {{ .apps.ghost.port }}
|
||||
targetPort: {{ .port }}
|
||||
selector:
|
||||
component: web
|
||||
@@ -20,7 +20,7 @@ Sensitive configuration is stored in the `gitea-secrets` secret and managed by t
|
||||
- `dbPassword` - Database password
|
||||
- `smtpPassword` - SMTP authentication password
|
||||
|
||||
Secrets are defined in `secrets.yaml` and listed in `manifest.yaml` under `requiredSecrets`. When deploying, the system automatically ensures all required secrets exist in the `gitea-secrets` secret before deployment.
|
||||
Secrets are defined in `secrets.yaml` and listed in `manifest.yaml` under `defaultSecrets`. When deploying, the system automatically ensures all required secrets exist in the `gitea-secrets` secret before deployment.
|
||||
|
||||
### Persistent Configuration (app.ini)
|
||||
Gitea manages its own `app.ini` file on persistent storage for:
|
||||
@@ -46,7 +46,7 @@ Gitea manages its own `app.ini` file on persistent storage for:
|
||||
|
||||
### Secret Settings
|
||||
1. Edit `secrets.yaml` with your secret values
|
||||
2. Ensure the secret key is listed in `manifest.yaml` under `requiredSecrets`
|
||||
2. Ensure the secret key is listed in `manifest.yaml` under `defaultSecrets`
|
||||
3. Deploy the app via the web app, CLI, or API - this will automatically update the `gitea-secrets` secret and restart the pod
|
||||
|
||||
### Web UI Changes
|
||||
|
||||
@@ -12,7 +12,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: db-init
|
||||
image: {{ .apps.postgres.image }}
|
||||
image: postgres:17
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
@@ -36,16 +36,16 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-secrets
|
||||
key: apps.postgres.password
|
||||
key: password
|
||||
- name: DB_HOSTNAME
|
||||
value: "{{ .apps.gitea.dbHost }}"
|
||||
value: "{{ .dbHost }}"
|
||||
- name: DB_DATABASE_NAME
|
||||
value: "{{ .apps.gitea.dbName }}"
|
||||
value: "{{ .dbName }}"
|
||||
- name: DB_USERNAME
|
||||
value: "{{ .apps.gitea.dbUser }}"
|
||||
value: "{{ .dbUser }}"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: apps.gitea.dbPassword
|
||||
key: dbPassword
|
||||
restartPolicy: OnFailure
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
terminationGracePeriodSeconds: 60
|
||||
containers:
|
||||
- name: gitea
|
||||
image: "{{ .apps.gitea.image }}"
|
||||
image: "{{ .image }}"
|
||||
imagePullPolicy: IfNotPresent
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
@@ -33,27 +33,27 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: apps.gitea.adminPassword
|
||||
key: adminPassword
|
||||
- name: GITEA__security__SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: apps.gitea.secretKey
|
||||
key: secretKey
|
||||
- name: GITEA__security__INTERNAL_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: apps.gitea.jwtSecret
|
||||
key: jwtSecret
|
||||
- name: GITEA__database__PASSWD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: apps.gitea.dbPassword
|
||||
key: dbPassword
|
||||
- name: GITEA__mailer__PASSWD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: apps.gitea.smtpPassword
|
||||
key: smtpPassword
|
||||
ports:
|
||||
- name: ssh
|
||||
containerPort: 2222
|
||||
|
||||
@@ -3,12 +3,12 @@ SSH_PORT=22
|
||||
GITEA_WORK_DIR=/data
|
||||
GITEA_TEMP=/tmp/gitea
|
||||
TMPDIR=/tmp/gitea
|
||||
GITEA_ADMIN_USERNAME={{ .apps.gitea.adminUser }}
|
||||
GITEA_ADMIN_USERNAME={{ .adminUser }}
|
||||
GITEA_ADMIN_PASSWORD_MODE=keepUpdated
|
||||
|
||||
# Core app settings
|
||||
GITEA____APP_NAME={{ .apps.gitea.appName }}
|
||||
GITEA____RUN_MODE={{ .apps.gitea.runMode }}
|
||||
GITEA____APP_NAME={{ .appName }}
|
||||
GITEA____RUN_MODE={{ .runMode }}
|
||||
GITEA____RUN_USER=git
|
||||
|
||||
# Security settings
|
||||
@@ -17,19 +17,19 @@ GITEA__security__PASSWORD_HASH_ALGO=pbkdf2
|
||||
|
||||
# Database settings (except password which comes from secret)
|
||||
GITEA__database__DB_TYPE=postgres
|
||||
GITEA__database__HOST={{ .apps.gitea.dbHost }}:{{ .apps.gitea.dbPort }}
|
||||
GITEA__database__NAME={{ .apps.gitea.dbName }}
|
||||
GITEA__database__USER={{ .apps.gitea.dbUser }}
|
||||
GITEA__database__HOST={{ .dbHost }}:{{ .dbPort }}
|
||||
GITEA__database__NAME={{ .dbName }}
|
||||
GITEA__database__USER={{ .dbUser }}
|
||||
GITEA__database__SSL_MODE=disable
|
||||
GITEA__database__LOG_SQL=false
|
||||
|
||||
# Server settings
|
||||
GITEA__server__DOMAIN={{ .apps.gitea.domain }}
|
||||
GITEA__server__HTTP_PORT={{ .apps.gitea.port }}
|
||||
GITEA__server__ROOT_URL=https://{{ .apps.gitea.domain }}/
|
||||
GITEA__server__DOMAIN={{ .domain }}
|
||||
GITEA__server__HTTP_PORT={{ .port }}
|
||||
GITEA__server__ROOT_URL=https://{{ .domain }}/
|
||||
GITEA__server__DISABLE_SSH=false
|
||||
GITEA__server__SSH_DOMAIN={{ .apps.gitea.domain }}
|
||||
GITEA__server__SSH_PORT={{ .apps.gitea.sshPort }}
|
||||
GITEA__server__SSH_DOMAIN={{ .domain }}
|
||||
GITEA__server__SSH_PORT={{ .sshPort }}
|
||||
GITEA__server__SSH_LISTEN_PORT=2222
|
||||
GITEA__server__LFS_START_SERVER=true
|
||||
GITEA__server__OFFLINE_MODE=true
|
||||
@@ -53,8 +53,8 @@ GITEA__webhook__ALLOWED_HOST_LIST=*
|
||||
|
||||
# Mailer settings (enabled via env vars, password from secret)
|
||||
GITEA__mailer__ENABLED=true
|
||||
GITEA__mailer__SMTP_ADDR={{ .apps.gitea.smtp.host }}
|
||||
GITEA__mailer__SMTP_PORT={{ .apps.gitea.smtp.port }}
|
||||
GITEA__mailer__FROM={{ .apps.gitea.smtp.from }}
|
||||
GITEA__mailer__USER={{ .apps.gitea.smtp.user }}
|
||||
GITEA__mailer__SMTP_ADDR={{ .smtp.host }}
|
||||
GITEA__mailer__SMTP_PORT={{ .smtp.port }}
|
||||
GITEA__mailer__FROM={{ .smtp.from }}
|
||||
GITEA__mailer__USER={{ .smtp.user }}
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ metadata:
|
||||
namespace: gitea
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}"
|
||||
external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}"
|
||||
spec:
|
||||
rules:
|
||||
- host: "{{ .apps.gitea.domain }}"
|
||||
- host: "{{ .domain }}"
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -19,6 +19,6 @@ spec:
|
||||
port:
|
||||
number: 3000
|
||||
tls:
|
||||
- secretName: "{{ .apps.gitea.tlsSecretName }}"
|
||||
- secretName: "{{ .tlsSecretName }}"
|
||||
hosts:
|
||||
- "{{ .apps.gitea.domain }}"
|
||||
- "{{ .domain }}"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
name: gitea
|
||||
description: Gitea is a painless self-hosted Git service written in Go
|
||||
version: 1.24.3
|
||||
icon: https://github.com/go-gitea/gitea/raw/main/assets/logo.png
|
||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gitea.svg
|
||||
requires:
|
||||
- name: postgres
|
||||
- name: postgres
|
||||
defaultConfig:
|
||||
namespace: gitea
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
image: gitea/gitea:1.24.3
|
||||
appName: Gitea
|
||||
domain: gitea.{{ .cloud.domain }}
|
||||
@@ -16,18 +18,20 @@ defaultConfig:
|
||||
dbUser: gitea
|
||||
dbHost: postgres.postgres.svc.cluster.local
|
||||
adminUser: admin
|
||||
adminEmail: "admin@{{ .cloud.domain }}"
|
||||
adminEmail: "{{ .operator.email }}"
|
||||
dbPort: 5432
|
||||
timezone: UTC
|
||||
runMode: prod
|
||||
smtp:
|
||||
host: TBD
|
||||
port: 465
|
||||
from: no-reply@{{ .cloud.domain }}
|
||||
user: TBD
|
||||
host: '{{ .cloud.smtp.host }}'
|
||||
port: '{{ .cloud.smtp.port }}'
|
||||
user: '{{ .cloud.smtp.user }}'
|
||||
from: '{{ .cloud.smtp.from }}'
|
||||
defaultSecrets:
|
||||
- key: adminPassword
|
||||
- key: dbPassword
|
||||
- key: secretKey
|
||||
- key: jwtSecret
|
||||
- key: smtpPassword
|
||||
requiredSecrets:
|
||||
- apps.gitea.adminPassword
|
||||
- apps.gitea.dbPassword
|
||||
- apps.gitea.secretKey
|
||||
- apps.gitea.jwtSecret
|
||||
- apps.gitea.smtpPassword
|
||||
- postgres.password
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: gitea
|
||||
name: "{{ .namespace }}"
|
||||
@@ -9,4 +9,4 @@ spec:
|
||||
storageClassName: longhorn
|
||||
resources:
|
||||
requests:
|
||||
storage: "{{ .apps.gitea.storage }}"
|
||||
storage: "{{ .storage }}"
|
||||
@@ -8,7 +8,7 @@ spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 3000
|
||||
targetPort: {{ .apps.gitea.port }}
|
||||
targetPort: {{ .port }}
|
||||
selector:
|
||||
component: web
|
||||
---
|
||||
@@ -21,7 +21,7 @@ spec:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- name: ssh
|
||||
port: {{ .apps.gitea.sshPort }}
|
||||
port: {{ .sshPort }}
|
||||
targetPort: 2222
|
||||
protocol: TCP
|
||||
selector:
|
||||
|
||||
@@ -7,7 +7,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: db-init
|
||||
image: {{ .apps.postgres.image }}
|
||||
image: postgres:17
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
@@ -53,16 +53,16 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-secrets
|
||||
key: apps.postgres.password
|
||||
key: postgres.password
|
||||
- name: DB_HOSTNAME
|
||||
value: "{{ .apps.immich.dbHostname }}"
|
||||
value: "{{ .dbHostname }}"
|
||||
- name: DB_DATABASE_NAME
|
||||
value: "{{ .apps.immich.dbUsername }}"
|
||||
value: "{{ .dbUsername }}"
|
||||
- name: DB_USERNAME
|
||||
value: "{{ .apps.immich.dbUsername }}"
|
||||
value: "{{ .dbUsername }}"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-secrets
|
||||
key: apps.immich.dbPassword
|
||||
key: dbPassword
|
||||
restartPolicy: OnFailure
|
||||
|
||||
@@ -15,14 +15,14 @@ spec:
|
||||
component: machine-learning
|
||||
spec:
|
||||
containers:
|
||||
- image: "{{ .apps.immich.mlImage }}"
|
||||
- image: "{{ .mlImage }}"
|
||||
name: immich-machine-learning
|
||||
ports:
|
||||
- containerPort: {{ .apps.immich.mlPort }}
|
||||
- containerPort: {{ .mlPort }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: TZ
|
||||
value: "{{ .apps.immich.timezone }}"
|
||||
value: "{{ .timezone }}"
|
||||
volumeMounts:
|
||||
- mountPath: /cache
|
||||
name: immich-cache
|
||||
|
||||
@@ -20,27 +20,27 @@ spec:
|
||||
component: microservices
|
||||
spec:
|
||||
containers:
|
||||
- image: "{{ .apps.immich.serverImage }}"
|
||||
- image: "{{ .serverImage }}"
|
||||
name: immich-microservices
|
||||
env:
|
||||
- name: REDIS_HOSTNAME
|
||||
value: "{{ .apps.immich.redisHostname }}"
|
||||
value: "{{ .redisHostname }}"
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-secrets
|
||||
key: apps.redis.password
|
||||
key: redis.password
|
||||
- name: DB_HOSTNAME
|
||||
value: "{{ .apps.immich.dbHostname }}"
|
||||
value: "{{ .dbHostname }}"
|
||||
- name: DB_USERNAME
|
||||
value: "{{ .apps.immich.dbUsername }}"
|
||||
value: "{{ .dbUsername }}"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-secrets
|
||||
key: apps.immich.dbPassword
|
||||
key: dbPassword
|
||||
- name: TZ
|
||||
value: "{{ .apps.immich.timezone }}"
|
||||
value: "{{ .timezone }}"
|
||||
- name: IMMICH_WORKERS_EXCLUDE
|
||||
value: api
|
||||
volumeMounts:
|
||||
|
||||
@@ -20,30 +20,30 @@ spec:
|
||||
component: server
|
||||
spec:
|
||||
containers:
|
||||
- image: "{{ .apps.immich.serverImage }}"
|
||||
- image: "{{ .serverImage }}"
|
||||
name: immich-server
|
||||
ports:
|
||||
- containerPort: {{ .apps.immich.serverPort }}
|
||||
- containerPort: {{ .serverPort }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: REDIS_HOSTNAME
|
||||
value: "{{ .apps.immich.redisHostname }}"
|
||||
value: "{{ .redisHostname }}"
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-secrets
|
||||
key: apps.redis.password
|
||||
key: redis.password
|
||||
- name: DB_HOSTNAME
|
||||
value: "{{ .apps.immich.dbHostname }}"
|
||||
value: "{{ .dbHostname }}"
|
||||
- name: DB_USERNAME
|
||||
value: "{{ .apps.immich.dbUsername }}"
|
||||
value: "{{ .dbUsername }}"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-secrets
|
||||
key: apps.immich.dbPassword
|
||||
key: dbPassword
|
||||
- name: TZ
|
||||
value: "{{ .apps.immich.timezone }}"
|
||||
value: "{{ .timezone }}"
|
||||
- name: IMMICH_WORKERS_EXCLUDE
|
||||
value: microservices
|
||||
volumeMounts:
|
||||
|
||||
@@ -4,11 +4,11 @@ kind: Ingress
|
||||
metadata:
|
||||
name: immich-public
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/target: "{{ .cloud.domain }}"
|
||||
external-dns.alpha.kubernetes.io/target: "{{ .externalDnsDomain }}"
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
spec:
|
||||
rules:
|
||||
- host: "{{ .apps.immich.domain }}"
|
||||
- host: "{{ .domain }}"
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -21,4 +21,4 @@ spec:
|
||||
tls:
|
||||
- secretName: wildcard-wild-cloud-tls
|
||||
hosts:
|
||||
- "{{ .apps.immich.domain }}"
|
||||
- "{{ .domain }}"
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
name: immich
|
||||
install: true
|
||||
description: Immich is a self-hosted photo and video backup solution that allows you to store, manage, and share your media files securely.
|
||||
version: 1.0.0
|
||||
icon: https://immich.app/assets/images/logo.png
|
||||
description: Immich is a self-hosted photo and video backup solution that allows you
|
||||
to store, manage, and share your media files securely.
|
||||
version: release
|
||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/immich.svg
|
||||
requires:
|
||||
- name: redis
|
||||
- name: postgres
|
||||
- name: redis
|
||||
- name: postgres
|
||||
defaultConfig:
|
||||
namespace: immich
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
serverImage: ghcr.io/immich-app/immich-server:release
|
||||
mlImage: ghcr.io/immich-app/immich-machine-learning:release
|
||||
timezone: UTC
|
||||
@@ -19,7 +22,8 @@ defaultConfig:
|
||||
dbUsername: immich
|
||||
domain: immich.{{ .cloud.domain }}
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
defaultSecrets:
|
||||
- key: dbPassword
|
||||
requiredSecrets:
|
||||
- apps.immich.dbPassword
|
||||
- apps.postgres.password
|
||||
- apps.redis.password
|
||||
- redis.password
|
||||
- postgres.password
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: immich
|
||||
name: "{{ .namespace }}"
|
||||
@@ -9,7 +9,7 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.immich.storage }}
|
||||
storage: {{ .storage }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
@@ -21,4 +21,4 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.immich.cacheStorage }}
|
||||
storage: {{ .cacheStorage }}
|
||||
|
||||
@@ -9,7 +9,7 @@ metadata:
|
||||
spec:
|
||||
ports:
|
||||
- port: 3001
|
||||
targetPort: {{ .apps.immich.serverPort }}
|
||||
targetPort: {{ .serverPort }}
|
||||
selector:
|
||||
app: immich
|
||||
component: server
|
||||
@@ -25,7 +25,7 @@ metadata:
|
||||
app: immich-machine-learning
|
||||
spec:
|
||||
ports:
|
||||
- port: {{ .apps.immich.mlPort }}
|
||||
- port: {{ .mlPort }}
|
||||
selector:
|
||||
app: immich
|
||||
component: machine-learning
|
||||
|
||||
@@ -26,23 +26,23 @@ spec:
|
||||
readOnlyRootFilesystem: false
|
||||
env:
|
||||
- name: PGHOST
|
||||
value: {{ .apps.keila.dbHostname }}
|
||||
value: {{ .dbHostname }}
|
||||
- name: PGUSER
|
||||
value: postgres
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keila-secrets
|
||||
key: apps.postgres.password
|
||||
key: postgres.password
|
||||
- name: DB_NAME
|
||||
value: {{ .apps.keila.dbName }}
|
||||
value: {{ .dbName }}
|
||||
- name: DB_USER
|
||||
value: {{ .apps.keila.dbUsername }}
|
||||
value: {{ .dbUsername }}
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keila-secrets
|
||||
key: apps.keila.dbPassword
|
||||
key: dbPassword
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
|
||||
@@ -14,54 +14,54 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: keila
|
||||
image: {{ .apps.keila.image }}
|
||||
image: "{{ .image }}"
|
||||
ports:
|
||||
- containerPort: {{ .apps.keila.port }}
|
||||
- containerPort: {{ .port }}
|
||||
env:
|
||||
- name: DB_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keila-secrets
|
||||
key: apps.keila.dbUrl
|
||||
key: dbUrl
|
||||
- name: URL_HOST
|
||||
value: {{ .apps.keila.domain }}
|
||||
value: "{{ .domain }}"
|
||||
- name: URL_SCHEMA
|
||||
value: https
|
||||
- name: URL_PORT
|
||||
value: "443"
|
||||
- name: PORT
|
||||
value: "{{ .apps.keila.port }}"
|
||||
value: "{{ .port }}"
|
||||
- name: SECRET_KEY_BASE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keila-secrets
|
||||
key: apps.keila.secretKeyBase
|
||||
key: secretKeyBase
|
||||
- name: MAILER_SMTP_HOST
|
||||
value: {{ .apps.keila.smtp.host }}
|
||||
value: "{{ .smtp.host }}"
|
||||
- name: MAILER_SMTP_PORT
|
||||
value: "{{ .apps.keila.smtp.port }}"
|
||||
value: "{{ .smtp.port }}"
|
||||
- name: MAILER_ENABLE_SSL
|
||||
value: "{{ .apps.keila.smtp.tls }}"
|
||||
value: "{{ .smtp.tls }}"
|
||||
- name: MAILER_ENABLE_STARTTLS
|
||||
value: "{{ .apps.keila.smtp.startTls }}"
|
||||
value: "{{ .smtp.startTls }}"
|
||||
- name: MAILER_SMTP_USER
|
||||
value: {{ .apps.keila.smtp.user }}
|
||||
value: "{{ .smtp.user }}"
|
||||
- name: MAILER_SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keila-secrets
|
||||
key: apps.keila.smtpPassword
|
||||
key: smtpPassword
|
||||
- name: MAILER_SMTP_FROM_EMAIL
|
||||
value: {{ .apps.keila.smtp.from }}
|
||||
value: "{{ .smtp.from }}"
|
||||
- name: DISABLE_REGISTRATION
|
||||
value: "{{ .apps.keila.disableRegistration }}"
|
||||
value: "{{ .disableRegistration }}"
|
||||
- name: KEILA_USER
|
||||
value: "{{ .apps.keila.adminUser }}"
|
||||
value: "{{ .adminUser }}"
|
||||
- name: KEILA_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keila-secrets
|
||||
key: apps.keila.adminPassword
|
||||
key: adminPassword
|
||||
- name: USER_CONTENT_DIR
|
||||
value: /var/lib/keila/uploads
|
||||
volumeMounts:
|
||||
@@ -70,13 +70,13 @@ spec:
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: {{ .apps.keila.port }}
|
||||
port: {{ .port }}
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: {{ .apps.keila.port }}
|
||||
port: {{ .port }}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
volumes:
|
||||
|
||||
@@ -5,12 +5,12 @@ metadata:
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
traefik.ingress.kubernetes.io/router.middlewares: keila-cors@kubernetescrd
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ .apps.keila.domain }}
|
||||
- host: {{ .domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -23,4 +23,4 @@ spec:
|
||||
tls:
|
||||
- secretName: "wildcard-wild-cloud-tls"
|
||||
hosts:
|
||||
- "{{ .apps.keila.domain }}"
|
||||
- "{{ .domain }}"
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
name: keila
|
||||
description: Keila is an open-source email marketing platform that allows you to send newsletters and manage mailing lists with privacy and control.
|
||||
version: 1.0.0
|
||||
icon: https://www.keila.io/images/logo.svg
|
||||
version: 0.17.1
|
||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/keila.svg
|
||||
requires:
|
||||
- name: postgres
|
||||
defaultConfig:
|
||||
image: pentacent/keila:latest
|
||||
namespace: keila
|
||||
externalDnsDomain: "{{ .cloud.domain }}"
|
||||
image: pentacent/keila:0.17.1
|
||||
port: 4000
|
||||
storage: 1Gi
|
||||
domain: keila.{{ .cloud.domain }}
|
||||
dbHostname: postgres.postgres.svc.cluster.local
|
||||
dbHostname: "{{ .apps.postgres.host }}"
|
||||
dbPort: "{{ .apps.postgres.port }}"
|
||||
dbName: keila
|
||||
dbUsername: keila
|
||||
disableRegistration: "true"
|
||||
@@ -20,12 +23,15 @@ defaultConfig:
|
||||
port: "{{ .cloud.smtp.port }}"
|
||||
from: "{{ .cloud.smtp.from }}"
|
||||
user: "{{ .cloud.smtp.user }}"
|
||||
tls: {{ .cloud.smtp.tls }}
|
||||
startTls: {{ .cloud.smtp.startTls }}
|
||||
tls: "{{ .cloud.smtp.tls }}"
|
||||
startTls: "{{ .cloud.smtp.startTls }}"
|
||||
defaultSecrets:
|
||||
- key: secretKeyBase
|
||||
default: "{{ random.AlphaNum 64 }}"
|
||||
- key: dbPassword
|
||||
- key: dbUrl
|
||||
default: "postgres://{{ .app.dbUsername }}:{{ .secrets.dbPassword }}@{{ .app.dbHostname }}:{{ .app.dbPort }}/keila?sslmode=disable"
|
||||
- key: adminPassword
|
||||
- key: smtpPassword
|
||||
requiredSecrets:
|
||||
- apps.keila.secretKeyBase
|
||||
- apps.keila.dbPassword
|
||||
- apps.keila.dbUrl
|
||||
- apps.keila.adminPassword
|
||||
- apps.keila.smtpPassword
|
||||
- apps.postgres.password
|
||||
- postgres.password
|
||||
@@ -21,8 +21,8 @@ spec:
|
||||
- "OPTIONS"
|
||||
accessControlAllowOriginList:
|
||||
- "http://localhost:1313"
|
||||
- "https://*.{{ .cloud.domain }}"
|
||||
- "https://{{ .cloud.domain }}"
|
||||
- "https://*.{{ .externalDnsDomain }}"
|
||||
- "https://{{ .externalDnsDomain }}"
|
||||
accessControlExposeHeaders:
|
||||
- "*"
|
||||
accessControlMaxAge: 86400
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: keila
|
||||
name: "{{ .namespace }}"
|
||||
@@ -7,4 +7,4 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.keila.storage }}
|
||||
storage: {{ .storage }}
|
||||
@@ -7,5 +7,5 @@ spec:
|
||||
component: web
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: {{ .apps.keila.port }}
|
||||
targetPort: {{ .port }}
|
||||
protocol: TCP
|
||||
@@ -28,23 +28,23 @@ spec:
|
||||
readOnlyRootFilesystem: false
|
||||
env:
|
||||
- name: PGHOST
|
||||
value: {{ .apps.listmonk.dbHost }}
|
||||
value: {{ .dbHost }}
|
||||
- name: PGUSER
|
||||
value: postgres
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: listmonk-secrets
|
||||
key: apps.postgres.password
|
||||
key: postgres.password
|
||||
- name: DB_NAME
|
||||
value: {{ .apps.listmonk.dbName }}
|
||||
value: {{ .dbName }}
|
||||
- name: DB_USER
|
||||
value: {{ .apps.listmonk.dbUser }}
|
||||
value: {{ .dbUser }}
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: listmonk-secrets
|
||||
key: apps.listmonk.dbPassword
|
||||
key: dbPassword
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
|
||||
@@ -30,21 +30,23 @@ spec:
|
||||
env:
|
||||
- name: LISTMONK_app__address
|
||||
value: "0.0.0.0:9000"
|
||||
- name: LISTMONK_app__root_url
|
||||
value: "{{ .rootUrl }}"
|
||||
- name: LISTMONK_db__host
|
||||
value: {{ .apps.listmonk.dbHost }}
|
||||
value: {{ .dbHost }}
|
||||
- name: LISTMONK_db__port
|
||||
value: "{{ .apps.listmonk.dbPort }}"
|
||||
value: "{{ .dbPort }}"
|
||||
- name: LISTMONK_db__user
|
||||
value: {{ .apps.listmonk.dbUser }}
|
||||
value: {{ .dbUser }}
|
||||
- name: LISTMONK_db__database
|
||||
value: {{ .apps.listmonk.dbName }}
|
||||
value: {{ .dbName }}
|
||||
- name: LISTMONK_db__ssl_mode
|
||||
value: {{ .apps.listmonk.dbSSLMode }}
|
||||
value: {{ .dbSSLMode }}
|
||||
- name: LISTMONK_db__password
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: listmonk-secrets
|
||||
key: apps.listmonk.dbPassword
|
||||
key: dbPassword
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
|
||||
@@ -6,16 +6,16 @@ metadata:
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .apps.listmonk.domain }}
|
||||
secretName: {{ .apps.listmonk.tlsSecretName }}
|
||||
- {{ .domain }}
|
||||
secretName: {{ .tlsSecretName }}
|
||||
rules:
|
||||
- host: {{ .apps.listmonk.domain }}
|
||||
- host: {{ .domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
name: listmonk
|
||||
description: Listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary.
|
||||
description: Listmonk is a standalone, self-hosted, newsletter and mailing list manager.
|
||||
It is fast, feature-rich, and packed into a single binary.
|
||||
version: 5.0.3
|
||||
icon: https://listmonk.app/static/images/logo.svg
|
||||
requires:
|
||||
- name: postgres
|
||||
- name: postgres
|
||||
defaultConfig:
|
||||
namespace: listmonk
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
domain: listmonk.{{ .cloud.domain }}
|
||||
rootUrl: https://listmonk.{{ .cloud.domain }}
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
storage: 1Gi
|
||||
dbHost: postgres.postgres.svc.cluster.local
|
||||
@@ -14,7 +18,9 @@ defaultConfig:
|
||||
dbUser: listmonk
|
||||
dbSSLMode: disable
|
||||
timezone: UTC
|
||||
defaultSecrets:
|
||||
- key: dbPassword
|
||||
- key: dbUrl
|
||||
default: 'postgres://{{ .app.dbUser }}:{{ .secrets.dbPassword }}@{{ .app.dbHost }}:{{ .app.dbPort }}/{{ .app.dbName }}?sslmode={{ .app.dbSSLMode }}'
|
||||
requiredSecrets:
|
||||
- apps.listmonk.dbPassword
|
||||
- apps.listmonk.dbUrl
|
||||
- apps.postgres.password
|
||||
- postgres.password
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: listmonk
|
||||
name: "{{ .namespace }}"
|
||||
@@ -8,4 +8,4 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.listmonk.storage }}
|
||||
storage: {{ .storage }}
|
||||
64
loomio/db-init-job.yaml
Normal file
64
loomio/db-init-job.yaml
Normal file
@@ -0,0 +1,64 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: loomio-db-init
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: db-init
|
||||
image: postgres:15-alpine
|
||||
env:
|
||||
- name: PGHOST
|
||||
value: "{{ .db.host }}"
|
||||
- name: PGPORT
|
||||
value: "{{ .db.port }}"
|
||||
- name: PGUSER
|
||||
value: postgres
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-secrets
|
||||
key: postgres.password
|
||||
- name: LOOMIO_DB_NAME
|
||||
value: "{{ .db.name }}"
|
||||
- name: LOOMIO_DB_USER
|
||||
value: "{{ .db.user }}"
|
||||
- name: LOOMIO_DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: dbPassword
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
echo "Creating database and user for Loomio..."
|
||||
|
||||
# Check if database exists, create if not
|
||||
psql -tc "SELECT 1 FROM pg_database WHERE datname = '$LOOMIO_DB_NAME'" | grep -q 1 || \
|
||||
psql -c "CREATE DATABASE \"$LOOMIO_DB_NAME\""
|
||||
|
||||
# Check if user exists, create or update password
|
||||
psql -tc "SELECT 1 FROM pg_user WHERE usename = '$LOOMIO_DB_USER'" | grep -q 1 && \
|
||||
psql -c "ALTER USER \"$LOOMIO_DB_USER\" WITH PASSWORD '$LOOMIO_DB_PASSWORD'" || \
|
||||
psql -c "CREATE USER \"$LOOMIO_DB_USER\" WITH PASSWORD '$LOOMIO_DB_PASSWORD'"
|
||||
|
||||
# Grant all privileges
|
||||
psql -c "GRANT ALL PRIVILEGES ON DATABASE \"$LOOMIO_DB_NAME\" TO \"$LOOMIO_DB_USER\""
|
||||
|
||||
# Connect to the database and grant schema permissions
|
||||
psql -d "$LOOMIO_DB_NAME" -c "GRANT ALL ON SCHEMA public TO \"$LOOMIO_DB_USER\""
|
||||
|
||||
echo "Database initialization complete!"
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 999 # postgres user
|
||||
runAsGroup: 999
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: [ALL]
|
||||
readOnlyRootFilesystem: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
101
loomio/deployment-worker.yaml
Normal file
101
loomio/deployment-worker.yaml
Normal file
@@ -0,0 +1,101 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: loomio-worker
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
component: worker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
component: worker
|
||||
spec:
|
||||
containers:
|
||||
- name: worker
|
||||
image: {{ .workerImage }}
|
||||
env:
|
||||
- name: TASK
|
||||
value: worker
|
||||
- name: RAILS_ENV
|
||||
value: production
|
||||
- name: SITE_NAME
|
||||
value: {{ .appName }}
|
||||
- name: CANONICAL_HOST
|
||||
value: {{ .domain }}
|
||||
- name: PUBLIC_APP_URL
|
||||
value: https://{{ .domain }}
|
||||
- name: SUPPORT_EMAIL
|
||||
value: {{ .supportEmail }}
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: dbUrl
|
||||
- name: REDIS_URL
|
||||
value: {{ .redisUrl }}
|
||||
- name: DEVISE_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: deviseSecret
|
||||
- name: SECRET_COOKIE_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: secretCookieToken
|
||||
- name: ACTIVE_STORAGE_SERVICE
|
||||
value: {{ .activeStorageService }}
|
||||
- name: SMTP_AUTH
|
||||
value: {{ .smtp.auth }}
|
||||
- name: SMTP_DOMAIN
|
||||
value: {{ .smtp.domain }}
|
||||
- name: SMTP_SERVER
|
||||
value: {{ .smtp.host }}
|
||||
- name: SMTP_PORT
|
||||
value: "{{ .smtp.port }}"
|
||||
- name: SMTP_USERNAME
|
||||
value: {{ .smtp.user }}
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: smtpPassword
|
||||
- name: SMTP_USE_SSL
|
||||
value: "{{ .smtp.tls }}"
|
||||
- name: REPLY_HOSTNAME
|
||||
value: {{ .smtp.from }}
|
||||
volumeMounts:
|
||||
- name: uploads
|
||||
mountPath: /loomio/public/system
|
||||
- name: storage
|
||||
mountPath: /loomio/storage
|
||||
- name: tmp
|
||||
mountPath: /loomio/tmp
|
||||
resources:
|
||||
requests:
|
||||
memory: 256Mi
|
||||
cpu: 100m
|
||||
limits:
|
||||
memory: 1Gi
|
||||
cpu: 500m
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: [ALL]
|
||||
readOnlyRootFilesystem: false
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
volumes:
|
||||
- name: uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: loomio-uploads
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: loomio-storage
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
124
loomio/deployment.yaml
Normal file
124
loomio/deployment.yaml
Normal file
@@ -0,0 +1,124 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: loomio
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
component: web
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
component: web
|
||||
spec:
|
||||
containers:
|
||||
- name: loomio
|
||||
image: {{ .image }}
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http
|
||||
env:
|
||||
- name: RAILS_ENV
|
||||
value: production
|
||||
- name: SITE_NAME
|
||||
value: {{ .appName }}
|
||||
- name: CANONICAL_HOST
|
||||
value: {{ .domain }}
|
||||
- name: PUBLIC_APP_URL
|
||||
value: https://{{ .domain }}
|
||||
- name: SUPPORT_EMAIL
|
||||
value: {{ .supportEmail }}
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: dbUrl
|
||||
- name: REDIS_URL
|
||||
value: {{ .redisUrl }}
|
||||
- name: DEVISE_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: deviseSecret
|
||||
- name: SECRET_COOKIE_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: secretCookieToken
|
||||
- name: FORCE_SSL
|
||||
value: "{{ .forceSSL }}"
|
||||
- name: USE_RACK_ATTACK
|
||||
value: "{{ .useRackAttack }}"
|
||||
- name: PUMA_WORKERS
|
||||
value: "{{ .pumaWorkers }}"
|
||||
- name: MIN_THREADS
|
||||
value: "{{ .minThreads }}"
|
||||
- name: MAX_THREADS
|
||||
value: "{{ .maxThreads }}"
|
||||
- name: ACTIVE_STORAGE_SERVICE
|
||||
value: {{ .activeStorageService }}
|
||||
- name: SMTP_AUTH
|
||||
value: {{ .smtp.auth }}
|
||||
- name: SMTP_DOMAIN
|
||||
value: {{ .smtp.domain }}
|
||||
- name: SMTP_SERVER
|
||||
value: {{ .smtp.host }}
|
||||
- name: SMTP_PORT
|
||||
value: "{{ .smtp.port }}"
|
||||
- name: SMTP_USERNAME
|
||||
value: {{ .smtp.user }}
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: loomio-secrets
|
||||
key: smtpPassword
|
||||
- name: SMTP_USE_SSL
|
||||
value: "{{ .smtp.tls }}"
|
||||
- name: REPLY_HOSTNAME
|
||||
value: {{ .smtp.from }}
|
||||
volumeMounts:
|
||||
- name: uploads
|
||||
mountPath: /loomio/public/system
|
||||
- name: storage
|
||||
mountPath: /loomio/storage
|
||||
- name: tmp
|
||||
mountPath: /loomio/tmp
|
||||
resources:
|
||||
requests:
|
||||
memory: 512Mi
|
||||
cpu: 200m
|
||||
limits:
|
||||
memory: 2Gi
|
||||
cpu: 1000m
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 3000
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 3000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: [ALL]
|
||||
readOnlyRootFilesystem: false
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
volumes:
|
||||
- name: uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: loomio-uploads
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: loomio-storage
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
24
loomio/ingress.yaml
Normal file
24
loomio/ingress.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: loomio
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .domain }}
|
||||
secretName: {{ .tlsSecretName }}
|
||||
rules:
|
||||
- host: {{ .domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: loomio
|
||||
port:
|
||||
number: 80
|
||||
20
loomio/kustomization.yaml
Normal file
20
loomio/kustomization.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: loomio
|
||||
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- pvc-uploads.yaml
|
||||
- pvc-storage.yaml
|
||||
- deployment.yaml
|
||||
- deployment-worker.yaml
|
||||
- service.yaml
|
||||
- ingress.yaml
|
||||
- db-init-job.yaml
|
||||
|
||||
labels:
|
||||
- includeSelectors: true
|
||||
pairs:
|
||||
app: loomio
|
||||
managedBy: kustomize
|
||||
partOf: wild-cloud
|
||||
55
loomio/manifest.yaml
Normal file
55
loomio/manifest.yaml
Normal file
@@ -0,0 +1,55 @@
|
||||
name: loomio
|
||||
description: Loomio is a collaborative decision-making tool that makes it easy for groups to make decisions together
|
||||
version: 3.0.11
|
||||
icon: https://www.loomio.com/brand/logo_gold.svg
|
||||
requires:
|
||||
- name: postgres
|
||||
installed_as: postgres
|
||||
- name: redis
|
||||
defaultConfig:
|
||||
namespace: loomio
|
||||
externalDnsDomain: "{{ .cloud.domain }}"
|
||||
image: loomio/loomio:v3.0.11
|
||||
workerImage: loomio/loomio:v3.0.11
|
||||
appName: Loomio
|
||||
domain: "loomio.{{ .cloud.domain }}"
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
port: 3000
|
||||
storage:
|
||||
uploads: 5Gi
|
||||
files: 5Gi
|
||||
plugins: 1Gi
|
||||
redisUrl: "{{ .apps.redis.uri }}"
|
||||
adminEmail: "{{ .operator.email }}"
|
||||
supportEmail: "{{ .operator.email }}"
|
||||
forceSSL: "1"
|
||||
useRackAttack: "1"
|
||||
pumaWorkers: "2"
|
||||
minThreads: "5"
|
||||
maxThreads: "5"
|
||||
activeStorageService: local
|
||||
db:
|
||||
name: loomio
|
||||
user: loomio
|
||||
host: "{{ .apps.postgres.host }}"
|
||||
port: "{{ .apps.postgres.port }}"
|
||||
smtp:
|
||||
auth: plain
|
||||
domain: "{{ .cloud.domain }}"
|
||||
host: "{{ .cloud.smtp.host }}"
|
||||
port: "{{ .cloud.smtp.port }}"
|
||||
user: "{{ .cloud.smtp.user }}"
|
||||
tls: "{{ .cloud.smtp.tls }}"
|
||||
from: "{{ .cloud.smtp.from }}"
|
||||
defaultSecrets:
|
||||
- key: dbPassword
|
||||
default: "{{ random.AlphaNum 32 }}"
|
||||
- key: dbUrl
|
||||
default: "postgresql://{{ .app.db.user }}:{{ .secrets.dbPassword }}@{{ .app.db.host }}:{{ .app.db.port }}/{{ .app.db.name }}?pool=30"
|
||||
- key: deviseSecret
|
||||
default: "{{ random.AlphaNum 32 }}"
|
||||
- key: secretCookieToken
|
||||
default: "{{ random.AlphaNum 32 }}"
|
||||
- key: smtpPassword
|
||||
requiredSecrets:
|
||||
- postgres.password
|
||||
4
loomio/namespace.yaml
Normal file
4
loomio/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .namespace }}
|
||||
11
loomio/pvc-storage.yaml
Normal file
11
loomio/pvc-storage.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: loomio-storage
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .storage.files }}
|
||||
storageClassName: longhorn
|
||||
11
loomio/pvc-uploads.yaml
Normal file
11
loomio/pvc-uploads.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: loomio-uploads
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .storage.uploads }}
|
||||
storageClassName: longhorn
|
||||
13
loomio/service.yaml
Normal file
13
loomio/service.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: loomio
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
component: web
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 3000
|
||||
protocol: TCP
|
||||
@@ -3,7 +3,7 @@ kind: Deployment
|
||||
metadata:
|
||||
name: memcached
|
||||
spec:
|
||||
replicas: {{ .apps.memcached.replicas }}
|
||||
replicas: {{ .replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
component: cache
|
||||
@@ -14,24 +14,24 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: memcached
|
||||
image: {{ .apps.memcached.image }}
|
||||
image: "{{ .image }}"
|
||||
ports:
|
||||
- containerPort: {{ .apps.memcached.port }}
|
||||
- containerPort: {{ .port }}
|
||||
name: memcached
|
||||
args:
|
||||
- -m
|
||||
- {{ .apps.memcached.memoryLimit }}
|
||||
- "{{ .memoryLimit }}"
|
||||
- -c
|
||||
- "{{ .apps.memcached.maxConnections }}"
|
||||
- "{{ .maxConnections }}"
|
||||
- -p
|
||||
- "{{ .apps.memcached.port }}"
|
||||
- "{{ .port }}"
|
||||
resources:
|
||||
requests:
|
||||
memory: {{ .apps.memcached.resources.requests.memory }}
|
||||
cpu: {{ .apps.memcached.resources.requests.cpu }}
|
||||
memory: "{{ .resources.requests.memory }}"
|
||||
cpu: "{{ .resources.requests.cpu }}"
|
||||
limits:
|
||||
memory: {{ .apps.memcached.resources.limits.memory }}
|
||||
cpu: {{ .apps.memcached.resources.limits.cpu }}
|
||||
memory: "{{ .resources.limits.memory }}"
|
||||
cpu: "{{ .resources.limits.cpu }}"
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 11211
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
name: memcached
|
||||
description: Memcached is an in-memory key-value store for small chunks of arbitrary data, commonly used as a cache layer.
|
||||
description: Memcached is an in-memory key-value store for small chunks of arbitrary
|
||||
data, commonly used as a cache layer.
|
||||
version: 1.6.32
|
||||
icon: https://memcached.org/memcached-logo.png
|
||||
icon: https://www.vectorlogo.zone/logos/memcached/memcached-icon.svg
|
||||
requires: []
|
||||
defaultConfig:
|
||||
namespace: memcached
|
||||
image: memcached:1.6.32-alpine
|
||||
port: 11211
|
||||
memoryLimit: 64m
|
||||
@@ -16,4 +18,4 @@ defaultConfig:
|
||||
limits:
|
||||
memory: 128Mi
|
||||
cpu: 200m
|
||||
requiredSecrets: []
|
||||
defaultSecrets: []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: memcached
|
||||
name: "{{ .namespace }}"
|
||||
@@ -4,8 +4,8 @@ metadata:
|
||||
name: memcached
|
||||
spec:
|
||||
ports:
|
||||
- port: {{ .apps.memcached.port }}
|
||||
targetPort: {{ .apps.memcached.port }}
|
||||
- port: {{ .port }}
|
||||
targetPort: {{ .port }}
|
||||
protocol: TCP
|
||||
name: memcached
|
||||
selector:
|
||||
|
||||
@@ -4,6 +4,8 @@ version: 9.1.0
|
||||
icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png
|
||||
requires: []
|
||||
defaultConfig:
|
||||
namespace: mysql
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
image: mysql:9.1.0
|
||||
port: 3306
|
||||
storage: 20Gi
|
||||
@@ -12,6 +14,6 @@ defaultConfig:
|
||||
user: mysql
|
||||
timezone: UTC
|
||||
enableSSL: false
|
||||
requiredSecrets:
|
||||
- apps.mysql.rootPassword
|
||||
- apps.mysql.password
|
||||
defaultSecrets:
|
||||
- key: rootPassword
|
||||
- key: password
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: mysql
|
||||
name: "{{ .namespace }}"
|
||||
@@ -9,7 +9,7 @@ spec:
|
||||
publishNotReadyAddresses: true
|
||||
ports:
|
||||
- name: mysql
|
||||
port: {{ .apps.mysql.port }}
|
||||
port: {{ .port }}
|
||||
protocol: TCP
|
||||
targetPort: mysql
|
||||
selector:
|
||||
|
||||
@@ -7,7 +7,7 @@ spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: mysql
|
||||
port: {{ .apps.mysql.port }}
|
||||
port: {{ .port }}
|
||||
protocol: TCP
|
||||
targetPort: mysql
|
||||
selector:
|
||||
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: mysql
|
||||
image: {{ .apps.mysql.image }}
|
||||
image: {{ .image }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -42,21 +42,21 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysql-secrets
|
||||
key: apps.mysql.rootPassword
|
||||
key: rootPassword
|
||||
- name: MYSQL_USER
|
||||
value: {{ .apps.mysql.user }}
|
||||
value: {{ .user }}
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysql-secrets
|
||||
key: apps.mysql.password
|
||||
key: password
|
||||
- name: MYSQL_DATABASE
|
||||
value: {{ .apps.mysql.dbName }}
|
||||
value: {{ .dbName }}
|
||||
- name: TZ
|
||||
value: {{ .apps.mysql.timezone }}
|
||||
value: {{ .timezone }}
|
||||
ports:
|
||||
- name: mysql
|
||||
containerPort: {{ .apps.mysql.port }}
|
||||
containerPort: {{ .port }}
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
exec:
|
||||
@@ -113,4 +113,4 @@ spec:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.mysql.storage }}
|
||||
storage: {{ .storage }}
|
||||
@@ -45,7 +45,7 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: open-webui-secrets
|
||||
key: apps.openWebui.secretKey
|
||||
key: openWebui.secretKey
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /app/backend/data
|
||||
|
||||
@@ -4,12 +4,12 @@ kind: Ingress
|
||||
metadata:
|
||||
name: open-webui
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
traefik.ingress.kubernetes.io/router.middlewares: crowdsec-crowdsec-bouncer@kubernetescrd,crowdsec-rate-limit@kubernetescrd
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ .apps.open-webui.domain }}
|
||||
- host: {{ .domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -22,4 +22,4 @@ spec:
|
||||
tls:
|
||||
- secretName: wildcard-wild-cloud-tls
|
||||
hosts:
|
||||
- {{ .apps.open-webui.domain }}
|
||||
- {{ .domain }}
|
||||
@@ -1,17 +1,18 @@
|
||||
name: openWebui
|
||||
description: Open WebUI is a comprehensive, open-source web interface for AI models. Features a user-friendly design, supports various LLM runners, and operates entirely offline. Perfect for creating a ChatGPT-like experience with local or hosted models.
|
||||
description: Open WebUI is a comprehensive, open-source web interface for AI models.
|
||||
Features a user-friendly design, supports various LLM runners, and operates entirely
|
||||
offline. Perfect for creating a ChatGPT-like experience with local or hosted models.
|
||||
version: 0.4.5
|
||||
icon: https://docs.openwebui.com/assets/logo-dark.png
|
||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/open-webui.svg
|
||||
requires: []
|
||||
defaultConfig:
|
||||
namespace: open-webui
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
port: 8080
|
||||
storage: 10Gi
|
||||
domain: chat.{{ .cloud.domain }}
|
||||
# vLLM integration - connect to existing vLLM service
|
||||
vllmApiUrl: http://vllm-service.llm.svc.cluster.local:8000/v1
|
||||
# Authentication settings
|
||||
enableAuth: true
|
||||
enableSignup: false
|
||||
requiredSecrets:
|
||||
- apps.openWebui.secretKey
|
||||
defaultSecrets: []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: open-webui
|
||||
name: "{{ .namespace }}"
|
||||
@@ -5,17 +5,17 @@ kind: "ConfigMap"
|
||||
metadata:
|
||||
name: "openproject-core"
|
||||
data:
|
||||
DATABASE_HOST: "{{ .apps.openproject.dbHostname }}"
|
||||
DATABASE_HOST: "{{ .dbHostname }}"
|
||||
DATABASE_PORT: "5432"
|
||||
DATABASE_URL: "postgresql://{{ .apps.openproject.dbUsername }}@{{ .apps.openproject.dbHostname }}:5432/{{ .apps.openproject.dbName }}"
|
||||
OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: "{{ .apps.openproject.adminPasswordReset }}"
|
||||
OPENPROJECT_SEED_ADMIN_USER_NAME: "{{ .apps.openproject.adminUserName }}"
|
||||
OPENPROJECT_SEED_ADMIN_USER_MAIL: "{{ .apps.openproject.adminUserEmail }}"
|
||||
OPENPROJECT_HTTPS: "{{ .apps.openproject.https }}"
|
||||
OPENPROJECT_SEED_LOCALE: "{{ .apps.openproject.seedLocale }}"
|
||||
OPENPROJECT_HOST__NAME: "{{ .apps.openproject.domain }}"
|
||||
OPENPROJECT_HSTS: "{{ .apps.openproject.hsts }}"
|
||||
OPENPROJECT_RAILS__CACHE__STORE: "{{ .apps.openproject.cacheStore }}"
|
||||
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "{{ .apps.openproject.railsRelativeUrlRoot }}"
|
||||
POSTGRES_STATEMENT_TIMEOUT: "{{ .apps.openproject.postgresStatementTimeout }}"
|
||||
DATABASE_URL: "postgresql://{{ .dbUsername }}@{{ .dbHostname }}:5432/{{ .dbName }}"
|
||||
OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: "{{ .adminPasswordReset }}"
|
||||
OPENPROJECT_SEED_ADMIN_USER_NAME: "{{ .adminUserName }}"
|
||||
OPENPROJECT_SEED_ADMIN_USER_MAIL: "{{ .adminUserEmail }}"
|
||||
OPENPROJECT_HTTPS: "{{ .https }}"
|
||||
OPENPROJECT_SEED_LOCALE: "{{ .seedLocale }}"
|
||||
OPENPROJECT_HOST__NAME: "{{ .domain }}"
|
||||
OPENPROJECT_HSTS: "{{ .hsts }}"
|
||||
OPENPROJECT_RAILS__CACHE__STORE: "{{ .cacheStore }}"
|
||||
OPENPROJECT_RAILS__RELATIVE__URL__ROOT: "{{ .railsRelativeUrlRoot }}"
|
||||
POSTGRES_STATEMENT_TIMEOUT: "{{ .postgresStatementTimeout }}"
|
||||
...
|
||||
|
||||
@@ -5,5 +5,5 @@ kind: "ConfigMap"
|
||||
metadata:
|
||||
name: "openproject-memcached"
|
||||
data:
|
||||
OPENPROJECT_CACHE__MEMCACHE__SERVER: "{{ .apps.openproject.memcachedHostname }}:{{ .apps.openproject.memcachedPort }}"
|
||||
OPENPROJECT_CACHE__MEMCACHE__SERVER: "{{ .memcachedHostname }}:{{ .memcachedPort }}"
|
||||
...
|
||||
|
||||
@@ -12,7 +12,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: db-init
|
||||
image: {{ .apps.postgres.image }}
|
||||
image: postgres:17
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
@@ -36,16 +36,16 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-secrets
|
||||
key: apps.postgres.password
|
||||
key: password
|
||||
- name: DB_HOSTNAME
|
||||
value: "{{ .apps.openproject.dbHostname }}"
|
||||
value: "{{ .dbHostname }}"
|
||||
- name: DB_DATABASE_NAME
|
||||
value: "{{ .apps.openproject.dbName }}"
|
||||
value: "{{ .dbName }}"
|
||||
- name: DB_USERNAME
|
||||
value: "{{ .apps.openproject.dbUsername }}"
|
||||
value: "{{ .dbUsername }}"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.dbPassword
|
||||
key: dbPassword
|
||||
restartPolicy: OnFailure
|
||||
@@ -7,10 +7,10 @@ metadata:
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- "{{ .apps.openproject.domain }}"
|
||||
- "{{ .domain }}"
|
||||
secretName: "wildcard-wild-cloud-tls"
|
||||
rules:
|
||||
- host: "{{ .apps.openproject.domain }}"
|
||||
- host: "{{ .domain }}"
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
name: openproject
|
||||
description: OpenProject is an open-source project management software that provides comprehensive features for project planning, tracking, and collaboration.
|
||||
description: OpenProject is an open-source project management software that provides
|
||||
comprehensive features for project planning, tracking, and collaboration.
|
||||
version: 16.1.1
|
||||
icon: https://www.openproject.org/assets/images/openproject-logo.png
|
||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/openproject.svg
|
||||
requires:
|
||||
- name: postgres
|
||||
- name: memcached
|
||||
- name: postgres
|
||||
- name: memcached
|
||||
defaultConfig:
|
||||
namespace: openproject
|
||||
externalDnsDomain: '{{ .cloud.domain }}'
|
||||
serverImage: openproject/openproject:16.1.1-slim
|
||||
timezone: UTC
|
||||
serverPort: 8080
|
||||
@@ -20,14 +23,15 @@ defaultConfig:
|
||||
hsts: true
|
||||
seedLocale: en
|
||||
adminUserName: OpenProject Admin
|
||||
adminUserEmail: "{{ .operator.email }}"
|
||||
adminUserEmail: '{{ .operator.email }}'
|
||||
adminPasswordReset: true
|
||||
postgresStatementTimeout: 120s
|
||||
tmpVolumesStorage: 2Gi
|
||||
tlsSecretName: wildcard-wild-cloud-tls
|
||||
cacheStore: memcache
|
||||
railsRelativeUrlRoot: ""
|
||||
railsRelativeUrlRoot: ''
|
||||
defaultSecrets:
|
||||
- key: dbPassword
|
||||
- key: adminPassword
|
||||
requiredSecrets:
|
||||
- apps.openproject.dbPassword
|
||||
- apps.openproject.adminPassword
|
||||
- apps.postgres.password
|
||||
- postgres.password
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: openproject
|
||||
name: "{{ .namespace }}"
|
||||
@@ -8,5 +8,5 @@ spec:
|
||||
accessModes: [ReadWriteMany]
|
||||
resources:
|
||||
requests:
|
||||
storage: "{{ .apps.openproject.storage }}"
|
||||
storage: "{{ .storage }}"
|
||||
...
|
||||
|
||||
@@ -27,7 +27,7 @@ spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.openproject.tmpVolumesStorage }}
|
||||
storage: {{ .tmpVolumesStorage }}
|
||||
- name: app-tmp
|
||||
# we can't use emptyDir due to the sticky bit / world writable issue
|
||||
# see: https://github.com/kubernetes/kubernetes/issues/110835
|
||||
@@ -39,13 +39,13 @@ spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.openproject.tmpVolumesStorage }}
|
||||
storage: {{ .tmpVolumesStorage }}
|
||||
- name: "data"
|
||||
persistentVolumeClaim:
|
||||
claimName: openproject
|
||||
initContainers:
|
||||
- name: check-db-ready
|
||||
image: "{{ .apps.postgres.image }}"
|
||||
image: "postgres:17"
|
||||
imagePullPolicy: Always
|
||||
command: [
|
||||
'sh',
|
||||
@@ -62,12 +62,12 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.dbPassword
|
||||
key: dbPassword
|
||||
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.adminPassword
|
||||
key: adminPassword
|
||||
resources:
|
||||
limits:
|
||||
memory: 200Mi
|
||||
@@ -91,7 +91,7 @@ spec:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: seeder
|
||||
image: "{{ .apps.openproject.serverImage }}"
|
||||
image: "{{ .serverImage }}"
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- bash
|
||||
@@ -106,12 +106,12 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.dbPassword
|
||||
key: dbPassword
|
||||
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.adminPassword
|
||||
key: adminPassword
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
|
||||
@@ -43,7 +43,7 @@ spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.openproject.tmpVolumesStorage }}
|
||||
storage: {{ .tmpVolumesStorage }}
|
||||
- name: app-tmp
|
||||
# we can't use emptyDir due to the sticky bit / world writable issue
|
||||
# see: https://github.com/kubernetes/kubernetes/issues/110835
|
||||
@@ -55,7 +55,7 @@ spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.openproject.tmpVolumesStorage }}
|
||||
storage: {{ .tmpVolumesStorage }}
|
||||
- name: "data"
|
||||
persistentVolumeClaim:
|
||||
claimName: openproject
|
||||
@@ -72,8 +72,13 @@ spec:
|
||||
runAsUser: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
image: {{ .apps.openproject.serverImage }}
|
||||
image: postgres:17
|
||||
imagePullPolicy: Always
|
||||
command: [
|
||||
'sh',
|
||||
'-c',
|
||||
'until pg_isready -h $DATABASE_HOST -p $DATABASE_PORT; do echo "waiting for database $DATABASE_HOST:$DATABASE_PORT"; sleep 2; done; echo "Database is ready!"'
|
||||
]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: openproject-core
|
||||
@@ -84,14 +89,12 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.dbPassword
|
||||
key: dbPassword
|
||||
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.adminPassword
|
||||
args:
|
||||
- /app/docker/prod/wait-for-db
|
||||
key: adminPassword
|
||||
resources:
|
||||
limits:
|
||||
memory: 1Gi
|
||||
@@ -115,7 +118,7 @@ spec:
|
||||
runAsUser: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
image: {{ .apps.openproject.serverImage }}
|
||||
image: {{ .serverImage }}
|
||||
imagePullPolicy: Always
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
@@ -127,12 +130,12 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.dbPassword
|
||||
key: dbPassword
|
||||
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.adminPassword
|
||||
key: adminPassword
|
||||
args:
|
||||
- /app/docker/prod/web
|
||||
volumeMounts:
|
||||
|
||||
@@ -43,7 +43,7 @@ spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.openproject.tmpVolumesStorage }}
|
||||
storage: {{ .tmpVolumesStorage }}
|
||||
- name: app-tmp
|
||||
# we can't use emptyDir due to the sticky bit / world writable issue
|
||||
# see: https://github.com/kubernetes/kubernetes/issues/110835
|
||||
@@ -55,7 +55,7 @@ spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.openproject.tmpVolumesStorage }}
|
||||
storage: {{ .tmpVolumesStorage }}
|
||||
- name: "data"
|
||||
persistentVolumeClaim:
|
||||
claimName: openproject
|
||||
@@ -72,8 +72,13 @@ spec:
|
||||
runAsUser: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
image: {{ .apps.openproject.serverImage }}
|
||||
image: postgres:17
|
||||
imagePullPolicy: Always
|
||||
command: [
|
||||
'sh',
|
||||
'-c',
|
||||
'until pg_isready -h $DATABASE_HOST -p $DATABASE_PORT; do echo "waiting for database $DATABASE_HOST:$DATABASE_PORT"; sleep 2; done; echo "Database is ready!"'
|
||||
]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: openproject-core
|
||||
@@ -84,15 +89,12 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.dbPassword
|
||||
key: dbPassword
|
||||
- name: OPENPROJECT_SEED_ADMIN_USER_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.adminPassword
|
||||
args:
|
||||
- bash
|
||||
- /app/docker/prod/wait-for-db
|
||||
key: adminPassword
|
||||
resources:
|
||||
limits:
|
||||
memory: 1Gi
|
||||
@@ -116,7 +118,7 @@ spec:
|
||||
runAsUser: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
image: {{ .apps.openproject.serverImage }}
|
||||
image: {{ .serverImage }}
|
||||
imagePullPolicy: Always
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
@@ -132,7 +134,7 @@ spec:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openproject-secrets
|
||||
key: apps.openproject.dbPassword
|
||||
key: dbPassword
|
||||
- name: "OPENPROJECT_GOOD_JOB_QUEUES"
|
||||
value: ""
|
||||
volumeMounts:
|
||||
|
||||
@@ -15,7 +15,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: "{{ .apps.postgres.image }}"
|
||||
image: "{{ .image }}"
|
||||
args:
|
||||
[
|
||||
"-c",
|
||||
@@ -35,16 +35,16 @@ spec:
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
- name: TZ
|
||||
value: "{{ .apps.postgres.timezone }}"
|
||||
value: "{{ .timezone }}"
|
||||
- name: POSTGRES_DB
|
||||
value: "{{ .apps.postgres.database }}"
|
||||
value: "{{ .database }}"
|
||||
- name: POSTGRES_USER
|
||||
value: "{{ .apps.postgres.user }}"
|
||||
value: "{{ .user }}"
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-secrets
|
||||
key: apps.postgres.password
|
||||
key: password
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
|
||||
@@ -4,10 +4,13 @@ description: PostgreSQL is a powerful, open source object-relational database sy
|
||||
version: 1.0.0
|
||||
icon: https://www.postgresql.org/media/img/about/press/elephant.png
|
||||
defaultConfig:
|
||||
namespace: postgres
|
||||
host: postgres.postgres.svc.cluster.local
|
||||
port: 5432
|
||||
database: postgres
|
||||
user: postgres
|
||||
storage: 10Gi
|
||||
image: pgvector/pgvector:pg15
|
||||
timezone: UTC
|
||||
requiredSecrets:
|
||||
- apps.postgres.password
|
||||
defaultSecrets:
|
||||
- key: password
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: postgres
|
||||
name: {{ .namespace }}
|
||||
|
||||
@@ -9,4 +9,4 @@ spec:
|
||||
storageClassName: longhorn
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .apps.postgres.storage | default "10Gi" }}
|
||||
storage: {{ .storage }}
|
||||
|
||||
@@ -5,6 +5,6 @@ metadata:
|
||||
name: postgres
|
||||
spec:
|
||||
ports:
|
||||
- port: 5432
|
||||
- port: {{ .port }}
|
||||
selector:
|
||||
app: postgres
|
||||
|
||||
@@ -14,18 +14,18 @@ spec:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- image: "{{ .apps.redis.image }}"
|
||||
- image: "{{ .image }}"
|
||||
name: redis
|
||||
ports:
|
||||
- containerPort: {{ .apps.redis.port }}
|
||||
- containerPort: {{ .port }}
|
||||
env:
|
||||
- name: TZ
|
||||
value: "{{ .apps.redis.timezone }}"
|
||||
value: "{{ .timezone }}"
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: redis-secrets
|
||||
key: apps.redis.password
|
||||
key: password
|
||||
command:
|
||||
- redis-server
|
||||
- --requirepass
|
||||
|
||||
@@ -2,10 +2,13 @@ name: redis
|
||||
install: true
|
||||
description: Redis is an open source, in-memory data structure store, used as a database, cache and message broker.
|
||||
version: 1.0.0
|
||||
icon: <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:
|
||||
namespace: redis
|
||||
image: redis:alpine
|
||||
timezone: UTC
|
||||
host: redis.redis.svc.cluster.local
|
||||
port: 6379
|
||||
requiredSecrets:
|
||||
- apps.redis.password
|
||||
uri: redis://{{ .app.host }}:{{ .app.port }}/0
|
||||
defaultSecrets:
|
||||
- key: password
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: redis
|
||||
name: {{ .namespace }}
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
app: redis
|
||||
spec:
|
||||
ports:
|
||||
- port: {{ .apps.redis.port }}
|
||||
targetPort: {{ .apps.redis.port }}
|
||||
- port: {{ .port }}
|
||||
targetPort: {{ .port }}
|
||||
selector:
|
||||
app: redis
|
||||
|
||||
@@ -19,10 +19,10 @@ spec:
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
nodeSelector:
|
||||
nvidia.com/gpu.product: "{{ .apps.vllm.gpuProduct }}"
|
||||
nvidia.com/gpu.product: "{{ .gpuProduct }}"
|
||||
containers:
|
||||
- name: vllm
|
||||
image: "{{ .apps.vllm.image }}"
|
||||
image: "{{ .image }}"
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -31,10 +31,10 @@ spec:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: false
|
||||
args:
|
||||
- --model={{ .apps.vllm.model }}
|
||||
- --max-model-len={{ .apps.vllm.maxModelLen }}
|
||||
- --tensor-parallel-size={{ .apps.vllm.tensorParallelSize }}
|
||||
- --gpu-memory-utilization={{ .apps.vllm.gpuMemoryUtilization }}
|
||||
- --model={{ .model }}
|
||||
- --max-model-len={{ .maxModelLen }}
|
||||
- --tensor-parallel-size={{ .tensorParallelSize }}
|
||||
- --gpu-memory-utilization={{ .gpuMemoryUtilization }}
|
||||
{{- if .apps.vllm.enforceEager }}
|
||||
- --enforce-eager=True
|
||||
{{- end }}
|
||||
@@ -48,13 +48,13 @@ spec:
|
||||
containerPort: 8000
|
||||
resources:
|
||||
requests:
|
||||
cpu: "{{ .apps.vllm.cpuRequest }}"
|
||||
memory: "{{ .apps.vllm.memoryRequest }}"
|
||||
nvidia.com/gpu: {{ .apps.vllm.gpuCount }}
|
||||
cpu: "{{ .cpuRequest }}"
|
||||
memory: "{{ .memoryRequest }}"
|
||||
nvidia.com/gpu: {{ .gpuCount }}
|
||||
limits:
|
||||
cpu: "{{ .apps.vllm.cpuLimit }}"
|
||||
memory: "{{ .apps.vllm.memoryLimit }}"
|
||||
nvidia.com/gpu: {{ .apps.vllm.gpuCount }}
|
||||
cpu: "{{ .cpuLimit }}"
|
||||
memory: "{{ .memoryLimit }}"
|
||||
nvidia.com/gpu: {{ .gpuCount }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/models
|
||||
|
||||
@@ -3,13 +3,13 @@ kind: Ingress
|
||||
metadata:
|
||||
name: vllm
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/target: {{ .cloud.domain }}
|
||||
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
|
||||
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
traefik.ingress.kubernetes.io/router.tls.certresolver: letsencrypt
|
||||
spec:
|
||||
rules:
|
||||
- host: {{ .apps.vllm.domain }}
|
||||
- host: {{ .domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -21,5 +21,5 @@ spec:
|
||||
number: 8000
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .apps.vllm.domain }}
|
||||
- {{ .domain }}
|
||||
secretName: vllm-tls
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user