6.6 KiB
AGENTS.md
This is a Helm chart for deploying a self-hosted home environment (Homey) on Kubernetes.
Project Overview
- Type: Helm Chart (Kubernetes package manager)
- Language: YAML + Go template syntax (Helm templating)
- Key Files:
Chart.yaml- Chart metadatavalues.yaml- Default configuration valuestemplates/- Kubernetes manifest templates (auth.yaml, media.yaml, phpldapadmin.yaml, _definitions.yaml)files/- Configuration file templates (processed by Helm withtplfunction)
Build/Lint/Test Commands
Helm Validation
# Lint the Helm chart for errors
helm lint .
# Template rendering (dry-run install)
helm template test-release . --debug
# Install/upgrade in cluster
helm upgrade --install homey . -n homey
# Verify chart against Kubernetes API
helm kubeval .
# Check schema validation of values.yaml
helm schema generate
Manual Template Testing
# Render templates locally with custom values
helm template homey . -f values.yaml --set homey.url=example.com
# Template with debug output
helm template homey . --debug 2>&1 | less
Kubectl Validation
# Dry-run apply to validate manifests
kubectl apply -f templates/auth.yaml --dry-run=server
# Get rendered template directly
helm template homey . | kubectl apply --dry-run=server -f -
Code Style Guidelines
YAML Structure
-
Document Separators: Use
---at the start of each YAML document--- apiVersion: v1 kind: ConfigMap -
Indentation: Use 2 spaces (not tabs)
spec: containers: - name: app image: nginx -
Trailing Commas: Optional but preferred for multi-line lists
accessModes: - ReadWriteMany - ReadOnlyMany -
Quotes: Use quotes for strings that might be interpreted as other types
- Always quote:
.Values.homey.url | quote - Optional for simple strings like names
- Always quote:
Kubernetes Resources
-
Labels: Use Kubernetes recommended labels
labels: app.kubernetes.io/name: openldap app.kubernetes.io/component: auth -
Naming: Use kebab-case for resource names
name: openldap-admin name: nextcloud-postgres -
Storage: Always specify
storageClassName: longhornspec: storageClassName: longhorn
Helm Template Syntax
-
Variable Assignment: Use
$_ := setfor complex assignments{{- $_ := set $ "varname" (include "homey.lookuporgensecret" (merge (dict "secretname" "secret-name") $)) }} -
Include with Merge: Always pass
$as the last argument{{ include "homey.randomsecret" (merge (dict "secretname" "secret-name" "secretval" $secretval) $) }} -
Quote Values from .Values: Use
quotefiltervalue: {{ .Values.homey.url | quote }} -
Template Definitions: Define reusable templates in
_definitions.yamlhomey.lookuporgensecret- Look up existing secrets or generate randomhomey.randomsecret- Generate a random secrethomey.randHex- Generate random hex string
-
Template Spacing: Use whitespace control to avoid extra newlines
{{- "leading minus" -}} # No newline before {{ "trailing minus" -}} # No newline after
Secret Management
-
Annotations: Always annotate managed secrets to prevent deletion
annotations: "helm.sh/resource-policy": "keep" -
Secret Generation Pattern:
# Check for existing secret, create if not exists {{- $secretObj := (lookup "v1" "Secret" .Release.Namespace "secret-name") | default dict -}} {{- $secretData := (get $secretObj "data") | default dict -}} {{- $pass := (get $secretData "password") | default (randAlphaNum 32 | b64enc) -}} -
Never hardcode secrets - Use the secret lookup pattern above
Config Files (files/ directory)
-
Go Templates in Configs: Use
tplfunction to process config filesdata: config.yml: |- {{ tpl (.Files.Get "files/authelia-config.yaml" | indent 4) . }} -
Accessing Variables: Config files can access
.Values.*and custom variables set in templates
Ingress Configuration
-
TLS: Always specify TLS with proper hosts and secret
spec: ingressClassName: {{ .Values.homey.ingress_class }} tls: - hosts: - auth.{{ .Values.homey.url }} secretName: {{ .Values.homey.certname }} -
Authelia Integration: Use auth snippets for protected ingresses
annotations: nginx.ingress.kubernetes.io/auth-url: http://authelia.{{ .Release.Namespace }}.svc.cluster.local:9091/api/verify nginx.ingress.kubernetes.io/auth-signin: https://auth.{{ .Values.homey.url }}?rm=$request_method
Resource Organization
-
File Structure:
templates/_definitions.yaml- Helper templates (secrets, utilities)templates/auth.yaml- Authentication services (OpenLDAP, Authelia, Gitea, Nextcloud, Radicale)templates/media.yaml- Media services (Jellyfin, Transmission)templates/phpldapadmin.yaml- LDAP admin interface
-
Manifest Order (within a file):
- PersistentVolumeClaim
- Secrets
- ConfigMaps
- Deployments
- Services
- Ingress
-
Unused Resources: Keep deprecated manifests in
unused/directory
Environment Variables
-
Naming: Use uppercase with underscores
- name: LDAP_ORGANISATION value: {{ .Values.homey.organization }} -
Value Sources: Prefer
valueFrom.secretKeyRefover inline values- name: PASSWORD valueFrom: secretKeyRef: name: secret-name key: password
Volume Mounts
-
subPath: Use
subPathfor shared PVCsvolumeMounts: - mountPath: /data subPath: service-name/data -
Read-only ConfigMaps: Mark config mounts as read-only
readOnly: true
Common Operations
Adding a New Service
- Add values to
values.yaml - Create/extend template in
templates/ - Add PVC if persistent storage needed
- Add Ingress with appropriate annotations
- Test with
helm template .
Updating Secrets
Secrets are generated on first install. To regenerate:
kubectl delete secret <secret-name> -n homey
helm upgrade --install homey . -n homey
Debugging Templates
# Show all template variables available
helm template . --show-only templates/_helpers.tpl
# Render single template
helm template . --show-only templates/auth.yaml