Helm is a package manager for Kubernetes. It is an open-source container orchestration system. It helps you manage Kubernetes applications by providing an easy way to define, install, and upgrade complex Kubernetes applications.
Using Helm, you can package your application into a "chart," which is a bundle of files that describes your application. You can then use Helm to install and manage your application on a Kubernetes cluster. Helm makes it easy to automate the installation and management of complex applications, and it provides a number of features that make it a powerful tool for managing Kubernetes applications.
Some of the benefits of using Helm include:
- Simplifies the process of installing and managing complex Kubernetes applications.
- Makes it easy to automate the deployment and management of applications.
- Allows you to version control your application configurations.
- Provides a way to share applications with others through public or private chart repositories.
- Makes it easy to roll back to a previous version of an application if necessary.
Overall, Helm is a useful tool for managing and deploying applications on Kubernetes, and it can help you streamline the process of managing complex applications on a Kubernetes cluster.
Why Docker is supporting Helm Chart?
Docker Hub is the popular hosted repository service provided by Docker for finding and sharing container images with your team. It is a repository of container images used to store and distribute container images — or artifacts usable by container runtimes. This became a limitation of our platform since container image distribution is just the starting point of the application delivery process.
Modern apps today support numerous artifacts such as WebAssembly modules, OPA Bundles, Helm charts, SBOMs and custom artifacts. Hence, it became essential for the Docker Hub team to accommodate and support all these artifacts so that developers can share these with clients that need them since they add immense value to their projects. Last October 2022, Docker announced that Docker Hub can now help you distribute any type of application artifacts! You can now keep everything in one place without having to leverage multiple registries.
In this blog, you will see how Docker Hub can store Helm charts flawlessly.
1. Create a Helm chart
The best way to get started with a new chart is to use the helm create command to scaffold out an example we can build on. Use this command to create a new chart named collabnix in a new directory:
helm create collabnix
2. Viewing the Chart
Helm will create a new directory in your project called collabnix
with the structure shown below. Let's navigate our new chart to find out how it works.
demo % tree
.
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
3 directories, 10 files
The most important piece of the file structure is the templates/
directory. This is where Helm finds the YAML definitions for your Services
, Deployments
and other Kubernetes objects. If you already have definitions for your application, all you need to do is replace the generated YAML files with your own. What you end up with is a working chart that can be deployed using the helm install command.
Open the service.yaml
file to see what this looks like:
apiVersion: v1
kind: Service
metadata:
name: {{ include "collabnix.fullname" . }}
labels:
{{- include "collabnix.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "collabnix.selectorLabels" . | nindent 4 }}
This is a basic Service definition using templating. When deploying the chart, Helm will generate a definition that will look a lot more like a valid Service. We can do a dry-run of a helm install and enable debug to inspect the generated definitions.
Please ensure that you run the below command outside the Helm directory.
helm install collabnix --dry-run --debug ./collabnix
install.go:192: [debug] Original chart version: ""
install.go:209: [debug] CHART PATH: /Users/ajeetraina/dec/collabnix
NAME: collabnix
LAST DEPLOYED: Thu Dec 8 11:02:54 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
affinity: {}
autoscaling:
enabled: false
maxReplicas: 100
minReplicas: 1
targetCPUUtilizationPercentage: 80
fullnameOverride: ""
image:
pullPolicy: IfNotPresent
repository: nginx
tag: ""
imagePullSecrets: []
ingress:
annotations: {}
className: ""
enabled: false
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
nameOverride: ""
nodeSelector: {}
podAnnotations: {}
podSecurityContext: {}
replicaCount: 1
resources: {}
securityContext: {}
service:
port: 80
type: ClusterIP
serviceAccount:
annotations: {}
create: true
name: ""
tolerations: []
HOOKS:
---
# Source: collabnix/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "collabnix-test-connection"
labels:
helm.sh/chart: collabnix-0.1.0
app.kubernetes.io/name: collabnix
app.kubernetes.io/instance: collabnix
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['collabnix:80']
restartPolicy: Never
MANIFEST:
---
# Source: collabnix/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: collabnix
labels:
helm.sh/chart: collabnix-0.1.0
app.kubernetes.io/name: collabnix
app.kubernetes.io/instance: collabnix
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
---
# Source: collabnix/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: collabnix
labels:
helm.sh/chart: collabnix-0.1.0
app.kubernetes.io/name: collabnix
app.kubernetes.io/instance: collabnix
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: collabnix
app.kubernetes.io/instance: collabnix
---
# Source: collabnix/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: collabnix
labels:
helm.sh/chart: collabnix-0.1.0
app.kubernetes.io/name: collabnix
app.kubernetes.io/instance: collabnix
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: collabnix
app.kubernetes.io/instance: collabnix
template:
metadata:
labels:
app.kubernetes.io/name: collabnix
app.kubernetes.io/instance: collabnix
spec:
serviceAccountName: collabnix
securityContext:
{}
containers:
- name: collabnix
securityContext:
{}
image: "nginx:1.16.0"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{}
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=collabnix,app.kubernetes.io/instance=collabnix" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT
4. Changing the default value for service.internalPort
If you execute another dry-run, you should find that the targetPort in the Service and the containerPort in the Deployment changes.
helm install collabnix --dry-run --debug ./collabnix --set service.internalPort=8080
5. Exposing it externally
By default, the chart will create a ClusterIP-type Service, so NGINX will only be exposed internally in the cluster. To access it externally, we'll use the NodePort type instead. We can also set the name of the Helm release so we can easily refer back to it. Let's go ahead and deploy our NGINX chart using the helm install command:
helm install example ./collabnix --set service.type=NodePort
6. Packaging the Helm Chart
Once we’re done editing, we’ll need to package the Helm chart as an OCI image:
helm package collabnix
Successfully packaged chart and saved it to: /Users/ajeetraina/dec/collabnix-0.1.0.tgz
7. Login to Docker Hub
docker login
Authenticating with existing credentials...
Login Succeeded
Logging in with your password grants your terminal complete access to your account.
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/
8. Pushing it to Docker Hub
helm push collabnix-0.1.0.tgz oci://registry-1.docker.io/ajeetraina
Error: server message: insufficient_scope: authorization failed
You might encounter the error message.
Fix: We recommend creating a Personal Access Token (PAT) for this.
You can export your PAT via an environment variable, and login, as follows:
echo $REG_PAT | helm registry login registry-1.docker.io -u ajeetraina --password-stdin
Login Succeeded
Now you should be able to push it to Docker Hub
helm push collabnix-0.1.0.tgz oci://registry-1.docker.io/ajeetraina
Pushed: registry-1.docker.io/ajeetraina/collabnix:0.1.0
Digest: sha256:b3efd72f8044772a461b6ee51eb89b1f1635239378be9752c688ebd58d7dc9ec
Conclusion
Storing your Helm Charts in Docker Hub enables improved collaboration through Docker Hub’s standard sharing capabilities. Developers can now build Helm chart locally by using the search capabilities of Docker Desktop and then push it flawlessly to the Docker Hub.