So far we have applied manifests by hand. It works for learning, but it doesn’t scale: each environment becomes a copy with invisible differences, and no one knows which version is running.
Helm solves the problem of packaging and versioning the deployment. It’s not magic — it’s template + values + a release registry.
Course seal: tested on Kubernetes 1.35 with Helm 3.
The real problem
Without Helm, three environments usually become three folders:
k8s/
homolog/deployment.yaml
prod/deployment.yaml
staging/deployment.yaml
Differences: image, replicas, resources, variables. One day someone fixes only in prod and the rest stays wrong. It’s the beginning of drift.
With Helm:
chart/
Chart.yaml
values.yaml
values-homolog.yaml
values-prod.yaml
templates/
deployment.yaml
service.yaml
ingress.yaml
_helpers.tpl
One template, three sets of values.
Minimal structure
Chart.yaml:
apiVersion: v2
name: portal
description: Portal Nyverra
type: application
version: 1.4.0
appVersion: "v5"
version: version of the chart.appVersion: version of the application (image).
They are different things. Mix them up and you lose traceability.
Templates and values
values.yaml (defaults):
replicaCount: 2
image:
repository: ghcr.io/example/portal-backend
tag: v5
pullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 512Mi
env:
LOG_LEVEL: info
templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "portal.fullname" . }}
labels:
{{- include "portal.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "portal.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "portal.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: backend
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- range $k, $v := .Values.env }}
- name: {{ $k }}
value: {{ $v | quote }}
{{- end }}
_helpers.tpl centralizes names and labels. Without it, each template invents a different name and kubectl get becomes archaeology.
Values per environment
values-prod.yaml:
replicaCount: 4
image:
tag: v5
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 1Gi
Render without applying:
helm template portal ./chart -f values-prod.yaml
helm template portal ./chart -f values-prod.yaml --show-only templates/deployment.yaml
Always review the render before install. It’s Helm’s --dry-run.
Install, upgrade, rollback
helm upgrade --install portal ./chart -n portal --create-namespace -f values-prod.yaml
helm list -n portal
helm status portal -n portal
helm history portal -n portal
helm rollback portal 3 -n portal
Helm stores releases as Secrets in the namespace (sh.helm.release.v1.portal.v1). Don’t delete them by hand.
Hooks
Hooks run at moments of the cycle:
pre-install/pre-upgrade: database migrations.post-install/post-upgrade: smoke test.pre-delete: cleanup.
metadata:
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation
Careful: a migration hook runs before the rollout. If the new code version depends on the migration, that’s fine. If the migration breaks the old version, you have an error window.
What not to put in the chart
- Real secrets in
values.yaml(use External Secrets or a secret manager). - Registry credentials in plain text.
- Configuration that changes per cluster and should be GitOps (chapter 22).
Lab
- Create the chart:
helm create portal
rm -rf portal/templates/tests
- Adjust
values.yaml,_helpers.tpl, and the templates. - Render and compare environments:
helm template portal ./portal -f values-homolog.yaml > /tmp/homolog.yaml
helm template portal ./portal -f values-prod.yaml > /tmp/prod.yaml
diff /tmp/homolog.yaml /tmp/prod.yaml
- Install in homolog and upgrade with
--atomic:
helm upgrade --install portal ./portal -n portal --create-namespace \
-f values-homolog.yaml --atomic --timeout 5m
- Force a failure (nonexistent image) and observe
--atomicrevert by itself. - Manual
helm rollbackand checkhelm history.
Common errors
| Symptom | Cause |
|---|---|
rendered manifests contain a resource that already exists |
resource created outside Helm |
Upgrade stuck in pending-upgrade |
hook/rollout failed without timeout |
| Ignored values | -f in wrong order or typo in key |
nil pointer evaluating interface |
missing key in values |
| Silent drift | resource edited by hand after install |
| Rollback doesn't revert image | appVersion diverging from tag |
| Secret leaked to Git | sensitive value in values.yaml |
Checklist
- [ ]
Chart.yamlwith coherentversionandappVersion. - [ ]
_helpers.tplfor names and labels. - [ ]
values-<env>.yamlper environment. - [ ]
helm templatereviewed before upgrade. - [ ]
--atomicand--timeouton upgrade. - [ ] Resources (requests/limits) coming from values.
- [ ] No plain-text secrets in the chart.
- [ ]
helm historyand rollback tested.
Glossary
- chart: Helm package.
- release: instance of a chart in the cluster.
- values: template parameters.
- hook: resource executed at a phase of the cycle.
- atomic: automatically reverts on failure.
- drift: difference between what is declared and what runs.
Next
Chart packaged. Now who applies the chart to the cluster? In the next chapter, GitOps with ArgoCD: Git as the source of truth and the cluster self-correcting.
Keep reading
Read also

StorCLI - Complete Cheat Sheet
StorCLI is the official and modern tool for managing Broadcom/LSI RAID controllers. This guide covers essential commands, syntax and use cases.
12 min de leitura
TutoriaisBusiness Services in Nyverra Portal: Translating IT into Business
The business doesn't feel a server go down — it feels email stop. The Business Services (Service Mapping) module of Nyverra ITSM Portal connects services like Email, ERP or PACS to CMDB assets, revealing the real impact of each failure.
5 min de leitura
SegurançaRPO vs RTO: How to Define Before Buying Backup (and Why Most Companies Get It Wrong)
Most companies buy backup asking the wrong question: "how much does it cost?". The right question is: how much data can I lose (RPO) and how long can I be down (RTO). Discover how to define these numbers per system and avoid purchasing protection based on price, not on real need.
9 min de leitura
Comments
No comments yet
Be the first to share your thoughts on this article.

Leave a comment