Helm is a powerful package manager for Kubernetes, analogous to apt for Debian-based systems or yum for Red Hat-based systems. It streamlines the deployment and management of applications on Kubernetes by packaging Kubernetes resources into reusable, configurable units called charts. Helm simplifies complex Kubernetes operations, enhances productivity, and fosters best practices in deploying applications.
Key Concepts in Helm
- Helm Chart: A Helm chart is a collection of files that describe a related set of Kubernetes resources. Charts contain all the necessary configuration to deploy an application, tool, or service inside a Kubernetes cluster.
- Chart Repository: A chart repository is a place where charts can be collected and shared. Helm uses repositories to distribute charts to users.
- Release: A release is a running instance of a chart, combined with configuration values. Each installation of a chart results in a unique release name.
- Values: Helm allows customization of charts through values. Values are parameters set by users to modify the behavior and configuration of the chart during deployment.
- Templates: Charts use Go templating to enable dynamic configuration of Kubernetes manifests based on the provided values.
- Helm CLI: The command-line interface used to interact with Helm, manage charts, repositories, and releases.
Helm Architecture
Helm consists of two main components:
- Helm Client: The CLI tool used by developers to create, manage, and deploy charts.
- Helm Repository: A storage for charts, often hosted on HTTP servers, cloud storage, or other accessible platforms.
In Helm 3, the server-side component called Tiller (present in Helm 2) was removed, simplifying security and architecture by having Helm interact directly with the Kubernetes API.
Installing and Setting Up Helm
Prerequisites
- A Kubernetes cluster (local like Minikube, or cloud-based like GKE, EKS, AKS)
- kubectl configured to communicate with your cluster
- Helm installed on your local machine
Installation Steps
Install Helm CLI:
# For macOS using Homebrew
brew install helm
# For Windows using Chocolatey
choco install kubernetes-helm
# For Linux
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
Initialize Helm:
Helm 3 does not require initialization steps like Helm 2 did (no Tiller setup).
Add a Chart Repository:
By default, Helm adds the official stable repository.
helm repo add stable https://charts.helm.sh/stable
helm repo update
Helm Charts in Detail
Anatomy of a Helm Chart
A typical Helm chart has the following directory structure:
mychart/
Chart.yaml # Metadata about the chart
values.yaml # Default configuration values
charts/ # Dependencies
templates/ # Kubernetes resource templates
README.md # Documentation
LICENSE # License information
Chart.yaml: Contains information such as the chart name, version, description, and dependencies.
apiVersion: v2
name: mychart
description: A Helm chart for Kubernetes
version: 0.1.0
appVersion: "1.16.0"
values.yaml: Defines default values for the chart's templates, allowing users to override them during deployment.
replicaCount: 3
image:
repository: nginx
tag: stable
service:
type: ClusterIP
port: 80
templates/: Contains Kubernetes manifest templates with placeholders for dynamic values.
Example deployment.yaml template:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
labels:
app: {{ include "mychart.name" . }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "mychart.name" . }}
template:
metadata:
labels:
app: {{ include "mychart.name" . }}
spec:
containers:
– name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
– containerPort: {{ .Values.service.port }}
- charts/: Optional directory for chart dependencies. Helm can manage dependencies using requirements.yaml or Chart.yaml in Helm 3.
Creating a Helm Chart
Create a New Chart:
helm create mychart
This command scaffolds a new chart with the standard directory structure and example templates.
Customize Templates and Values:
Modify values.yaml and templates in the templates/ directory to fit your application's requirements.
Package the Chart:
helm package mychart
This command creates a .tgz package that can be shared or stored in a repository.
Publish the Chart:
Upload the packaged chart to a chart repository or a storage service accessible to your deployment environment.
Using Helm: Common Commands and Workflows
Installing a Chart
To install a chart from a repository:
helm install my-release stable/nginx
- my-release is the name of the release.
- stable/nginx specifies the chart from the stable repository.
Customizing Installation with Values
Override default values using the –values (-f) flag or –set flag:
# Using a custom values file
helm install my-release stable/nginx -f custom-values.yaml
# Using the –set flag for individual values
helm install my-release stable/nginx –set replicaCount=5
Listing Releases
helm list
Upgrading a Release
To upgrade a release with new chart version or updated values:
helm upgrade my-release stable/nginx –set image.tag=1.17.0
Rolling Back a Release
If an upgrade causes issues, roll back to the previous release:
helm rollback my-release 1
Here, 1 is the revision number to roll back to.
Uninstalling a Release
helm uninstall my-release
Searching for Charts
helm search repo nginx
Adding and Removing Repositories
# Add a repository
helm repo add bitnami https://charts.bitnami.com/bitnami
# Remove a repository
helm repo remove bitnami
Advanced Helm Features
Dependencies Management
Helm charts can declare dependencies on other charts, allowing modular and reusable configurations.
Defining Dependencies: In Chart.yaml or requirements.yaml (Helm 3 uses Chart.yaml).
dependencies:
– name: redis
version: "14.8.8"
repository: "https://charts.bitnami.com/bitnami"
Updating Dependencies:
helm dependency update mychart
Chart Hooks
Hooks allow charts to perform actions at certain points in the release lifecycle, such as pre-install, post-install, pre-upgrade, etc.
Example of a hook in a template:
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-pre-install"
annotations:
"helm.sh/hook": pre-install
spec:
template:
spec:
containers:
– name: pre-install
image: busybox
command: ['sh', '-c', 'echo Pre-install hook']
restartPolicy: Never
Helm Tests
Helm allows defining tests for your releases to validate deployments.
Defining a Test:
Create a test pod with the annotation helm.sh/hook: test.
apiVersion: v1
kind: Pod
metadata:
name: "{{ .Release.Name }}-test"
annotations:
"helm.sh/hook": test
spec:
containers:
– name: test
image: busybox
command: ['sh', '-c', 'echo Test successful']
restartPolicy: Never
Running Tests:
helm test my-release
Helm Plugins
Helm supports plugins to extend its functionality. Examples include:
- Helm Diff: Shows a diff of what changes an upgrade would make.
- Helm Secrets: Manages secrets within Helm charts.
- Helm S3: Uses Amazon S3 as a chart repository.
Examples and Scenarios
Example 1: Deploying NGINX Using Helm
Scenario: Quickly deploy a web server for testing purposes.
Steps:
Add the Official Helm Repository:
helm repo add stable https://charts.helm.sh/stable
helm repo update
Install the NGINX Chart:
helm install my-nginx stable/nginx-ingress
Verify Installation:
kubectl get pods -l app.kubernetes.io/name=nginx-ingress
Accessing the NGINX Service:
Depending on the Kubernetes environment, access via LoadBalancer IP or NodePort.
Customizing Configuration:
helm upgrade my-nginx stable/nginx-ingress –set controller.replicaCount=2
Outcome: A scalable NGINX Ingress controller is deployed with two replicas, ensuring high availability.
Example 2: Creating a Custom Helm Chart for a Microservice
Scenario: Deploy a custom microservice with specific configurations.
Steps:
Create a New Chart:
helm create my-microservice
Customize values.yaml:
replicaCount: 2
image:
repository: myregistry/my-microservice
tag: "v1.0.0"
service:
type: ClusterIP
port: 8080
env:
– name: ENVIRONMENT
value: production
Modify Templates:
Update deployment.yaml to include environment variables:
env:
{{- range .Values.env }}
– name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
Package and Deploy:
helm package my-microservice
helm install my-microservice-release ./my-microservice-0.1.0.tgz
Managing Upgrades:
Update the image tag and upgrade:
helm upgrade my-microservice-release ./my-microservice-0.1.1.tgz –set image.tag="v1.0.1"
Outcome: A custom microservice is deployed with versioned releases, environment-specific configurations, and easy upgrade paths.
Example 3: Managing Complex Applications with Dependencies
Scenario: Deploy a WordPress site with a MySQL database, leveraging Helm dependencies.
Steps:
Create a Parent Chart:
helm create wordpress
Define Dependencies in Chart.yaml:
dependencies:
– name: mysql
version: "8.5.1"
repository: "https://charts.bitnami.com/bitnami"
– name: wordpress
version: "10.1.0"
repository: "https://charts.bitnami.com/bitnami"
Update Dependencies:
helm dependency update wordpress
Customize Values:
In values.yaml, configure MySQL and WordPress settings.
mysql:
auth:
rootPassword: "rootpassword"
database: "wordpressdb"
username: "wpuser"
password: "wppassword"
wordpress:
wordpressUsername: "admin"
wordpressPassword: "adminpassword"
wordpressEmail: "admin@example.com"
wordpressBlogName: "My Blog"
Install the Parent Chart:
helm install my-wordpress ./wordpress
Verify Deployment:
kubectl get pods -l app.kubernetes.io/instance=my-wordpress
Outcome: A WordPress site is deployed with an embedded MySQL database, managed as a single Helm release with dependencies handled automatically.
Example 4: Integrating Helm with CI/CD Pipelines
Scenario: Automate Helm chart deployments using a CI/CD tool like Jenkins, GitLab CI, or GitHub Actions.
Steps:
Store Helm Charts in Version Control:
Keep chart definitions and values.yaml files in a Git repository.
Define CI/CD Pipeline:
Example using GitHub Actions:
name: Helm Deploy
on:
push:
branches:
– main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
– name: Checkout Code
uses: actions/checkout@v2
– name: Set up Helm
uses: azure/setup-helm@v1
with:
version: '3.8.0'
– name: Helm Lint
run: helm lint ./mychart
– name: Helm Upgrade
env:
KUBECONFIG: ${{ secrets.KUBECONFIG }}
run: helm upgrade –install my-release ./mychart –values ./mychart/values.yaml
- Secure Kubernetes Credentials:
Store KUBECONFIG or necessary credentials securely in the CI/CD tool's secrets management. - Trigger Deployment on Code Changes:
When changes are pushed to the main branch, the pipeline lints the chart and performs an upgrade or install.
Outcome: Continuous deployment of Helm charts ensures that application updates are automatically deployed to Kubernetes upon code changes, maintaining consistency and reducing manual intervention.
Best Practices for Using Helm
- Version Control Charts: Keep Helm charts in version control systems (e.g., Git) to track changes and facilitate collaboration.
- Semantic Versioning: Use semantic versioning for chart versions to manage dependencies and upgrades effectively.
- Parameterize Configurations: Leverage values.yaml and templates to make charts flexible and reusable across different environments.
- Secure Sensitive Data: Avoid storing sensitive information in values.yaml. Use tools like Helm Secrets or integrate with Kubernetes secrets management solutions.
- Modularize with Dependencies: Break down complex applications into smaller, manageable charts with dependencies, enhancing maintainability.
- Lint and Test Charts: Use helm lint and Helm tests to validate charts before deployment, ensuring reliability.
- Document Charts: Provide comprehensive README.md files and inline documentation to help users understand chart usage and configurations.
- Use Chart Repositories Wisely: Host internal chart repositories for proprietary applications while leveraging public repositories for common services.
Advanced Scenarios
Scenario 1: Blue-Green Deployments with Helm
Objective: Minimize downtime and mitigate risks during deployments by using blue-green strategies.
Approach:
Create Separate Releases:
Deploy two identical environments (blue and green) using separate Helm releases.
helm install myapp-blue ./myapp-chart
helm install myapp-green ./myapp-chart
Switch Traffic:
Use a load balancer or Ingress controller to route traffic to the active release.
# Example Ingress switching between blue and green services
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
rules:
– host: myapp.example.com
http:
paths:
– path: /
pathType: Prefix
backend:
service:
name: myapp-green
port:
number: 80
Deploy Updates to Inactive Release:
Update the non-active release (e.g., green) with the new version.
helm upgrade myapp-green ./myapp-chart –set image.tag=new-version
Switch Traffic to Updated Release:
Update the Ingress to point to myapp-green.
Monitor and Rollback if Necessary:
Ensure the new release is functioning correctly. If issues arise, revert traffic to myapp-blue.
Outcome: Seamless transitions between application versions with minimal downtime and easy rollback capabilities.
Scenario 2: Multi-Tenant Deployments with Helm
Objective: Deploy applications for multiple tenants with isolated configurations using Helm.
Approach:
Use Values Files for Each Tenant:
Create separate values-tenant1.yaml, values-tenant2.yaml, etc., containing tenant-specific configurations.
Deploy Separate Releases:
Install the chart multiple times with different release names and values.
helm install tenant1-release ./myapp-chart -f values-tenant1.yaml
helm install tenant2-release ./myapp-chart -f values-tenant2.yaml
Isolate Resources:
Utilize Kubernetes namespaces to isolate tenant resources.
kubectl create namespace tenant1
kubectl create namespace tenant2
helm install tenant1-release ./myapp-chart -f values-tenant1.yaml –namespace tenant1
helm install tenant2-release ./myapp-chart -f values-tenant2.yaml –namespace tenant2
Manage Tenant Upgrades Independently:
Each release can be upgraded, rolled back, or configured separately without affecting others.
Outcome: Efficiently manage multi-tenant applications with isolated environments, ensuring security and customization per tenant.
Scenario 3: Hybrid Deployments with Helm
Objective: Manage deployments across multiple Kubernetes clusters using Helm.
Approach:
Configure Helm for Multiple Clusters:
Set up kubectl contexts for each cluster.
kubectl config get-contexts
kubectl config use-context cluster1
Deploy to Each Cluster:
Use Helm to install or upgrade releases in different contexts.
# Deploy to cluster1
kubectl config use-context cluster1
helm install release-cluster1 ./mychart -f values-cluster1.yaml
# Deploy to cluster2
kubectl config use-context cluster2
helm install release-cluster2 ./mychart -f values-cluster2.yaml
Automate with Scripts or CI/CD:
Create scripts or pipeline steps that switch contexts and perform Helm operations for each cluster.
Outcome: Streamlined management of applications across multiple Kubernetes environments, supporting hybrid cloud or multi-cloud strategies.
Scenario 4: Helm in GitOps Workflows
Objective: Implement GitOps principles by managing Helm releases through Git repositories.
Approach:
Store Helm Charts and Configurations in Git:
Maintain Helm charts and their values.yaml files in a Git repository.
Use GitOps Tools:
Integrate with tools like Argo CD or Flux that monitor Git repositories and reconcile Kubernetes clusters accordingly.
Automate Deployments:
When changes are pushed to the Git repository, the GitOps tool automatically applies Helm releases to the cluster.
Example with Argo CD:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp-helm-charts
targetRevision: main
path: mychart
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
Track Changes and Rollbacks:
Use Git history to track changes and enable rollbacks by reverting commits.
Outcome: Enhanced visibility, auditability, and reliability in deployments through Git-centric management of Helm releases.
Helm Best Practices and Tips
- Keep Charts DRY (Don't Repeat Yourself):
Use templates and helper functions to minimize repetition within your charts. - Use Semantic Versioning:
Align chart versions with semantic versioning to manage compatibility and dependencies effectively. - Leverage Helm Hooks Judiciously:
Utilize hooks for necessary lifecycle events but avoid overusing them to prevent complexity. - Secure Sensitive Data:
Integrate with Kubernetes Secrets or external secret management systems instead of embedding sensitive data in charts. - Test Charts Thoroughly:
Use Helm's built-in testing framework and CI pipelines to ensure charts behave as expected before deployment. - Modularize Large Applications:
Break down monolithic charts into smaller, manageable sub-charts with clear dependencies. - Document Your Charts:
Provide comprehensive documentation within the chart repository to assist users in deployment and customization. - Use Values Files for Environment Configurations:
Maintain separate values files for different environments (e.g., development, staging, production) to manage configurations efficiently. - Validate Charts:
Regularly use helm lint and other validation tools to catch errors early in the development process. - Monitor Helm Releases:
Implement monitoring and alerting for Helm releases to detect and respond to deployment issues promptly.
Conclusion
Helm significantly enhances the Kubernetes ecosystem by providing a standardized, efficient, and scalable way to manage application deployments. Its chart-based architecture simplifies complex configurations, promotes reuse, and integrates seamlessly with CI/CD pipelines and GitOps workflows. By leveraging Helm's capabilities and adhering to best practices, organizations can achieve consistent, reliable, and maintainable deployments across diverse Kubernetes environments.
Whether deploying simple services or managing intricate, multi-component applications, Helm serves as an indispensable tool for Kubernetes operators and developers alike, fostering agility and operational excellence in cloud-native deployments.