Comprehensive toolkit for generating best practice Helm charts and resources following current standards and conventions. Use this skill when creating new Helm charts, implementing Helm templates, or building Helm projects from scratch.
Overall
score
93%
Does it follow best practices?
Validation for skill structure
Common Custom Resource Definition patterns and examples for Helm charts.
File: templates/certificate.yaml
{{- if .Values.certificate.enabled }}
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ include "mychart.fullname" . }}-tls
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
secretName: {{ include "mychart.fullname" . }}-tls
issuerRef:
name: {{ .Values.certificate.issuer.name }}
kind: {{ .Values.certificate.issuer.kind | default "ClusterIssuer" }}
{{- with .Values.certificate.issuer.group }}
group: {{ . }}
{{- end }}
commonName: {{ .Values.certificate.commonName | default (first .Values.certificate.dnsNames) }}
dnsNames:
{{- range .Values.certificate.dnsNames }}
- {{ . | quote }}
{{- end }}
{{- with .Values.certificate.ipAddresses }}
ipAddresses:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.uris }}
uris:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.duration }}
duration: {{ . }}
{{- end }}
{{- with .Values.certificate.renewBefore }}
renewBefore: {{ . }}
{{- end }}
{{- with .Values.certificate.usages }}
usages:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.privateKey }}
privateKey:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.certificate.keystores }}
keystores:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
certificate:
enabled: false
issuer:
name: letsencrypt-prod
kind: ClusterIssuer
group: cert-manager.io
commonName: ""
dnsNames:
- example.com
- www.example.com
ipAddresses: []
uris: []
duration: 2160h # 90 days
renewBefore: 360h # 15 days
usages:
- digital signature
- key encipherment
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
rotationPolicy: Never
keystores: {}
# keystores:
# jks:
# create: true
# passwordSecretRef:
# name: jks-password
# key: passwordFile: templates/clusterissuer.yaml
{{- if .Values.certManager.clusterIssuer.create }}
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: {{ .Values.certManager.clusterIssuer.name }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
{{- if eq .Values.certManager.clusterIssuer.type "acme" }}
acme:
server: {{ .Values.certManager.clusterIssuer.acme.server }}
email: {{ required "certManager.clusterIssuer.acme.email is required!" .Values.certManager.clusterIssuer.acme.email }}
privateKeySecretRef:
name: {{ .Values.certManager.clusterIssuer.acme.privateKeySecretName }}
solvers:
{{- range .Values.certManager.clusterIssuer.acme.solvers }}
- {{ toYaml . | nindent 6 }}
{{- end }}
{{- else if eq .Values.certManager.clusterIssuer.type "ca" }}
ca:
secretName: {{ .Values.certManager.clusterIssuer.ca.secretName }}
{{- else if eq .Values.certManager.clusterIssuer.type "selfSigned" }}
selfSigned: {}
{{- end }}
{{- end }}Corresponding values.yaml:
certManager:
clusterIssuer:
create: false
name: letsencrypt-prod
type: acme # acme, ca, selfSigned, vault, venafi
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretName: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: nginx
# - dns01:
# cloudflare:
# email: admin@example.com
# apiTokenSecretRef:
# name: cloudflare-api-token
# key: api-token
ca:
secretName: ca-key-pairFile: templates/servicemonitor.yaml
{{- if .Values.metrics.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.metrics.serviceMonitor.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
endpoints:
- port: {{ .Values.metrics.serviceMonitor.port | default "metrics" }}
{{- with .Values.metrics.serviceMonitor.interval }}
interval: {{ . }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.scrapeTimeout }}
scrapeTimeout: {{ . }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.path }}
path: {{ . }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.scheme }}
scheme: {{ . }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.tlsConfig }}
tlsConfig:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.relabelings }}
relabelings:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.metricRelabelings }}
metricRelabelings:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .Values.metrics.serviceMonitor.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
metrics:
enabled: true
port: 9090
serviceMonitor:
enabled: false
labels: {}
annotations: {}
port: metrics
interval: 30s
scrapeTimeout: 10s
path: /metrics
scheme: http
tlsConfig: {}
relabelings: []
metricRelabelings: []
namespaceSelector: {}File: templates/prometheusrule.yaml
{{- if .Values.metrics.prometheusRule.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.metrics.prometheusRule.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
groups:
{{- range .Values.metrics.prometheusRule.groups }}
- name: {{ .name }}
{{- with .interval }}
interval: {{ . }}
{{- end }}
rules:
{{- range .rules }}
- alert: {{ .alert }}
expr: {{ .expr }}
{{- with .for }}
for: {{ . }}
{{- end }}
{{- with .labels }}
labels:
{{- toYaml . | nindent 8 }}
{{- end }}
annotations:
{{- range $key, $value := .annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
metrics:
prometheusRule:
enabled: false
labels: {}
groups:
- name: mychart-alerts
interval: 30s
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
for: 10m
labels:
severity: warning
annotations:
summary: "High error rate detected"
description: "Error rate is {{ $value }} errors per second"
- alert: PodDown
expr: up{job="mychart"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Pod is down"
description: "Pod {{ $labels.pod }} is down"File: templates/virtualservice.yaml
{{- if .Values.istio.virtualService.enabled }}
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
hosts:
{{- range .Values.istio.virtualService.hosts }}
- {{ . | quote }}
{{- end }}
{{- with .Values.istio.virtualService.gateways }}
gateways:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.istio.virtualService.http }}
http:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.istio.virtualService.tcp }}
tcp:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.istio.virtualService.tls }}
tls:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
istio:
virtualService:
enabled: false
hosts:
- example.com
gateways:
- istio-system/gateway
http:
- match:
- uri:
prefix: /api
route:
- destination:
host: mychart-svc
port:
number: 80
weight: 90
- destination:
host: mychart-svc-canary
port:
number: 80
weight: 10
timeout: 30s
retries:
attempts: 3
perTryTimeout: 10s
tcp: []
tls: []File: templates/gateway.yaml
{{- if .Values.istio.gateway.enabled }}
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
selector:
{{- toYaml .Values.istio.gateway.selector | nindent 4 }}
servers:
{{- range .Values.istio.gateway.servers }}
- port:
number: {{ .port.number }}
name: {{ .port.name }}
protocol: {{ .port.protocol }}
hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
{{- with .tls }}
tls:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
istio:
gateway:
enabled: false
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- example.com
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- example.com
tls:
mode: SIMPLE
credentialName: example-com-tlsFile: templates/destinationrule.yaml
{{- if .Values.istio.destinationRule.enabled }}
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
host: {{ .Values.istio.destinationRule.host | default (include "mychart.fullname" .) }}
{{- with .Values.istio.destinationRule.trafficPolicy }}
trafficPolicy:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.istio.destinationRule.subsets }}
subsets:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
istio:
destinationRule:
enabled: false
host: mychart-svc
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
http2MaxRequests: 100
loadBalancer:
simple: LEAST_REQUEST
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
simple: ROUND_ROBINFile: templates/argocd-application.yaml
{{- if .Values.argocd.application.enabled }}
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ include "mychart.fullname" . }}
namespace: {{ .Values.argocd.application.namespace | default "argocd" }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.argocd.application.finalizers }}
finalizers:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
project: {{ .Values.argocd.application.project | default "default" }}
source:
repoURL: {{ required "argocd.application.source.repoURL is required!" .Values.argocd.application.source.repoURL }}
targetRevision: {{ .Values.argocd.application.source.targetRevision | default "HEAD" }}
path: {{ .Values.argocd.application.source.path }}
{{- with .Values.argocd.application.source.helm }}
helm:
{{- toYaml . | nindent 6 }}
{{- end }}
destination:
server: {{ .Values.argocd.application.destination.server | default "https://kubernetes.default.svc" }}
namespace: {{ .Values.argocd.application.destination.namespace | default .Release.Namespace }}
syncPolicy:
{{- with .Values.argocd.application.syncPolicy }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.argocd.application.ignoreDifferences }}
ignoreDifferences:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
argocd:
application:
enabled: false
namespace: argocd
project: default
finalizers:
- resources-finalizer.argocd.argoproj.io
source:
repoURL: https://github.com/example/repo
targetRevision: main
path: charts/mychart
helm:
releaseName: mychart
valueFiles:
- values.yaml
values: ""
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PruneLast=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
ignoreDifferences: []File: templates/argocd-appproject.yaml
{{- if .Values.argocd.appProject.enabled }}
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: {{ .Values.argocd.appProject.name }}
namespace: {{ .Values.argocd.appProject.namespace | default "argocd" }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.argocd.appProject.finalizers }}
finalizers:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
description: {{ .Values.argocd.appProject.description }}
sourceRepos:
{{- range .Values.argocd.appProject.sourceRepos }}
- {{ . | quote }}
{{- end }}
destinations:
{{- range .Values.argocd.appProject.destinations }}
- namespace: {{ .namespace }}
server: {{ .server }}
{{- end }}
{{- with .Values.argocd.appProject.clusterResourceWhitelist }}
clusterResourceWhitelist:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.argocd.appProject.namespaceResourceWhitelist }}
namespaceResourceWhitelist:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
argocd:
appProject:
enabled: false
name: myproject
namespace: argocd
description: "My ArgoCD Project"
finalizers:
- resources-finalizer.argocd.argoproj.io
sourceRepos:
- '*'
destinations:
- namespace: '*'
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: '*'
kind: '*'
namespaceResourceWhitelist: []File: templates/sealedsecret.yaml
{{- if .Values.sealedSecret.enabled }}
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
encryptedData:
{{- range $key, $value := .Values.sealedSecret.encryptedData }}
{{ $key }}: {{ $value }}
{{- end }}
template:
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 8 }}
type: {{ .Values.sealedSecret.type | default "Opaque" }}
{{- end }}Corresponding values.yaml:
sealedSecret:
enabled: false
type: Opaque
encryptedData: {}
# API_KEY: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...
# DATABASE_PASSWORD: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...File: templates/externalsecret.yaml
{{- if .Values.externalSecret.enabled }}
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
secretStoreRef:
name: {{ .Values.externalSecret.secretStoreRef.name }}
kind: {{ .Values.externalSecret.secretStoreRef.kind | default "SecretStore" }}
target:
name: {{ include "mychart.fullname" . }}
{{- with .Values.externalSecret.target.creationPolicy }}
creationPolicy: {{ . }}
{{- end }}
{{- with .Values.externalSecret.target.template }}
template:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .Values.externalSecret.refreshInterval }}
refreshInterval: {{ . }}
{{- end }}
{{- if .Values.externalSecret.data }}
data:
{{- range .Values.externalSecret.data }}
- secretKey: {{ .secretKey }}
remoteRef:
key: {{ .remoteRef.key }}
{{- with .remoteRef.property }}
property: {{ . }}
{{- end }}
{{- with .remoteRef.version }}
version: {{ . }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.externalSecret.dataFrom }}
dataFrom:
{{- range .Values.externalSecret.dataFrom }}
- extract:
key: {{ .extract.key }}
{{- with .extract.property }}
property: {{ . }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
externalSecret:
enabled: false
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
creationPolicy: Owner
template:
type: Opaque
refreshInterval: 1h
data:
- secretKey: API_KEY
remoteRef:
key: secret/data/myapp
property: api_key
- secretKey: DATABASE_PASSWORD
remoteRef:
key: secret/data/myapp
property: db_password
dataFrom: []
# dataFrom:
# - extract:
# key: secret/data/myappFile: templates/secretstore.yaml
{{- if .Values.externalSecret.secretStore.create }}
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: {{ .Values.externalSecret.secretStore.name }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
provider:
{{- if .Values.externalSecret.secretStore.provider.vault }}
vault:
server: {{ .Values.externalSecret.secretStore.provider.vault.server }}
path: {{ .Values.externalSecret.secretStore.provider.vault.path }}
version: {{ .Values.externalSecret.secretStore.provider.vault.version | default "v2" }}
auth:
{{- toYaml .Values.externalSecret.secretStore.provider.vault.auth | nindent 8 }}
{{- else if .Values.externalSecret.secretStore.provider.aws }}
aws:
service: {{ .Values.externalSecret.secretStore.provider.aws.service }}
region: {{ .Values.externalSecret.secretStore.provider.aws.region }}
{{- with .Values.externalSecret.secretStore.provider.aws.auth }}
auth:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- else if .Values.externalSecret.secretStore.provider.gcpsm }}
gcpsm:
projectID: {{ .Values.externalSecret.secretStore.provider.gcpsm.projectID }}
{{- with .Values.externalSecret.secretStore.provider.gcpsm.auth }}
auth:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
externalSecret:
secretStore:
create: false
name: vault-backend
provider:
vault:
server: https://vault.example.com
path: secret
version: v2
auth:
kubernetes:
mountPath: kubernetes
role: myapp
serviceAccountRef:
name: mychart
# aws:
# service: SecretsManager
# region: us-east-1
# auth:
# jwt:
# serviceAccountRef:
# name: mychart
# gcpsm:
# projectID: my-project
# auth:
# workloadIdentity:
# clusterLocation: us-central1
# clusterName: my-cluster
# serviceAccountRef:
# name: mychartThe Gateway API is the evolution of Kubernetes Ingress, providing more expressive and extensible routing capabilities. It's becoming the standard for north-south traffic management in Kubernetes.
File: templates/gatewayclass.yaml
{{- if .Values.gatewayAPI.gatewayClass.create }}
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: {{ .Values.gatewayAPI.gatewayClass.name }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.gatewayAPI.gatewayClass.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
controllerName: {{ required "gatewayAPI.gatewayClass.controllerName is required!" .Values.gatewayAPI.gatewayClass.controllerName }}
{{- with .Values.gatewayAPI.gatewayClass.parametersRef }}
parametersRef:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.gatewayAPI.gatewayClass.description }}
description: {{ . | quote }}
{{- end }}
{{- end }}Corresponding values.yaml:
gatewayAPI:
gatewayClass:
create: false
name: my-gateway-class
# Controller implementations:
# - gateway.nginx.org/nginx-gateway-controller (NGINX Gateway Fabric)
# - gateway.envoyproxy.io/gatewayclass-controller (Envoy Gateway)
# - istio.io/gateway-controller (Istio)
# - projectcontour.io/gateway-controller (Contour)
# - traefik.io/gateway-controller (Traefik)
controllerName: gateway.nginx.org/nginx-gateway-controller
annotations: {}
description: "Production gateway class"
parametersRef: {}
# parametersRef:
# group: gateway.nginx.org
# kind: NginxProxy
# name: nginx-proxy-configFile: templates/gateway.yaml
{{- if .Values.gatewayAPI.gateway.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: {{ include "mychart.fullname" . }}
namespace: {{ .Values.gatewayAPI.gateway.namespace | default .Release.Namespace }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.gatewayAPI.gateway.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
gatewayClassName: {{ required "gatewayAPI.gateway.gatewayClassName is required!" .Values.gatewayAPI.gateway.gatewayClassName }}
{{- with .Values.gatewayAPI.gateway.addresses }}
addresses:
{{- toYaml . | nindent 4 }}
{{- end }}
listeners:
{{- range .Values.gatewayAPI.gateway.listeners }}
- name: {{ .name }}
hostname: {{ .hostname | quote }}
port: {{ .port }}
protocol: {{ .protocol }}
{{- with .tls }}
tls:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .allowedRoutes }}
allowedRoutes:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- end }}
{{- with .Values.gatewayAPI.gateway.infrastructure }}
infrastructure:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
gatewayAPI:
gateway:
enabled: false
namespace: "" # defaults to release namespace
gatewayClassName: my-gateway-class
annotations: {}
addresses: []
# addresses:
# - type: IPAddress
# value: 10.0.0.1
listeners:
- name: http
hostname: "*.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
kinds:
- kind: HTTPRoute
- name: https
hostname: "*.example.com"
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- name: example-com-tls
kind: Secret
allowedRoutes:
namespaces:
from: Same
kinds:
- kind: HTTPRoute
infrastructure: {}
# infrastructure:
# labels:
# app: my-gateway
# annotations:
# service.beta.kubernetes.io/aws-load-balancer-type: nlbFile: templates/httproute.yaml
{{- if .Values.gatewayAPI.httpRoute.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ include "mychart.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.gatewayAPI.httpRoute.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.gatewayAPI.httpRoute.parentRefs }}
parentRefs:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.gatewayAPI.httpRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.gatewayAPI.httpRoute.rules }}
- {{- with .matches }}
matches:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 6 }}
{{- end }}
backendRefs:
{{- range .backendRefs }}
- name: {{ .name | default (include "mychart.fullname" $) }}
port: {{ .port | default $.Values.service.port }}
{{- with .weight }}
weight: {{ . }}
{{- end }}
{{- with .kind }}
kind: {{ . }}
{{- end }}
{{- with .namespace }}
namespace: {{ . }}
{{- end }}
{{- end }}
{{- with .timeouts }}
timeouts:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
gatewayAPI:
httpRoute:
enabled: false
annotations: {}
parentRefs:
- name: my-gateway
namespace: default
sectionName: https
hostnames:
- app.example.com
rules:
# Simple routing to backend service
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: "" # defaults to chart fullname
port: 0 # defaults to service.port
weight: 100
# Path-based routing with multiple backends
- matches:
- path:
type: PathPrefix
value: /api
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: api-service
port: 8080
weight: 90
- name: api-service-canary
port: 8080
weight: 10
# Header-based routing
- matches:
- headers:
- name: X-Version
value: beta
backendRefs:
- name: beta-service
port: 8080
# Method-based routing
- matches:
- method: POST
path:
type: Exact
value: /webhook
backendRefs:
- name: webhook-service
port: 8080
timeouts:
request: 30sFile: templates/httproute-advanced.yaml
{{- if .Values.gatewayAPI.httpRouteAdvanced.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ include "mychart.fullname" . }}-advanced
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
parentRefs:
- name: {{ .Values.gatewayAPI.httpRouteAdvanced.gatewayRef }}
hostnames:
{{- range .Values.gatewayAPI.httpRouteAdvanced.hostnames }}
- {{ . | quote }}
{{- end }}
rules:
{{- if .Values.gatewayAPI.httpRouteAdvanced.redirectHttpToHttps }}
# HTTP to HTTPS redirect
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
{{- end }}
{{- if .Values.gatewayAPI.httpRouteAdvanced.urlRewrite }}
# URL rewrite
- matches:
- path:
type: PathPrefix
value: {{ .Values.gatewayAPI.httpRouteAdvanced.urlRewrite.matchPath }}
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: {{ .Values.gatewayAPI.httpRouteAdvanced.urlRewrite.replacePath }}
backendRefs:
- name: {{ include "mychart.fullname" . }}
port: {{ .Values.service.port }}
{{- end }}
{{- if .Values.gatewayAPI.httpRouteAdvanced.requestHeaderModifier }}
# Request header modification
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
{{- with .Values.gatewayAPI.httpRouteAdvanced.requestHeaderModifier.set }}
set:
{{- range . }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
{{- end }}
{{- with .Values.gatewayAPI.httpRouteAdvanced.requestHeaderModifier.add }}
add:
{{- range . }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
{{- end }}
{{- with .Values.gatewayAPI.httpRouteAdvanced.requestHeaderModifier.remove }}
remove:
{{- toYaml . | nindent 12 }}
{{- end }}
backendRefs:
- name: {{ include "mychart.fullname" . }}
port: {{ .Values.service.port }}
{{- end }}
{{- end }}Corresponding values.yaml:
gatewayAPI:
httpRouteAdvanced:
enabled: false
gatewayRef: my-gateway
hostnames:
- app.example.com
# HTTP to HTTPS redirect
redirectHttpToHttps: false
# URL rewrite configuration
urlRewrite:
matchPath: /old-api
replacePath: /api/v2
# Request header modification
requestHeaderModifier:
set:
- name: X-Forwarded-Proto
value: https
add:
- name: X-Request-ID
value: "{{ .Release.Name }}"
remove:
- X-Internal-HeaderFile: templates/grpcroute.yaml
{{- if .Values.gatewayAPI.grpcRoute.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: {{ include "mychart.fullname" . }}-grpc
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
parentRefs:
{{- range .Values.gatewayAPI.grpcRoute.parentRefs }}
- name: {{ .name }}
{{- with .namespace }}
namespace: {{ . }}
{{- end }}
{{- with .sectionName }}
sectionName: {{ . }}
{{- end }}
{{- end }}
{{- with .Values.gatewayAPI.grpcRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.gatewayAPI.grpcRoute.rules }}
- {{- with .matches }}
matches:
{{- toYaml . | nindent 6 }}
{{- end }}
backendRefs:
{{- range .backendRefs }}
- name: {{ .name }}
port: {{ .port }}
{{- with .weight }}
weight: {{ . }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
gatewayAPI:
grpcRoute:
enabled: false
parentRefs:
- name: my-gateway
sectionName: grpc
hostnames:
- grpc.example.com
rules:
# Route all gRPC traffic
- backendRefs:
- name: grpc-service
port: 50051
weight: 100
# Method-specific routing
- matches:
- method:
service: myservice.MyService
method: MyMethod
backendRefs:
- name: grpc-service-v2
port: 50051File: templates/referencegrant.yaml
{{- if .Values.gatewayAPI.referenceGrant.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: {{ include "mychart.fullname" . }}-grant
namespace: {{ .Values.gatewayAPI.referenceGrant.namespace | default .Release.Namespace }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
from:
{{- range .Values.gatewayAPI.referenceGrant.from }}
- group: {{ .group }}
kind: {{ .kind }}
namespace: {{ .namespace }}
{{- end }}
to:
{{- range .Values.gatewayAPI.referenceGrant.to }}
- group: {{ .group | default "" | quote }}
kind: {{ .kind }}
{{- with .name }}
name: {{ . }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
gatewayAPI:
referenceGrant:
enabled: false
namespace: "" # defaults to release namespace
# Allow Gateway in gateway-ns to reference Secrets in this namespace
from:
- group: gateway.networking.k8s.io
kind: Gateway
namespace: gateway-ns
to:
- group: ""
kind: Secret
# name: specific-secret # optional: restrict to specific secretKEDA (Kubernetes Event-driven Autoscaling) provides event-driven autoscaling for Kubernetes workloads. It can scale based on events from various sources like message queues, databases, HTTP requests, and more.
File: templates/scaledobject.yaml
{{- if .Values.keda.enabled }}
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.keda.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
scaleTargetRef:
apiVersion: {{ .Values.keda.scaleTargetRef.apiVersion | default "apps/v1" }}
kind: {{ .Values.keda.scaleTargetRef.kind | default "Deployment" }}
name: {{ .Values.keda.scaleTargetRef.name | default (include "mychart.fullname" .) }}
{{- with .Values.keda.scaleTargetRef.envSourceContainerName }}
envSourceContainerName: {{ . }}
{{- end }}
pollingInterval: {{ .Values.keda.pollingInterval | default 30 }}
cooldownPeriod: {{ .Values.keda.cooldownPeriod | default 300 }}
{{- with .Values.keda.idleReplicaCount }}
idleReplicaCount: {{ . }}
{{- end }}
minReplicaCount: {{ .Values.keda.minReplicaCount | default 0 }}
maxReplicaCount: {{ .Values.keda.maxReplicaCount | default 100 }}
{{- with .Values.keda.fallback }}
fallback:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.keda.advanced }}
advanced:
{{- toYaml . | nindent 4 }}
{{- end }}
triggers:
{{- range .Values.keda.triggers }}
- type: {{ .type }}
{{- with .name }}
name: {{ . }}
{{- end }}
metadata:
{{- range $key, $value := .metadata }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- with .authenticationRef }}
authenticationRef:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .metricType }}
metricType: {{ . }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
keda:
enabled: false
annotations: {}
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: "" # defaults to chart fullname
envSourceContainerName: "" # optional: container to source env from
pollingInterval: 30 # seconds
cooldownPeriod: 300 # seconds
idleReplicaCount: 0 # scale to 0 when idle (optional)
minReplicaCount: 1
maxReplicaCount: 10
fallback:
failureThreshold: 3
replicas: 2
advanced:
restoreToOriginalReplicaCount: true
horizontalPodAutoscalerConfig:
name: "" # custom HPA name
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
triggers:
# CPU-based scaling
- type: cpu
metricType: Utilization
metadata:
value: "80"
# Memory-based scaling
- type: memory
metricType: Utilization
metadata:
value: "80"
# Prometheus metrics
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: http_requests_total
query: sum(rate(http_requests_total{deployment="mychart"}[2m]))
threshold: "100"
# RabbitMQ queue length
- type: rabbitmq
metadata:
host: amqp://rabbitmq:5672
queueName: myqueue
queueLength: "50"
authenticationRef:
name: rabbitmq-auth
# Kafka consumer lag
- type: kafka
metadata:
bootstrapServers: kafka:9092
consumerGroup: my-group
topic: my-topic
lagThreshold: "100"
# Redis list length
- type: redis
metadata:
address: redis:6379
listName: mylist
listLength: "10"
# AWS SQS queue
- type: aws-sqs-queue
metadata:
queueURL: https://sqs.us-east-1.amazonaws.com/123456789/myqueue
queueLength: "50"
awsRegion: us-east-1
authenticationRef:
name: aws-credentials
# Cron-based scaling
- type: cron
metadata:
timezone: America/New_York
start: "0 8 * * 1-5" # 8 AM weekdays
end: "0 18 * * 1-5" # 6 PM weekdays
desiredReplicas: "10"File: templates/scaledjob.yaml
{{- if .Values.keda.scaledJob.enabled }}
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
name: {{ include "mychart.fullname" . }}-job
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
jobTargetRef:
parallelism: {{ .Values.keda.scaledJob.parallelism | default 1 }}
completions: {{ .Values.keda.scaledJob.completions | default 1 }}
activeDeadlineSeconds: {{ .Values.keda.scaledJob.activeDeadlineSeconds | default 600 }}
backoffLimit: {{ .Values.keda.scaledJob.backoffLimit | default 6 }}
template:
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 10 }}
{{- end }}
restartPolicy: {{ .Values.keda.scaledJob.restartPolicy | default "Never" }}
containers:
- name: {{ .Chart.Name }}-job
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- with .Values.keda.scaledJob.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.keda.scaledJob.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.keda.scaledJob.env }}
env:
{{- toYaml . | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.keda.scaledJob.resources | nindent 12 }}
pollingInterval: {{ .Values.keda.scaledJob.pollingInterval | default 30 }}
successfulJobsHistoryLimit: {{ .Values.keda.scaledJob.successfulJobsHistoryLimit | default 5 }}
failedJobsHistoryLimit: {{ .Values.keda.scaledJob.failedJobsHistoryLimit | default 5 }}
maxReplicaCount: {{ .Values.keda.scaledJob.maxReplicaCount | default 100 }}
scalingStrategy:
strategy: {{ .Values.keda.scaledJob.scalingStrategy | default "default" }}
triggers:
{{- range .Values.keda.scaledJob.triggers }}
- type: {{ .type }}
metadata:
{{- range $key, $value := .metadata }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- with .authenticationRef }}
authenticationRef:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
keda:
scaledJob:
enabled: false
parallelism: 1
completions: 1
activeDeadlineSeconds: 600
backoffLimit: 6
restartPolicy: Never
pollingInterval: 30
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 5
maxReplicaCount: 100
scalingStrategy: default # default, custom, accurate
command: []
args: []
env: []
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
triggers:
- type: aws-sqs-queue
metadata:
queueURL: https://sqs.us-east-1.amazonaws.com/123456789/myqueue
queueLength: "5"
awsRegion: us-east-1File: templates/triggerauthentication.yaml
{{- if .Values.keda.authentication.enabled }}
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
name: {{ include "mychart.fullname" . }}-auth
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
{{- with .Values.keda.authentication.secretTargetRef }}
secretTargetRef:
{{- range . }}
- parameter: {{ .parameter }}
name: {{ .name }}
key: {{ .key }}
{{- end }}
{{- end }}
{{- with .Values.keda.authentication.env }}
env:
{{- range . }}
- parameter: {{ .parameter }}
name: {{ .name }}
{{- with .containerName }}
containerName: {{ . }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.keda.authentication.podIdentity }}
podIdentity:
provider: {{ .provider }}
{{- with .identityId }}
identityId: {{ . }}
{{- end }}
{{- end }}
{{- with .Values.keda.authentication.hashiCorpVault }}
hashiCorpVault:
address: {{ .address }}
authentication: {{ .authentication }}
{{- with .role }}
role: {{ . }}
{{- end }}
{{- with .mount }}
mount: {{ . }}
{{- end }}
credential:
{{- toYaml .credential | nindent 6 }}
secrets:
{{- range .secrets }}
- parameter: {{ .parameter }}
key: {{ .key }}
path: {{ .path }}
{{- end }}
{{- end }}
{{- end }}Corresponding values.yaml:
keda:
authentication:
enabled: false
# Secret-based authentication
secretTargetRef:
- parameter: connection
name: rabbitmq-secret
key: connectionString
- parameter: password
name: db-secret
key: password
# Environment variable authentication
env:
- parameter: awsAccessKeyID
name: AWS_ACCESS_KEY_ID
- parameter: awsSecretAccessKey
name: AWS_SECRET_ACCESS_KEY
# Pod identity (Azure, AWS IRSA, GCP Workload Identity)
podIdentity:
provider: azure # azure, aws-eks, gcp
identityId: "" # optional: specific identity
# HashiCorp Vault authentication
hashiCorpVault:
address: https://vault.example.com
authentication: token # token, kubernetes
role: my-role
mount: secret
credential:
token: vault-token # or serviceAccount for kubernetes auth
secrets:
- parameter: connection
key: connectionString
path: secret/data/myappThe VerticalPodAutoscaler automatically adjusts the CPU and memory reservations for pods to help "right-size" your applications.
File: templates/vpa.yaml
{{- if .Values.vpa.enabled }}
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.vpa.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
targetRef:
apiVersion: {{ .Values.vpa.targetRef.apiVersion | default "apps/v1" }}
kind: {{ .Values.vpa.targetRef.kind | default "Deployment" }}
name: {{ .Values.vpa.targetRef.name | default (include "mychart.fullname" .) }}
updatePolicy:
updateMode: {{ .Values.vpa.updatePolicy.updateMode | default "Auto" }}
{{- with .Values.vpa.updatePolicy.minReplicas }}
minReplicas: {{ . }}
{{- end }}
{{- with .Values.vpa.resourcePolicy }}
resourcePolicy:
containerPolicies:
{{- range .containerPolicies }}
- containerName: {{ .containerName | default "*" }}
{{- with .mode }}
mode: {{ . }}
{{- end }}
{{- with .minAllowed }}
minAllowed:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .maxAllowed }}
maxAllowed:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .controlledResources }}
controlledResources:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .controlledValues }}
controlledValues: {{ . }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.vpa.recommenders }}
recommenders:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}Corresponding values.yaml:
vpa:
enabled: false
annotations: {}
targetRef:
apiVersion: apps/v1
kind: Deployment
name: "" # defaults to chart fullname
updatePolicy:
# Auto - VPA assigns resource requests on pod creation and updates on existing pods
# Recreate - VPA assigns resource requests on pod creation and kills existing pods
# Initial - VPA only assigns requests on pod creation, never updates
# Off - VPA does not update pods, only provides recommendations
updateMode: "Auto"
minReplicas: 1 # minimum replicas for VPA to act on
resourcePolicy:
containerPolicies:
# Apply to all containers
- containerName: "*"
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 2
memory: 4Gi
controlledResources:
- cpu
- memory
controlledValues: RequestsAndLimits # RequestsOnly or RequestsAndLimits
# Specific container policy
- containerName: my-container
mode: Auto # Auto or Off
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 1
memory: 2Gi
# Custom recommenders (optional, requires VPA 0.11+)
recommenders:
- name: custom-recommenderFor applications where you want VPA recommendations without automatic updates:
File: templates/vpa-recommendation.yaml
{{- if .Values.vpa.recommendationOnly.enabled }}
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: {{ include "mychart.fullname" . }}-recommendation
labels:
{{- include "mychart.labels" . | nindent 4 }}
vpa-mode: recommendation-only
spec:
targetRef:
apiVersion: apps/v1
kind: {{ .Values.vpa.recommendationOnly.kind | default "Deployment" }}
name: {{ include "mychart.fullname" . }}
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: {{ .Values.vpa.recommendationOnly.minCpu | default "25m" }}
memory: {{ .Values.vpa.recommendationOnly.minMemory | default "32Mi" }}
maxAllowed:
cpu: {{ .Values.vpa.recommendationOnly.maxCpu | default "4" }}
memory: {{ .Values.vpa.recommendationOnly.maxMemory | default "8Gi" }}
{{- end }}Corresponding values.yaml:
vpa:
recommendationOnly:
enabled: false
kind: Deployment
minCpu: 25m
minMemory: 32Mi
maxCpu: 4
maxMemory: 8GiAlways wrap CRD resources in conditional blocks:
{{- if .Values.certificate.enabled }}
# CRD resource
{{- end }}Use required for critical CRD fields:
email: {{ required "certManager.clusterIssuer.acme.email is required!" .Values.certManager.clusterIssuer.acme.email }}Document CRD dependencies in Chart.yaml:
annotations:
operatorDependencies: |
- name: cert-manager
version: ">=1.12.0"
url: https://cert-manager.io/docs/installation/Provide sensible defaults for all CRD fields:
certificate:
enabled: false
duration: 2160h
renewBefore: 360hBe explicit about API versions:
apiVersion: cert-manager.io/v1 # Not v1alpha1 or v1beta1Use chart helpers for consistent labeling:
metadata:
name: {{ include "mychart.fullname" . }}-tls
labels:
{{- include "mychart.labels" . | nindent 4 }}Always test CRD resources with:
helm template to verify renderinghelm lint to check syntaxkubectl apply --dry-run=server to validate against clusterInstall with Tessl CLI
npx tessl i pantheon-ai/helm-generator@0.1.0