Claude-skill-registry app-template
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/app-template" ~/.claude/skills/majiayu000-claude-skill-registry-app-template && rm -rf "$T"
manifest:
skills/data/app-template/SKILL.mdsource content
app-template Helm Chart
The bjw-s/app-template chart deploys containerized applications without requiring a dedicated Helm chart. It provides a declarative interface for common Kubernetes resources.
Chart source:
oci://ghcr.io/bjw-s-labs/helm/app-template
Schema: https://raw.githubusercontent.com/bjw-s-labs/helm-charts/app-template-4.6.0/charts/other/app-template/values.schema.json
Quick Start
Minimal values.yaml for a single-container deployment:
# yaml-language-server: $schema=https://raw.githubusercontent.com/bjw-s-labs/helm-charts/app-template-4.6.0/charts/other/app-template/values.schema.json controllers: main: containers: main: image: repository: nginx tag: latest service: main: controller: main ports: http: port: 80
Core Structure
Controllers
Controllers define workload types. Each controller creates one Pod spec.
controllers: main: # Controller identifier (arbitrary name) type: deployment # deployment|statefulset|daemonset|cronjob|job replicas: 1 strategy: Recreate # Recreate|RollingUpdate (deployment) # Pod-level settings pod: securityContext: fsGroup: 568 fsGroupChangePolicy: OnRootMismatch containers: main: # Container identifier image: repository: ghcr.io/org/app tag: v1.0.0 env: TZ: UTC CONFIG_PATH: /config
Multiple Controllers
Create separate deployments in one release:
controllers: web: containers: main: image: repository: nginx tag: latest worker: type: deployment replicas: 3 containers: main: image: repository: myapp/worker tag: v1.0.0
Sidecar Containers
Add sidecars with
dependsOn for ordering:
controllers: main: containers: main: image: repository: myapp tag: v1.0.0 sidecar: dependsOn: main # Start after main container image: repository: sidecar-image tag: latest args: ["--config", "/config/sidecar.yaml"]
Services
Services expose controller pods. Link via
controller field.
service: main: controller: main # Links to controllers.main type: ClusterIP # ClusterIP|LoadBalancer|NodePort ports: http: port: 8080 metrics: port: 9090 websocket: controller: main ports: ws: port: 3012
Ingress
ingress: main: className: nginx hosts: - host: app.example.com paths: - path: / pathType: Prefix service: identifier: main # References service.main port: http # References port name tls: - hosts: - app.example.com secretName: app-tls
Multiple paths to different services:
ingress: main: hosts: - host: app.example.com paths: - path: / service: identifier: main port: http - path: /ws service: identifier: websocket port: ws
Persistence
PersistentVolumeClaim
persistence: config: type: persistentVolumeClaim accessMode: ReadWriteOnce size: 1Gi globalMounts: - path: /config
Existing PVC
persistence: config: existingClaim: my-existing-pvc globalMounts: - path: /config
NFS Mount
persistence: backup: type: nfs server: nas.local path: /volume/backups globalMounts: - path: /backup
EmptyDir (Shared Between Containers)
persistence: shared-data: type: emptyDir globalMounts: - path: /shared
Advanced Mounts (Per-Controller/Container)
persistence: config: existingClaim: app-config advancedMounts: main: # Controller identifier main: # Container identifier - path: /config sidecar: - path: /config readOnly: true
Environment Variables
Direct Values
controllers: main: containers: main: env: TZ: UTC LOG_LEVEL: info TEMPLATE_VAR: "{{ .Release.Name }}"
From Secrets/ConfigMaps
controllers: main: containers: main: env: DATABASE_URL: valueFrom: secretKeyRef: name: db-secret key: url envFrom: - secretRef: name: app-secrets - configMapRef: name: app-config
Security Context
Pod-Level
defaultPodOptions: securityContext: runAsUser: 568 runAsGroup: 568 fsGroup: 568 fsGroupChangePolicy: OnRootMismatch controllers: main: containers: main: image: repository: myapp tag: v1.0.0
Container-Level (Privileged Sidecar)
controllers: main: containers: main: securityContext: runAsUser: 568 runAsGroup: 568 vpn: image: repository: vpn-client tag: latest securityContext: capabilities: add: - NET_ADMIN
Probes
Default probes use TCP on the primary service port. Customize:
controllers: main: containers: main: probes: liveness: enabled: true custom: true spec: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 30 readiness: enabled: true type: HTTP spec: path: /ready port: 8080 startup: enabled: false
StatefulSet with VolumeClaimTemplates
controllers: main: type: statefulset statefulset: volumeClaimTemplates: - name: data accessMode: ReadWriteOnce size: 10Gi globalMounts: - path: /data
CronJob
controllers: backup: type: cronjob cronjob: schedule: "0 2 * * *" concurrencyPolicy: Forbid successfulJobsHistory: 3 failedJobsHistory: 1 containers: main: image: repository: backup-tool tag: v1.0.0 args: ["--backup", "/data"]
ServiceMonitor (Prometheus)
serviceMonitor: main: enabled: true serviceName: main endpoints: - port: metrics scheme: http path: /metrics interval: 30s
Flux HelmRelease Integration
For this homelab, app-template deploys via Flux ResourceSet. Add to
kubernetes/platform/helm-charts.yaml:
# In resourcesTemplate, the pattern generates HelmRelease automatically # For app-template specifically, add to inputs: - name: "my-app" namespace: "default" chart: name: "app-template" version: "4.6.0" url: "oci://ghcr.io/bjw-s-labs/helm" # Note: OCI registry dependsOn: [cilium]
Values go in
kubernetes/platform/charts/my-app.yaml.
Common Patterns
See references/patterns.md for:
- VPN sidecar with gluetun
- Code-server sidecar for config editing
- Multi-service applications (websocket + http)
- Init containers for setup tasks
See references/values-reference.md for complete values.yaml documentation.