Kubernetes Helm Charts in 2026: Packaging, Deployment and Interview Questions

Learn Helm chart structure, templating, dependencies, and deployment strategies. Includes common interview questions and best practices for production deployments.

Kubernetes Helm Charts deployment and packaging visualization

Kubernetes Helm Charts simplify application deployment by packaging all Kubernetes resources into a single, versioned artifact. Helm 3, the current stable release, eliminates the need for Tiller and introduces OCI registry support, making chart distribution more secure and standardized. This tutorial covers chart creation, templating, deployment strategies, and the most common interview questions asked by hiring teams.

Helm 3 Quick Reference

Helm charts contain a Chart.yaml (metadata), values.yaml (defaults), and a templates/ directory with Kubernetes manifests. The helm install command renders templates with values and applies them to the cluster.

Understanding Helm Chart Structure and Components

A Helm chart is a directory with a predefined structure. The chart name becomes the directory name, and every file serves a specific purpose in the packaging and deployment process.

yaml
# Chart.yaml
apiVersion: v2
name: my-application
description: A production-ready web application
type: application
version: 1.0.0
appVersion: "2.1.0"
dependencies:
  - name: postgresql
    version: "15.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

The apiVersion: v2 indicates Helm 3 compatibility. The version field tracks chart changes, while appVersion reflects the deployed application version. Dependencies declare other charts this chart requires, with optional conditions to enable or disable them.

yaml
# values.yaml
replicaCount: 3

image:
  repository: myregistry.io/app
  tag: "2.1.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 8080

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

postgresql:
  enabled: true
  auth:
    database: appdb

Values define configuration defaults that users override during installation. Nesting values under meaningful keys keeps configurations organized and self-documenting.

Creating Kubernetes Deployments with Helm Templates

Helm templates use Go templating with Sprig functions to generate Kubernetes manifests dynamically. The {{ .Values }} object provides access to values.yaml content, while {{ .Release }} contains deployment metadata.

yaml
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-application.fullname" . }}
  labels:
    {{- include "my-application.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "my-application.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-application.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.port }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

The nindent function adds newline and indentation, critical for YAML generation. Using include with named templates (defined in _helpers.tpl) keeps templates DRY and maintainable.

yaml
# templates/_helpers.tpl
{{- define "my-application.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

{{- define "my-application.labels" -}}
helm.sh/chart: {{ include "my-application.chart" . }}
app.kubernetes.io/name: {{ include "my-application.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

Helper templates standardize naming conventions and labels across all resources, ensuring consistency with Kubernetes recommended labels.

Helm Chart Dependencies and Subcharts

Complex applications often depend on databases, caches, or message queues. Helm dependencies allow embedding these as subcharts, managed automatically during installation.

bash
# Update dependencies before packaging
helm dependency update ./my-application

# Build dependencies (creates charts/ directory)
helm dependency build ./my-application

The helm dependency update command downloads dependencies to the charts/ directory. Conditional dependencies use values to toggle inclusion:

yaml
# values.yaml
postgresql:
  enabled: true

redis:
  enabled: false
yaml
# Chart.yaml
dependencies:
  - name: postgresql
    version: "15.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled
  - name: redis
    version: "19.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: redis.enabled

This pattern enables environment-specific configurations where production uses managed services while development uses in-cluster databases.

OCI Registry Support

Helm 3.8+ supports storing charts in OCI-compliant registries like Docker Hub, GitHub Container Registry, and AWS ECR. Push charts with helm push my-app-1.0.0.tgz oci://registry.example.com/charts.

Deploying Helm Charts with Release Management

Helm tracks deployments as releases, enabling versioned rollbacks and upgrades. Each release maintains history for auditing and recovery.

bash
# Install a chart with custom values
helm install my-release ./my-application \
  --namespace production \
  --create-namespace \
  --values production-values.yaml \
  --set image.tag=2.1.1

# Upgrade an existing release
helm upgrade my-release ./my-application \
  --namespace production \
  --values production-values.yaml \
  --set image.tag=2.2.0 \
  --atomic \
  --timeout 5m

The --atomic flag ensures failed upgrades automatically rollback. The --timeout flag sets how long Helm waits for resources to become ready before declaring failure.

bash
# View release history
helm history my-release -n production

# Rollback to previous revision
helm rollback my-release 2 -n production

# Uninstall a release
helm uninstall my-release -n production --keep-history

The --keep-history flag preserves release records even after uninstallation, useful for compliance and debugging.

Ready to ace your DevOps interviews?

Practice with our interactive simulators, flashcards, and technical tests.

Helm Chart Testing and Validation Strategies

Testing Helm charts before deployment catches template errors and configuration issues early. Helm provides built-in tools for linting and dry-run testing.

bash
# Lint chart for errors and best practices
helm lint ./my-application

# Render templates locally without deploying
helm template my-release ./my-application \
  --values production-values.yaml \
  > rendered-manifests.yaml

# Dry-run against cluster API
helm install my-release ./my-application \
  --dry-run \
  --debug \
  --namespace production

The helm template command renders manifests locally, useful for CI pipelines that validate generated YAML. The --dry-run flag sends manifests to the Kubernetes API server for validation without creating resources.

yaml
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "{{ include "my-application.fullname" . }}-test"
  labels:
    {{- include "my-application.labels" . | nindent 4 }}
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: curl
      image: curlimages/curl:8.7.1
      command: ['curl']
      args: ['{{ include "my-application.fullname" . }}:{{ .Values.service.port }}/health']
  restartPolicy: Never

Helm hooks with helm.sh/hook: test run after helm test my-release, validating deployments work correctly post-installation.

Advanced Helm Templating Techniques

Production charts require conditional logic, loops, and data transformation. Sprig functions extend Go templates with utilities for string manipulation, encoding, and flow control.

yaml
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "my-application.fullname" . }}-config
data:
  {{- range $key, $value := .Values.config }}
  {{ $key }}: {{ $value | quote }}
  {{- end }}
  
  {{- if .Values.features.enabled }}
  FEATURE_FLAGS: {{ .Values.features.flags | join "," | quote }}
  {{- end }}
yaml
# templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: {{ include "my-application.fullname" . }}-secrets
type: Opaque
data:
  {{- range $key, $value := .Values.secrets }}
  {{ $key }}: {{ $value | b64enc }}
  {{- end }}

The range function iterates over maps and lists. The b64enc function base64-encodes values for Kubernetes secrets. Pipe operators chain functions for data transformation.

Secret Management

Storing secrets in values.yaml exposes them in version control. Use external secret managers like HashiCorp Vault, AWS Secrets Manager with External Secrets Operator, or SOPS-encrypted values files for production deployments.

Helm Charts Interview Questions and Answers

Technical interviews frequently test Helm knowledge through conceptual and practical questions. The following covers the most commonly asked topics.

What is the difference between helm install and helm upgrade --install?

helm install creates a new release and fails if the release already exists. helm upgrade --install (with the --install flag) creates a new release if one doesn't exist, or upgrades it if it does. CI/CD pipelines typically use helm upgrade --install for idempotent deployments.

How do you pass sensitive data to Helm charts?

Three approaches exist: external secret managers (Vault, AWS Secrets Manager), encrypted values files (SOPS, sealed-secrets), or Kubernetes secrets created outside Helm and referenced in templates. Avoid storing secrets in plain-text values.yaml files committed to version control.

What are Helm hooks and when should you use them?

Hooks execute at specific points in release lifecycle: pre-install, post-install, pre-upgrade, post-upgrade, pre-delete, post-delete, pre-rollback, post-rollback, and test. Common uses include database migrations before upgrades, sending notifications after deployments, or running integration tests.

How do you handle chart versioning?

The version field in Chart.yaml tracks chart changes using semantic versioning. The appVersion field tracks the deployed application version. Increment version for any chart modification, even if the application version stays the same.

What is the purpose of .helmignore?

Similar to .gitignore, .helmignore excludes files from chart packaging. Typical entries include *.tgz (avoid packaging previous builds), .git/, *.md documentation not needed at runtime, and CI configuration files.

For more Kubernetes interview preparation, explore the Kubernetes Basics and Kubernetes Advanced question modules on SharpSkill.

Conclusion

Practical takeaways for working with Helm charts:

  • Structure charts with clear separation between Chart.yaml metadata, values.yaml defaults, and templates directory containing Kubernetes manifests
  • Use helper templates in _helpers.tpl to standardize naming and labels across all resources
  • Manage dependencies through Chart.yaml with conditional enablement for environment-specific configurations
  • Test charts with helm lint, helm template, and helm install --dry-run before deploying to production
  • Track releases with meaningful names and use --atomic flag for automatic rollback on failed upgrades
  • Store secrets in external managers rather than plain-text values files

Start practicing!

Test your knowledge with our interview simulators and technical tests.

Tags

#kubernetes
#helm
#devops
#deployment
#interview

Share

Related articles