claude
This commit is contained in:
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
|
- When adding a new app to the directory, check to make sure you are adding the latest app version.
|
||||||
|
- Use traefik for ingress.
|
||||||
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.
|
- Use postgres for database if supported.
|
||||||
|
- Keep config key naming (including nesting) consistent with other apps.
|
||||||
## Repository Architecture
|
- 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
|
||||||
### App Structure
|
- when developing a new app:
|
||||||
|
- test with:
|
||||||
Each app follows a strict structure:
|
- reset to a fresh state between tests:
|
||||||
- **`manifest.yaml`** - App metadata, dependencies, default configuration, and secret requirements
|
- secrets.yaml is not checked in and any values unrelated to your current task should be preserved
|
||||||
- **`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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user