Writing Skills
writing-skills
效率与协作技能,来自 obra/superpowers,查看原文获取完整用途和操作说明。
helm-chart-development【部署与运维】Builds, templates, and manages Helm charts with Chart.yaml, values.yaml, and Go template files for reliable Kubernetes application deployment and versioned releases.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Implements the full lifecycle of Helm chart creation, templating, packaging, and distribution — from initial helm create scaffolding through production-ready chart releases on a registry or ChartMuseum.
Chart.yaml declares apiVersion: v2, a stable version, and appVersionvalues.yaml provides sensible defaults and documents every field with comments{{- / -}} whitespace control to avoid blank lines in rendered YAML{{ include }} helpers keep repeated logic DRY and namespaced per releasehelm lint <chart-dir> passes before any commithelm template . renders cleanly with default and overridden valueshelm package <chart-dir> produces a tarball with correct semantic versionhelm push or helm push chart.tgz chartmuseum://...Use this skill when:
helm lintAvoid this skill for:
helm install with proper requirements.yaml/dependencies in Chart.yamlCreate the chart scaffold — Run helm create <chart-name> in an empty directory. This generates Chart.yaml, values.yaml, and templates/ with a starter deployment.yaml, service.yaml, and helpers.tpl.
Audit the scaffold — Read every generated file. The scaffold is intentionally generic: update Chart.yaml metadata, remove files you do not need (e.g., ingress.yaml if the app has no ingress), and rename files to match your application's resources.
Define the directory layout — A production chart follows this structure:
my-chart/
├── Chart.yaml # Chart metadata
├── values.yaml # Default values
├── values.schema.json # Optional JSON Schema validation
├── templates/
│ ├── _helpers.tpl # Reusable named templates
│ ├── deployment.yaml
│ ├── service.yaml
│ └── NOTES.txt
└── .helmignore # Files to exclude from packaging
Checkpoint: Run helm lint my-chart/ and verify it reports no errors or only warnings you have intentionally accepted.
Write Chart.yaml — Use apiVersion: v2 for modern Helm charts. Set version to a semantic version (e.g., 1.2.0) and appVersion to the application's version string:
apiVersion: v2
name: my-chart
description: A Helm chart for deploying my application
type: application
version: 1.2.0
appVersion: "3.1.0"
keywords:
- web
- app
maintainers:
- name: Platform Team
email: platform@example.com
Checkpoint: Confirm version is valid semver and appVersion is quoted if it contains non-numeric characters.
Write values.yaml — Provide defaults for every configurable aspect of your chart. Every top-level key in values.yaml is overridable at install time via --set or --values. Comment each section to document its purpose:
# Replicas for the deployment
replicaCount: 2
# Container image configuration
image:
repository: myregistry/my-app
pullPolicy: IfNotPresent
# Override the image tag explicitly
tag: ""
# Service exposure
service:
type: ClusterIP
port: 80
targetPort: 8080
# Resource limits and requests
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
# Autoscaling configuration (disabled by default)
autoscaling:
enabled: false
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80
Checkpoint: Run helm template my-chart/ --set replicaCount=5 and verify the rendered output reflects the override.
Implement _helpers.tpl — Define named templates for labels, selectors, and any repeated patterns. Use the chart's fullname to namespace helper output:
{{/*
Generate basic labels including app.kubernetes.io/version.
*/}}
{{- define "my-chart.labels" -}}
include "my-chart.selectorLabels" .
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels used by Deployments and Services.
*/}}
{{- define "my-chart.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
Write resource templates — In templates/deployment.yaml, reference values and helpers:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "my-chart.selectorLabels" . | nindent 8 }}
template:
metadata:
labels:
{{- include "my-chart.selectorLabels" . | nindent 10 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: http
readinessProbe:
httpGet:
path: /ready
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
Handle conditional blocks — Use if/else for optional features (ingress, HPA, secrets) and range for lists:
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "my-chart.fullname" . }}
spec:
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "my-chart.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
Checkpoint: Run helm template my-chart/ -f custom-values.yaml with at least two different value sets and verify both render correctly.
Validate the chart — Run the full validation suite:
# Lint for structural issues
helm lint my-chart/
# Lint with strict mode (catches warnings as errors)
helm lint --strict my-chart/
# Render with default values
helm template my-chart/
# Render with custom overrides
helm template my-chart/ --set replicaCount=3 --set image.tag=v2.0.0
# Install in dry-run mode (no actual cluster interaction)
helm install --dry-run --debug my-release my-chart/
Package the chart — Create a versioned tarball for distribution:
helm package my-chart/
# Produces: my-chart-1.2.0.tgz
Push to a registry or ChartMuseum — Distribute the packaged chart:
# Push to a Helm OCI registry
helm push my-chart-1.2.0.tgz oci://registry.example.com/charts
# Push to a ChartMuseum instance
helm push my-chart-1.2.0.tgz chartmuseum://http://chartmuseum.internal
# Or upload manually
curl --data-binary @"my-chart-1.2.0.tgz" http://chartmuseum.internal/api/charts
Checkpoint: Install the packaged chart in a test cluster using helm install test-release ./my-chart-1.2.0.tgz and verify all resources are healthy.
This is the baseline deployment pattern for stateless workloads. It includes readiness/liveness probes, resource requests/limits, and proper label inheritance from helpers.
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
{{- with .Values.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
strategy:
{{- toYaml .Values.strategy | nindent 4 }}
selector:
matchLabels:
{{- include "my-chart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-chart.selectorLabels" . | nindent 8 }}
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "my-chart.serviceAccountName" . }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 10
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
values.yaml (deployment-related section)
replicaCount: 2
image:
repository: myregistry/my-app
pullPolicy: IfNotPresent
tag: ""
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
env:
APP_ENV: production
LOG_LEVEL: info
nodeSelector: {}
tolerations: []
affinity: {}
autoscaling:
enabled: false
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80
This pattern covers two service types in one chart: a standard ClusterIP for internal communication and an optional headless service for direct pod addressing (useful for stateful apps or service meshes).
service.yaml
{{- if .Values.service.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "my-chart.selectorLabels" . | nindent 4 }}
{{- end }}
{{- if .Values.headlessService.enabled }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "my-chart.fullname" . }}-headless
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
type: ClusterIP
clusterIP: None
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "my-chart.selectorLabels" . | nindent 4 }}
{{- end }}
values.yaml (service-related section)
service:
enabled: true
type: ClusterIP
port: 80
targetPort: 8080
headlessService:
enabled: false
Use this pattern when the application scales based on CPU, memory, or custom metrics (e.g., queue depth).
hpa.yaml
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "my-chart.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.customMetrics }}
{{- range .Values.autoscaling.customMetrics }}
- type: Object
object:
metric:
name: {{ .metricName }}
identifiedBy:
{{- range .identifiers }}
- key: {{ .key }}
value: {{ .value }}
{{- end }}
target:
type: Value
value: {{ .targetValue }}
{{- end }}
{{- end }}
{{- end }}
This pattern externalizes configuration into ConfigMaps and secrets, keeping sensitive data out of deployment manifests.
configmap.yaml
{{- if .Values.configMap.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "my-chart.fullname" . }}-config
labels:
{{- include "my-chart.labels" . | nindent 4 }}
data:
{{- range $key, $value := .Values.configMap.data }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
secrets.yaml
{{- if .Values.secrets.create }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "my-chart.fullname" . }}-secrets
labels:
{{- include "my-chart.labels" . | nindent 4 }}
type: Opaque
data:
{{- range $key, $value := .Values.secrets.data }}
{{ $key }}: {{ $value | b64enc }}
{{- end }}
{{- end }}
apiVersion: v2 in Chart.yaml for modern Helm charts (supports dependencies without requirements.yaml)._helpers.tpl with the chart name to avoid collisions across releases (e.g., my-chart.labels).{{- (dash-open) to strip leading whitespace and -}} (close-dash) to strip trailing whitespace in template conditionals.nindent when embedding block output (like include results) inside YAML to maintain correct indentation levels.resources with both requests and limits — omitting requests prevents the scheduler from making correct decisions..Values.image.tag | default .Chart.AppVersion so that untagged installs fall back to the app version rather than latest.helm lint --strict and helm template before committing template changes.values.yaml with a comment explaining its purpose and acceptable range.--- YAML document separators only when multiple top-level resources are in one template file.helm test <release-name> if you define test hooks in templates/tests/.{{ .Release.Namespace }} so the chart can be installed into any namespace..Values keys that shadow Helm built-in objects (e.g., avoid a key named Capabilities or Release).values.yaml — use a Secret resource or an external secret manager (Sealed Secrets, External Secrets Operator).helm lint before packaging — a chart that fails lint will produce silent rendering errors in production..Values without the .Values. prefix — bare variable names resolve to Go template variables, not Helm values, causing nil pointer errors.Chart.yaml or values.yaml inside the templates/ directory — Helm only processes .yaml and .tpl files in templates/ during rendering.helm upgrade --install with --force in production scripts — it tears down and recreates resources, which can cause data loss for stateful workloads.extensions/v1beta1 for Deployments or networking.k8s.io/v1beta1 for Ingress) in templates.When this skill is active, the model's output must contain:
helm lint, helm template, and helm install --dry-run commands to verify the chart before distribution.helm package command and the appropriate push/install command for the target registry.| Skill | Purpose |
|---|---|
cncf-kubernetes | Cluster fundamentals, namespaces, and resource types referenced in charts |
coding-kubernetes-deployments-management | Advanced deployment strategies (canary, blue-green) that charts may implement |
cncf-prometheus | ServiceMonitor and Prometheus annotations that charts can inject for observability |