Blog post image for Helm Charts: Templating & Multi-Environment Kubernetes Deployments - Master Helm Charts for Kubernetes deployments. Learn templating, values overrides, conditional logic, chart dependencies, and GitOps workflows to manage complex microservices across dev, staging, and production environments.
Devtips

Helm Charts: Templating & Multi-Environment Kubernetes Deployments

Helm Charts: Templating & Multi-Environment Kubernetes Deployments

04 Mins read

Why Helm Matters

The Kubernetes Manifest Problem

Managing Kubernetes manifests at scale becomes a nightmare.

You have a deployment for dev, staging, and production. Each one is 90% identical same containers, same services but with different replicas, resource limits, environment variables. Copy-paste the YAML, make a few edits, and deploy. Works fine until someone edits dev and forgets to update staging. Or production has a typo and nobody notices until users report the outage.

Helm packages Kubernetes applications, providing templating, versioning, and dependency management transforming “paste YAML and hope” into “deploy with confidence.”

The Manual YAML Approach Breaks At Scale

Environment Fragmentation:
prod-deployment.yaml ← Different values hardcoded
staging-deployment.yaml ← Needs 3 edits for prod
dev-deployment.yaml ← Inconsistent structure
Result:
• Configurations drift
• Changes in one place aren't replicated
• Rollback = manually revert files
• New environments = copy-paste hell

The Solution: Helm Charts

What is Helm?

Helm is package management for Kubernetes, like npm for Node.js or pip for Python.

  • Charts: Helm packages containing templated Kubernetes manifests
  • Values: Configuration that gets injected into templates (replicas, image tags, resources)
  • Releases: Deployed instances of charts, tracked with versions for easy rollback
  • Repos: Central repositories where teams share charts

Core Benefits

  • Single chart, multiple environments: Use template variables instead of duplicating YAML
  • Templating system: {{ .Values.replicas }} → substituted with values from env-specific file
  • Dependency management: Charts can depend on other charts (PostgreSQL, Redis, etc.)
  • Versioning & rollback: Every deployment tracked, instant rollback to previous version
  • Validation: Helm validates charts before deployment
  • GitOps ready: Store charts in Git, deploy from Git

Chart Structure

Directory Layout

my-app/
├── Chart.yaml # Chart metadata (name, version, description)
├── values.yaml # Default values
├── values-dev.yaml # Dev environment overrides
├── values-staging.yaml # Staging overrides
├── values-prod.yaml # Production overrides
├── templates/
│ ├── deployment.yaml # Templated Kubernetes Deployment
│ ├── service.yaml # Service manifest
│ ├── configmap.yaml # ConfigMap for config
│ ├── hpa.yaml # Horizontal Pod Autoscaler (prod only)
│ └── _helpers.tpl # Template helpers/functions
└── README.md # Chart documentation

Chart.yaml

Chart.yaml
apiVersion: v2
name: my-app
description: A Helm chart for my microservice
type: application
version: 1.0.0 # Chart version
appVersion: '1.2.3' # Application version
maintainers:
- name: Your Team

Templating: The Power of Helm

Basic Values Templating

values.yaml
# Default values for all environments
replicaCount: 1
image:
repository: myregistry.azurecr.io/my-app
tag: '1.2.3'
pullPolicy: IfNotPresent
resources:
requests:
memory: '128Mi'
cpu: '100m'
limits:
memory: '256Mi'
cpu: '500m'
environment: 'dev'
debug: true
values-prod.yaml
# Production overrides
replicaCount: 3 # More replicas for load
resources:
requests:
memory: '512Mi'
cpu: '500m'
limits:
memory: '1Gi'
cpu: '2000m'
environment: 'production'
debug: false # Disable debug logging

Templated Deployment

templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.Release.Name}}
namespace: {{.Release.Namespace}}
spec:
replicas: {{.Values.replicaCount}} # Injected from values
selector:
matchLabels:
app: {{.Chart.Name}}
template:
metadata:
labels:
app: {{.Chart.Name}}
spec:
containers:
- name: {{.Chart.Name}}
image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}'
imagePullPolicy: {{.Values.image.pullPolicy}}
env:
- name: ENVIRONMENT
value: {{.Values.environment}}
- name: DEBUG
value: '{{ .Values.debug }}'
ports:
- containerPort: 8080
resources:
requests:
memory: {{.Values.resources.requests.memory | quote}}
cpu: {{.Values.resources.requests.cpu | quote}}
limits:
memory: {{.Values.resources.limits.memory | quote}}
cpu: {{.Values.resources.limits.cpu | quote}}

Conditional Logic in Helm Templates

Environment-Specific Configuration

templates/deployment.yaml
spec:
{{- if eq .Values.environment "production" }}
replicas: 3
{{- else if eq .Values.environment "staging" }}
replicas: 2
{{- else }}
replicas: 1
{{- end }}

Conditional Resources

templates/hpa.yaml
{{- if eq .Values.environment "production" }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ .Release.Name }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ .Release.Name }}
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
{{- end }}

Conditional Security Policies

templates/deployment.yaml
spec:
{{- if eq .Values.environment "production" }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsReadOnlyRootFilesystem: true
{{- end }}

Managing Multiple Environments

Environment-Specific Values Files

Deploy to dev:
helm install my-app . -f values.yaml -f values-dev.yaml
Deploy to staging:
helm install my-app . -f values.yaml -f values-staging.yaml
Deploy to prod:
helm install my-app . -f values.yaml -f values-prod.yaml

Values Priority (Right-to-left wins)

Terminal window
# Later files override earlier ones
helm install my-app \
-f values.yaml \ # Base defaults
-f values-prod.yaml \ # Override for prod
--set environment=production # Override from CLI (highest priority)

Chart Dependencies

Depends on PostgreSQL

Chart.yaml
dependencies:
- name: postgresql
version: '13.0.0'
repository: https://charts.bitnami.com/bitnami

Install Dependencies

Terminal window
# Download dependencies
helm dependency update
# Then deploy (PostgreSQL chart auto-installs)
helm install my-app . -f values-prod.yaml

Values for Dependencies

values-prod.yaml
# My app values
replicaCount: 3
# PostgreSQL sub-chart values
postgresql:
enabled: true
auth:
password: 'prod-secure-password'
primary:
persistence:
size: 100Gi
metrics:
enabled: true

Helm Release Management

Basic Deployment

Terminal window
# Install a release
helm install my-app ./chart -f values-prod.yaml
# Upgrade to new version
helm upgrade my-app ./chart -f values-prod.yaml
# Check release history
helm history my-app
# Rollback to previous version (instant!)
helm rollback my-app 2
# Delete release
helm uninstall my-app

Deployment Workflow

Terminal window
# 1. Make changes to chart
# 2. Test locally
helm install test-release . -f values-dev.yaml
# 3. Test succeeded, upgrade
helm uninstall test-release
# 4. Deploy to production
helm upgrade my-app . -f values-prod.yaml
# 5. Verify
kubectl get pods -l app=my-app
# 6. If something's wrong, instant rollback
helm rollback my-app

GitOps Integration

Store Charts in Git

git repository structure:
├── charts/
│ ├── my-app/
│ │ ├── Chart.yaml
│ │ ├── values.yaml
│ │ ├── values-dev.yaml
│ │ ├── values-prod.yaml
│ │ └── templates/
│ └── other-app/
├── .gitignore
└── README.md

GitOps Workflow with ArgoCD

ArgoCD watches your Git repo and automatically keeps your Kubernetes cluster in sync:

argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-prod
spec:
project: default
source:
repoURL: https://github.com/myteam/infrastructure
targetRevision: main
path: charts/my-app
helm:
values: |
environment: production
replicaCount: 3
destination:
server: https://kubernetes.default.svc
namespace: prod
syncPolicy:
automated:
prune: true
selfHeal: true

Deploy workflow:

1. Developer updates Chart in Git
2. Commits and pushes
3. ArgoCD detects change
4. Automatically syncs to Kubernetes
5. Helm applies new deployment
6. Services updated with zero downtime

Advanced Templating

Helper Functions

templates/_helpers.tpl
{{- define "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
{{- define "my-app.name" -}}
{{ .Chart.Name }}
{{- end }}
templates/deployment.yaml
# Reuse helper
metadata:
labels: {{- include "my-app.labels" . | nindent 4}}

Loops and Iterations

templates/deployment.yaml
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}

Best Practices

1. Semantic Versioning for Charts

version: 2.1.0 # MAJOR.MINOR.PATCH
# MAJOR: Breaking changes
# MINOR: New features
# PATCH: Bug fixes

2. Use Namespaces

Terminal window
# Deploy each environment to different namespace
helm install app . -n production -f values-prod.yaml
helm install app . -n staging -f values-staging.yaml
helm install app . -n dev -f values-dev.yaml

3. Helm Lint Before Deploy

Terminal window
# Validate chart syntax
helm lint ./chart
# Dry-run to see what will be deployed
helm install --dry-run my-app ./chart -f values-prod.yaml

4. Test Charts

Terminal window
helm test my-app # Run chart tests

5. Values Schema Validation

values.schema.json
{
'$schema': 'https://json-schema.org/draft-07/schema#',
'type': 'object',
'properties':
{
'replicaCount': {'type': 'integer', 'minimum': 1},
'image': {'type': 'object', 'properties': {'tag': {'type': 'string'}}},
},
}

Real-World Example: Complete Deployment

Minimal Chart Structure

my-service/
├── Chart.yaml
├── values.yaml
├── values-prod.yaml
└── templates/
├── deployment.yaml
└── service.yaml

Deploy

Terminal window
# Dev
helm install my-service . -f values.yaml -f values-dev.yaml
# Production
helm upgrade my-service . -f values.yaml -f values-prod.yaml --install
# Rollback if needed
helm rollback my-service

Conclusion

Helm transforms Kubernetes deployments from manual tedium to automated simplicity.

By templating your manifests, managing values per environment, and versioning releases, you eliminate the fragility of manual YAML management. Combined with GitOps tools like ArgoCD, Helm becomes the backbone of reliable, repeatable Kubernetes deployments.

Resources

Related Posts

You might also enjoy

Check out some of our other posts on similar topics

Policy-as-Code Governance with OPA/Rego

Policy-as-Code Governance with OPA/Rego

Why Policy-as-Code Matters The Governance Challenge Managing infrastructure at scale gets complicated fast. As your infrastructure grows, ensuring consistency and compliance becomes incr

Structured Logging & Log Aggregation with ELK Stack

Structured Logging & Log Aggregation with ELK Stack

Why Centralized Logging Matters The Logging Crisis When services fail, where do you look first? With distributed systems, logs scatter across servers, containers, and cloud regions. A si

Understanding Kubernetes Services: ClusterIP vs NodePort vs LoadBalancer

Understanding Kubernetes Services: ClusterIP vs NodePort vs LoadBalancer

Hey, trying to figure out how to expose your Kubernetes apps? If you're working with Kubernetes, you've probably noticed that Pods come and go, and their IP addresses keep changing. That's where

Tracing Microservices with OpenTelemetry

Tracing Microservices with OpenTelemetry

Why Monitor Your Microservices? The Complexity of Distributed Systems Hey, want to know what’s going on in your microservices? If you’re juggling multiple services, it’s hard to track ho

Container Image Vulnerability Scanning in CI/CD with Trivy

Container Image Vulnerability Scanning in CI/CD with Trivy

Why Container Security Matters The Vulnerability Problem Container images are a critical attack surface in modern deployments. Every time you build a container image, it includes the bas

Setting Up GitHub Copilot Agent Skills in Your Repository

Setting Up GitHub Copilot Agent Skills in Your Repository

Why Teach Copilot New Skills? The Power of Specialized Instructions Want Copilot to do more than just autocomplete? If you're ready to teach Copilot some new tricks, Agent Skills are you

6 related posts