Hereβs the standard layout of a Helm chart:
myapp/
βββ Chart.yaml
βββ values.yaml
βββ charts/
βββ templates/
β βββ _helpers.tpl
β βββ deployment.yaml
β βββ service.yaml
β βββ ingress.yaml
β βββ hpa.yaml
β βββ configmap.yaml
β βββ secret.yaml
β βββ NOTES.txt
βββ values-production.yaml
βββ values-dev.yaml
1. Chart.yaml
β Helm Metadata
apiVersion: v2
name: myapp
description: "A Helm chart for deploying MyApp"
type: application
version: 0.1.0
appVersion: "1.0.0"
This is the metadata file for your chart. It tells Helm the chartβs name, version, and the version of the application itβs deploying.
2. values.yaml
β Default Configuration
replicaCount: 2
image:
repository: myregistry/myapp
pullPolicy: IfNotPresent
tag: "1.0.0"
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
hosts:
- host: myapp.local
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.local
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 200m
memory: 128Mi
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
This is your default configuration file, and it can be overridden with environment-specific files like values-production.yaml
.
3. Environment-specific values
values-production.yaml
replicaCount: 3
image:
tag: "1.0.1"
env:
- name: SPRING_PROFILES_ACTIVE
value: production
This allows you to override values for different environments like production, staging, or dev.
Use it with:
helm install myapp ./myapp -f values-production.yaml
4. templates/
β All Kubernetes Manifests
Everything inside the templates/
directory gets converted into Kubernetes YAML.
π deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "myapp.fullname" . }}
template:
metadata:
labels:
app: {{ include "myapp.fullname" . }}
spec:
containers:
- name: myapp
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 8080
env:
{{- toYaml .Values.env | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
This file is responsible for the Kubernetes Deployment, defining how the app is run.
π service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "myapp.fullname" . }}
spec:
type: {{ .Values.service.type }}
selector:
app: {{ include "myapp.fullname" . }}
ports:
- port: {{ .Values.service.port }}
targetPort: 8080
This exposes your app inside the cluster or to the outside (depending on type).
π ingress.yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "myapp.fullname" . }}
annotations:
{{- toYaml .Values.ingress.annotations | nindent 4 }}
spec:
ingressClassName: {{ .Values.ingress.className }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "myapp.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
tls:
{{- toYaml .Values.ingress.tls | nindent 4 }}
{{- end }}
Use this when exposing your app via a domain name and TLS.
π hpa.yaml
β Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "myapp.fullname" . }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "myapp.fullname" . }}
minReplicas: 2
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80
Add this if you want auto-scaling based on CPU usage.
π configmap.yaml
β Config Injection
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "myapp.fullname" . }}-config
data:
app.properties: |
LOG_LEVEL=INFO
Used for injecting config files or environment-specific values.
π secret.yaml
β Secure Credentials
apiVersion: v1
kind: Secret
metadata:
name: {{ include "myapp.fullname" . }}-secret
type: Opaque
data:
password: {{ .Values.secret.password | b64enc | quote }}
Use this to pass sensitive data like passwords or API keys.
π _helpers.tpl
β Reusable Snippets
{{- define "myapp.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end }}
This is a great place to store helper functions and reusable naming logic.
π NOTES.txt
β Post-Install Tips
MyApp has been deployed!
Access it via:
http://{{ (index .Values.ingress.hosts 0).host }}
Check all resources:
kubectl get all -l app={{ include "myapp.fullname" . }}
This file gives helpful info to users after running helm install
.
π Useful Helm Commands
# Validate your chart
helm lint myapp/
# Dry-run your chart to see what it generates
helm install myapp ./myapp --dry-run --debug
# Install with default values
helm install myapp ./myapp
# Install with prod override
helm install myapp ./myapp -f values-production.yaml
# Upgrade release
helm upgrade myapp ./myapp -f values-production.yaml
# Uninstall
helm uninstall myapp
π§ Pro Tips
-
Use
_helpers.tpl
to keep templates DRY (Don't Repeat Yourself). - Use
values-production.yaml
,values-dev.yaml
, etc., to manage multiple environments cleanly. - Always run
helm lint
and--dry-run
before pushing changes to production. - Use
configmap
for non-sensitive settings,secret
for credentials. - Add autoscaling and resource limits for production-grade workloads.
β Summary
Helm simplifies Kubernetes deployments by giving you structure, reusability, and flexibility. By following this Helm chart structure and customizing templates wisely, you can confidently deploy complex applications to Kubernetes in a clean and maintainable way.
Top comments (0)