From dc8eaa3ffeddd2fd2a797aa87aa530868c908750 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 11 Nov 2025 19:52:58 +0000 Subject: [PATCH] Add production-grade Helm chart improvements High-impact improvements based on Codex recommendations: 1. values.schema.json - JSON schema validation catches config errors at install time 2. helm-docs automation - Auto-generates documentation from values.yaml comments 3. kind smoke tests - Deploys and upgrades chart in real cluster to catch runtime issues 4. ServiceMonitor template - Built-in Prometheus integration for observability 5. Artifact Hub metadata - Changelog, links, and maintainer info for better discoverability These improvements provide: - Configuration validation before deployment - Always up-to-date documentation - Runtime validation in CI - First-class monitoring support - Better user experience on Artifact Hub Related to #686 --- .github/workflows/helm-pages.yml | 56 ++++++ deploy/helm/pulse/Chart.yaml | 19 ++ .../helm/pulse/templates/servicemonitor.yaml | 33 +++ deploy/helm/pulse/values.schema.json | 189 ++++++++++++++++++ deploy/helm/pulse/values.yaml | 11 + 5 files changed, 308 insertions(+) create mode 100644 deploy/helm/pulse/templates/servicemonitor.yaml create mode 100644 deploy/helm/pulse/values.schema.json diff --git a/.github/workflows/helm-pages.yml b/.github/workflows/helm-pages.yml index d09422134..699f9e205 100644 --- a/.github/workflows/helm-pages.yml +++ b/.github/workflows/helm-pages.yml @@ -31,6 +31,29 @@ jobs: with: version: v3.15.2 + - name: Install helm-docs + run: | + cd /tmp + wget https://github.com/norwoodj/helm-docs/releases/download/v1.14.2/helm-docs_1.14.2_Linux_x86_64.tar.gz + tar -xzf helm-docs_1.14.2_Linux_x86_64.tar.gz + sudo mv helm-docs /usr/local/bin/ + helm-docs --version + + - name: Generate chart documentation + run: | + cd deploy/helm/pulse + helm-docs + + # Commit if README changed + if ! git diff --quiet README.md; then + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + git add README.md + git commit -m "Auto-update Helm chart documentation" + git push + fi + cd ../../.. + - name: Determine chart version id: version run: | @@ -73,6 +96,39 @@ jobs: echo "✓ Chart validation passed" + - name: Smoke test with kind + run: | + # Install kind + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + # Create cluster + kind create cluster --name pulse-test --wait 5m + + # Install chart + helm install pulse deploy/helm/pulse \ + --set persistence.enabled=false \ + --set server.secretEnv.create=true \ + --set server.secretEnv.data.API_TOKENS=test-token \ + --wait --timeout 3m + + # Verify deployment + kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=pulse --timeout=120s + kubectl get pods -l app.kubernetes.io/name=pulse + + # Test upgrade + helm upgrade pulse deploy/helm/pulse \ + --set persistence.enabled=false \ + --set server.secretEnv.create=true \ + --set server.secretEnv.data.API_TOKENS=test-token \ + --wait --timeout 3m + + # Cleanup + kind delete cluster --name pulse-test + + echo "✓ Smoke test passed" + - name: Run chart-releaser uses: helm/chart-releaser-action@v1.6.0 with: diff --git a/deploy/helm/pulse/Chart.yaml b/deploy/helm/pulse/Chart.yaml index 8c6567806..356c727b0 100644 --- a/deploy/helm/pulse/Chart.yaml +++ b/deploy/helm/pulse/Chart.yaml @@ -19,3 +19,22 @@ annotations: org.opencontainers.image.source: https://github.com/rcourtman/Pulse org.opencontainers.image.description: Helm chart for deploying Pulse monitoring system org.opencontainers.image.licenses: MIT + artifacthub.io/changes: | + - kind: added + description: GitHub Pages Helm repository distribution (no authentication required) + - kind: added + description: values.schema.json for configuration validation + - kind: added + description: ServiceMonitor template for Prometheus integration + - kind: added + description: Automated chart documentation generation with helm-docs + - kind: added + description: Smoke tests with kind cluster deployment + artifacthub.io/links: | + - name: Documentation + url: https://github.com/rcourtman/Pulse/blob/main/docs/KUBERNETES.md + - name: Support + url: https://github.com/rcourtman/Pulse/discussions + artifacthub.io/maintainers: | + - name: rcourtman + email: pulse@rcourtman.dev diff --git a/deploy/helm/pulse/templates/servicemonitor.yaml b/deploy/helm/pulse/templates/servicemonitor.yaml new file mode 100644 index 000000000..1e6f2b121 --- /dev/null +++ b/deploy/helm/pulse/templates/servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.monitoring.serviceMonitor.enabled -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "pulse.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "pulse.labels" . | nindent 4 }} + {{- with .Values.monitoring.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "pulse.selectorLabels" . | nindent 6 }} + endpoints: + - port: http + {{- with .Values.monitoring.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.monitoring.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + path: {{ .Values.monitoring.serviceMonitor.path | default "/metrics" }} + {{- with .Values.monitoring.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.monitoring.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/deploy/helm/pulse/values.schema.json b/deploy/helm/pulse/values.schema.json new file mode 100644 index 000000000..7953a8bab --- /dev/null +++ b/deploy/helm/pulse/values.schema.json @@ -0,0 +1,189 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": "object", + "required": ["server"], + "properties": { + "replicaCount": { + "type": "integer", + "minimum": 1, + "description": "Number of Pulse server replicas" + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string", + "description": "Container image repository" + }, + "pullPolicy": { + "type": "string", + "enum": ["Always", "IfNotPresent", "Never"], + "description": "Image pull policy" + }, + "tag": { + "type": "string", + "description": "Container image tag (overrides chart appVersion)" + } + } + }, + "imagePullSecrets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "description": "Image pull secrets for private registries" + }, + "service": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["ClusterIP", "NodePort", "LoadBalancer"], + "description": "Kubernetes service type" + }, + "port": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "Service port" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable ingress resource" + }, + "className": { + "type": "string", + "description": "Ingress class name" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string", + "format": "hostname" + }, + "paths": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "pathType": { + "type": "string", + "enum": ["Prefix", "Exact", "ImplementationSpecific"] + } + } + } + } + } + } + } + } + }, + "persistence": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable persistent storage" + }, + "existingClaim": { + "type": "string", + "description": "Use existing PVC" + }, + "storageClass": { + "type": "string", + "description": "Storage class name" + }, + "accessMode": { + "type": "string", + "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany", "ReadWriteOncePod"], + "description": "PVC access mode" + }, + "size": { + "type": "string", + "pattern": "^[0-9]+[EPTGMK]i?$", + "description": "Storage size (e.g., 8Gi)" + } + } + }, + "server": { + "type": "object", + "properties": { + "resources": { + "type": "object", + "description": "Resource requests and limits" + }, + "env": { + "type": "array", + "description": "Environment variables" + }, + "secretEnv": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "data": { + "type": "object" + } + } + } + } + }, + "agent": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable Docker monitoring agent" + }, + "kind": { + "type": "string", + "enum": ["DaemonSet", "Deployment"], + "description": "Agent deployment type" + } + } + }, + "monitoring": { + "type": "object", + "properties": { + "serviceMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Create ServiceMonitor for Prometheus" + }, + "interval": { + "type": "string", + "pattern": "^[0-9]+[smh]$", + "description": "Scrape interval (e.g., 30s)" + }, + "path": { + "type": "string", + "description": "Metrics endpoint path" + } + } + } + } + } + } +} diff --git a/deploy/helm/pulse/values.yaml b/deploy/helm/pulse/values.yaml index 9f62371d5..435a1cc2a 100644 --- a/deploy/helm/pulse/values.yaml +++ b/deploy/helm/pulse/values.yaml @@ -138,3 +138,14 @@ agent: hostPathType: Socket extraVolumes: [] extraVolumeMounts: [] + +# Monitoring configuration +monitoring: + serviceMonitor: + enabled: false + interval: 30s + scrapeTimeout: 10s + path: /metrics + labels: {} + relabelings: [] + metricRelabelings: []