158 lines
6.0 KiB
Markdown
158 lines
6.0 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## 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 by `wild-app-add` when operators add apps to their Wild Cloud home directory.
|
|
|
|
### 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
|
|
|
|
## Common Wild Cloud Commands
|
|
|
|
These commands are run by operators from their Wild Cloud home directory (not this repository):
|
|
|
|
- `wild-apps-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
|
|
|
|
## 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
|