Monday, May 11, 2026

Kubernetes and Helm Chart Applications

A Helm chart is a packaging format for Kubernetes, acting as a blueprint to define, install, and upgrade complex applications. It bundles multiple YAML manifest files (templates) into a single unit, managed via Helm to enable easy versioning, sharing, and configuration reuse across environments.

 Helm must be installed into your system. Below is the official script how to install it into your system.

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

 dpasek@k0s1:~$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash   
  % Total  % Received % Xferd Average Speed Time  Time  Time  Current  
                  Dload Upload Total  Spent  Left  Speed  
  0   0  0   0  0   0   0   0               100 11929 100 11929  0   0 43973   0               100 11929 100 11929  0   0 43953   0               100 11929 100 11929  0   0 43950   0               0  
 Downloading https://get.helm.sh/helm-v3.20.2-linux-arm64.tar.gz  
 Verifying checksum... Done.  
 Preparing to install helm into /usr/local/bin  
 helm installed into /usr/local/bin/helm  
 dpasek@k0s1:~$   

Now we can create our own simple Helm Charts and deploy it into 3-node Kubernetes cluster in consolidated architecture I have for playing with K8s. Let's host several applications (service) in our 3-node K8s cluster and observe how it behaves. 

Application Hello

The first application is called HelloRun following commands to create hello-nginx directory with all necessary content ...
 
cd
mkdir -p hello-nginx/templates
cd hello-nginx 
 

cat > Chart.yaml <<EOF
apiVersion: v2
name: hello-nginx
description: Simple Hello World NGINX demo app
type: application
version: 0.1.0
appVersion: "1.0"
EOF

cat > values.yaml <<EOF
replicaCount: 2

image:
  repository: nginxdemos/hello
  tag: latest
  pullPolicy: IfNotPresent

service:
  type: NodePort
  port: 80
EOF

cat > templates/deployment.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-hello-nginx
  labels:
    app: {{ .Release.Name }}-hello-nginx
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}-hello-nginx
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-hello-nginx
    spec:
      containers:
      - name: hello-nginx
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: 80
EOF

cat > templates/service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-hello-nginx
spec:
  type: {{ .Values.service.type }}
  selector:
    app: {{ .Release.Name }}-hello-nginx
  ports:
  - port: {{ .Values.service.port }}
    targetPort: 80
    protocol: TCP
EOF

Now we can install application hello having all artifacts in directory ./hello-nginx  

helm install hello ./hello-nginx

 dpasek@k0s1:~$ helm install hello ./hello-nginx  
 NAME: hello  
 LAST DEPLOYED: Mon May 11 11:34:34 2026  
 NAMESPACE: default  
 STATUS: deployed  
 REVISION: 1  
 TEST SUITE: None  
 dpasek@k0s1:~$   

The hello app is deployed.

Application Echo

The second application is called EchoRun following commands to create echo-hashicorp directory with all necessary content ...
 
cd
mkdir -p echo-hashicorp/templates
cd echo-hashicorp 
 

cat > Chart.yaml <<EOF
apiVersion: v2
name: echo-hashicorp
description: Simple Hashicorp HTTP Echo demo app
type: application
version: 0.1.0
appVersion: "1.0"
EOF

cat > values.yaml <<EOF
replicaCount: 3

image:
  repository: hashicorp/http-echo
  tag: latest
  pullPolicy: IfNotPresent

service:
  type: NodePort
  port: 80
EOF

cat > templates/deployment.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-http-echo
-hashicorp
  labels:
    app: {{ .Release.Name }}-http-echo
-hashicorp
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}-http-echo-hashicorp
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-
http-echo-hashicorp
    spec:
      containers:
      - name: 
http-echo-hashicorp
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: 80
EOF

cat > templates/service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-
http-echo-hashicorp
spec:
  type: {{ .Values.service.type }}
  selector:
    app: {{ .Release.Name }}-
http-echo-hashicorp
  ports:
  - port: {{ .Values.service.port }}
    targetPort: 80
    protocol: TCP
EOF

Now we can install application Echo having all artifacts in directory ./echo-hashicorp  

helm install echo ./echo-hashicorp

 dpasek@k0s1:~$ helm install echo ./echo-hashicorp  
 NAME: echo  
 LAST DEPLOYED: Mon May 11 14:27:18 2026  
 NAMESPACE: default  
 STATUS: deployed  
 REVISION: 1  
 TEST SUITE: None  
 dpasek@k0s1:~$   

Working with Kubectl

Two apps (Hello and Echo) are deployed on K8s cluster. Bellow are visible deployed theirs K8s pods across cluster nodes.

 dpasek@k0s1:~$ kubectl get pods -o wide  
 NAME                                      READY  STATUS     RESTARTS  AGE    IP           NODE  NOMINATED NODE  READINESS GATES  
 echo-http-echo-hashicorp-88b9f786c-7m62j  1/1    Running    0         9m58s  10.244.1.14  k0s2  <none>          <none>  
 echo-http-echo-hashicorp-88b9f786c-jf5w2  1/1    Running    0         9m58s  10.244.1.16  k0s2  <none>          <none>  
 echo-http-echo-hashicorp-88b9f786c-wtmfs  1/1    Running    0         9m58s  10.244.1.15  k0s2  <none>          <none>  
 hello-hello-nginx-55ff8f7fb9-h524n        1/1    Running    0         3h2m   10.244.1.12  k0s2  <none>          <none>  
 hello-hello-nginx-55ff8f7fb9-l82gw        0/1    Completed  0         3h2m   10.244.0.25  k0s1  <none>          <none>  
 hello-hello-nginx-55ff8f7fb9-qcgxq        1/1    Running    0         83m    10.244.1.13  k0s2  <none>          <none>  
 dpasek@k0s1:~$   

The most useful K8s command is ... kubectl getl all ... because you can see all pods, services, deployments, and replicasets.

 dpasek@k0s2:~$ kubectl get all  
 NAME                                          READY  STATUS    RESTARTS  AGE  
 pod/echo-http-echo-hashicorp-88b9f786c-7m62j  1/1   Running    0         20m  
 pod/echo-http-echo-hashicorp-88b9f786c-jf5w2  1/1   Running    0         20m  
 pod/echo-http-echo-hashicorp-88b9f786c-wtmfs  1/1   Running    0         20m  
 pod/hello-hello-nginx-55ff8f7fb9-h524n        1/1   Running    0         3h13m  
 pod/hello-hello-nginx-55ff8f7fb9-l82gw        0/1   Completed  0         3h13m  
 pod/hello-hello-nginx-55ff8f7fb9-qcgxq        1/1   Running    0         94m  
 NAME                              TYPE        CLUSTER-IP     EXTERNAL-IP  PORT(S)       AGE  
 service/echo-http-echo-hashicorp  NodePort    10.99.203.238  <none>       80:32677/TCP  20m  
 service/hello-hello-nginx         NodePort    10.110.90.212  <none>       80:31785/TCP  3h13m  
 service/kubernetes                ClusterIP   10.96.0.1      <none>       443/TCP       45h  
 NAME                                      READY  UP-TO-DATE  AVAILABLE  AGE  
 deployment.apps/echo-http-echo-hashicorp  3/3    3           3          20m  
 deployment.apps/hello-hello-nginx         2/2    2           2          3h13m  
 NAME                                                DESIRED  CURRENT  READY  AGE  
 replicaset.apps/echo-http-echo-hashicorp-88b9f786c  3        3        3      20m  
 replicaset.apps/hello-hello-nginx-55ff8f7fb9        2        2        2      3h13m  
 dpasek@k0s2:~$  

Recommended Kubectl Beginner Operational Commands

kubectl get pods
kubectl get all
kubectl logs -f <pod>
kubectl describe pod <pod>
kubectl exec -it <pod> -- sh
kubectl rollout restart deployment <deploy>
kubectl scale deployment <deploy> --replicas=3

Working with Helm

Operational procedures for Helm are usually described similarly to traditional enterprise application runbooks. The important difference is that helm procedures operate application releases,
not individual servers or VMs.

Recommended Helm Beginner Operational Commands 

helm list
helm status <release>
helm upgrade <release> <chart>
helm rollback <release> <revision>
helm uninstall <release>

Helm install

In my small K8s lab I have my two helm charts stored on a home directory in single server (k0s1). This is not production ready, but good enough to test K8s behavior. Helm Repository Cache is enterprise ready solution, but too heavy for home lab. Anyway, let's do a testing with my local Helm Charts.

We already installed these two application charts - hello and echo. You can find procedures above in this blog post.   

Helm list

We can list already installed applications.

 dpasek@k0s1:~$ helm list  
 NAME      NAMESPACE    REVISION     UPDATED                                     STATUS       CHART                APP VERSION  
 echo      default      1            2026-05-11 14:27:18.497102365 +0000 UTC     deployed     hi-nginx-0.1.0       1.0      
 hello     default      1            2026-05-11 11:34:34.046517773 +0000 UTC     deployed     hello-nginx-0.1.0    1.0      
 dpasek@k0s1:~$   

Helm status

We can check the status of these two applications. 

 dpasek@k0s3:/var/log$ helm status hello  
 NAME: hello  
 LAST DEPLOYED: Mon May 11 11:34:34 2026  
 NAMESPACE: default  
 STATUS: deployed  
 REVISION: 1  
 TEST SUITE: None  
 dpasek@k0s3:/var/log$  

Helm uninstall

Of course, you can uninstall the application.

Helm get manifest

Helm get is another useful command. Especially get manifest. It can show the full application manifest.\

 dpasek@k0s1:~$ helm get manifest echo  
 ---  
 # Source: echo-hashicorp/templates/service.yaml  
 apiVersion: v1  
 kind: Service  
 metadata:  
  name: echo-http-echo-hashicorp  
 spec:  
  type: NodePort  
  selector:  
   app: echo-http-echo-hashicorp  
  ports:  
  - port: 80  
   targetPort: 80  
   protocol: TCP  
 ---  
 # Source: echo-hashicorp/templates/deployment.yaml  
 apiVersion: apps/v1  
 kind: Deployment  
 metadata:  
  name: echo-http-echo-hashicorp  
  labels:  
   app: echo-http-echo-hashicorp  
 spec:  
  replicas: 3  
  selector:  
   matchLabels:  
    app: echo-http-echo-hashicorp  
  template:  
   metadata:  
    labels:  
     app: echo-http-echo-hashicorp  
   spec:  
    containers:  
    - name: http-echo-hashicorp  
     image: "hashicorp/http-echo:latest"  
     imagePullPolicy: IfNotPresent  
     ports:  
     - containerPort: 80  
 dpasek@k0s1:~$   

See full manifest is pretty useful during troubleshooting. 

Conclusion

Most Important Kubernetes Operational Concept in Kubernetes is that Pods are cattle, not pets.

Meaning:

  • Pods are disposable
  • Kubernetes recreates them automatically
  • you usually operate Deployments/Helm releases
  • not individual Pods

That is one of the biggest mindset shifts from traditional VM operations.

In this article we deployed two applications - Hello (2 replicas) and Echo (3 replicas). These applications run as K8s Pods in K0s K8s distribution.

Hope someone find this insightful.

 

 

No comments:

Post a Comment

Kubernetes and Helm Chart Applications

A Helm chart is a packaging format for Kubernetes, acting as a blueprint to define, install, and upgrade complex applications. It bundles m...