Skip to content
beginner Phase 10 · Helm and Kubernetes Packaging

Chart Structure

Create and organize Helm charts with Chart.yaml, templates directory, values.yaml, and helpers template file.

55m
0 problems
Topic Progress 0%

Helm Basics

Helm Basics

What is Helm?

Helm is the package manager for Kubernetes. It simplifies defining, installing, and upgrading Kubernetes applications.

Chart:      Package of Kubernetes manifests
Release:    Running instance of a chart
Repository: Collection of charts
Values:     Configuration passed to templates

Helm Commands

# Install Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Add repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

# Search charts
helm search repo nginx
helm search hub prometheus

# Install chart
helm install my-release bitnami/nginx
helm install my-release bitnami/nginx -n production --create-namespace

# Install with values
helm install my-release bitnami/nginx -f values.yaml
helm install my-release bitnami/nginx --set replicaCount=3 --set service.type=ClusterIP

# Upgrade release
helm upgrade my-release bitnami/nginx -f values.yaml
helm upgrade --install my-release bitnami/nginx    # Install or upgrade

# Rollback
helm rollback my-release 1    # Rollback to revision 1

# Uninstall
helm uninstall my-release

# List releases
helm list -A
helm list -n production

# Release history
helm history my-release

# Show chart info
helm show chart bitnami/nginx
helm show values bitnami/nginx
helm show readme bitnami/nginx

# Lint chart
helm lint ./mychart

# Package chart
helm package ./mychart

# Template rendering (debug)
helm template my-release ./mychart -f values.yaml

Creating Charts

Creating Charts

Chart Structure

# Create a new chart
helm create mychart

# Structure:
mychart/
├── Chart.yaml           # Chart metadata
├── values.yaml          # Default values
├── charts/              # Dependency charts
├── templates/           # Template files
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── hpa.yaml
│   ├── serviceaccount.yaml
│   ├── _helpers.tpl     # Template helpers
│   └── tests/
│       └── test-connection.yaml
├── .helmignore
└── README.md

Chart.yaml

apiVersion: v2
name: myapp
description: My application Helm chart
type: application
version: 0.1.0          # Chart version
appVersion: "1.0.0"     # Application version
keywords:
  - web
  - api
maintainers:
  - name: John Doe
    email: john@example.com
dependencies:
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

values.yaml

replicaCount: 2

image:
  repository: myapp
  pullPolicy: IfNotPresent
  tag: ""

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

ingress:
  enabled: true
  className: nginx
  hosts:
    - host: api.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: api-tls
      hosts:
        - api.example.com

resources:
  requests:
    memory: 256Mi
    cpu: 250m
  limits:
    memory: 512Mi
    cpu: 1000m

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

postgresql:
  enabled: true
  auth:
    database: myapp
    username: myapp

Template Files

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

# templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "myapp.fullname" . }}
spec:
  type: {{ .Values.service.type }}
  ports:
  - port: {{ .Values.service.port }}
    targetPort: {{ .Values.service.targetPort }}
  selector:
    {{- include "myapp.selectorLabels" . | nindent 4 }}

# templates/_helpers.tpl
{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

{{- define "myapp.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
{{- end }}

{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

Helm Hooks and Conditions

Helm Hooks and Conditions

Helm Hooks

# Pre-install hook (runs before install)
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-db-migrate
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "0"    # Execution order
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      containers:
      - name: migrate
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        command: ["./migrate.sh"]
      restartPolicy: Never
  backoffLimit: 1

# Post-install hook
apiVersion: v1
kind: Pod
metadata:
  name: {{ include "myapp.fullname" . }}-verify
  annotations:
    "helm.sh/hook": post-install,post-upgrade
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  containers:
  - name: verify
    image: curlimages/curl
    command: ['curl', '-f', 'http://{{ include "myapp.fullname" . }}:{{ .Values.service.port }}/health']
  restartPolicy: Never

# Hook weights (lower runs first)
# hook-weight: "-1" runs before "0" runs before "1"

# Hook delete policies:
# before-hook-creation  - Delete previous hook before creating new one
# hook-succeeded        - Delete hook after successful completion
# hook-failed           - Delete hook after failure

Conditions

# templates/ingress.yaml (only create if ingress.enabled)
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "myapp.fullname" . }}
spec:
  {{- if .Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ .path }}
            pathType: {{ .pathType }}
            backend:
              service:
                name: {{ include "myapp.fullname" $ }}
                port:
                  number: {{ $.Values.service.port }}
          {{- end }}
    {{- end }}
{{- end }}

# templates/hpa.yaml
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
  minReplicas: {{ .Values.autoscaling.minReplicas }}
  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}