Docker & Kubernetes

Como Usar Helm Fundamentos: Charts, Values, Templates e Releases em Produção

17 min de leitura

Como Usar Helm Fundamentos: Charts, Values, Templates e Releases em Produção

Helm Fundamentos: Charts, Values, Templates e Releases Helm é o gerenciador de pacotes do Kubernetes, frequentemente comparado ao apt, yum ou npm, mas para orquestrações containerizadas. Se você está aqui, provavelmente já conhece a dor de escrever centenas de linhas de YAML para cada deployment no Kubernetes — Helm resolve isso de forma elegante e reutilizável. Neste artigo, vamos explorar os quatro pilares do Helm: Charts (como os pacotes são organizados), Values (como parametrizamos comportamentos), Templates (como geramos YAMLs dinamicamente) e Releases (como instalamos e atualizamos na prática). A proposta do Helm é simples: evitar duplicação, aumentar consistência entre ambientes e permitir que você compartilhe aplicações Kubernetes de forma encapsulada. Você verá que esses quatro conceitos não são isolados — eles trabalham juntos em um ecossistema coeso e bem pensado. Charts: Estrutura e Anatomia Um Chart no Helm é um pacote que contém tudo o que você precisa para rodar uma aplicação no Kubernetes. Pense nele como um diretório estruturado

<h2>Helm Fundamentos: Charts, Values, Templates e Releases</h2>

<p>Helm é o gerenciador de pacotes do Kubernetes, frequentemente comparado ao apt, yum ou npm, mas para orquestrações containerizadas. Se você está aqui, provavelmente já conhece a dor de escrever centenas de linhas de YAML para cada deployment no Kubernetes — Helm resolve isso de forma elegante e reutilizável. Neste artigo, vamos explorar os quatro pilares do Helm: Charts (como os pacotes são organizados), Values (como parametrizamos comportamentos), Templates (como geramos YAMLs dinamicamente) e Releases (como instalamos e atualizamos na prática).</p>

<p>A proposta do Helm é simples: evitar duplicação, aumentar consistência entre ambientes e permitir que você compartilhe aplicações Kubernetes de forma encapsulada. Você verá que esses quatro conceitos não são isolados — eles trabalham juntos em um ecossistema coeso e bem pensado.</p>

<h2>1. Charts: Estrutura e Anatomia</h2>

<p>Um Chart no Helm é um pacote que contém tudo o que você precisa para rodar uma aplicação no Kubernetes. Pense nele como um diretório estruturado que segue convenções específicas, similar a um repositório npm ou um pacote Python, mas orientado ao Kubernetes.</p>

<h3>Estrutura de um Chart</h3>

<p>Quando você cria um Chart com <code>helm create minha-aplicacao</code>, você obtém a seguinte estrutura:</p>

<pre><code>minha-aplicacao/

├── Chart.yaml # Metadados do Chart (nome, versão, descrição)

├── values.yaml # Valores padrão (configurações)

├── charts/ # Dependências (outros Charts)

├── templates/ # Arquivos de template (YAML + Helm)

│ ├── deployment.yaml

│ ├── service.yaml

│ ├── configmap.yaml

│ ├── _helpers.tpl # Templates auxiliares reutilizáveis

│ └── NOTES.txt # Instruções pós-instalação

├── README.md # Documentação do Chart

├── .helmignore # Arquivos ignorados (como .gitignore)

└── values-*.yaml # Valores específicos de ambientes (opcional)</code></pre>

<p>O arquivo <code>Chart.yaml</code> é o coração do Chart. Ele define metadados essenciais:</p>

<pre><code class="language-yaml">apiVersion: v2 # Versão da API do Helm (v2 é moderna)

name: minha-aplicacao # Nome único do Chart

description: Minha aplicação # Descrição breve

type: application # application ou library

version: 1.0.0 # Versão do Chart

appVersion: &quot;2.4.1&quot; # Versão da aplicação dentro do Chart

keywords:

  • web
  • api

home: https://github.com/user/repo

sources:

  • https://github.com/user/repo

maintainers:

  • name: João Silva

email: joao@example.com</code></pre>

<p>Um Chart bem estruturado é autossuficiente. Ele não apenas encapsula a aplicação, mas também documenta como usá-la, permitindo que qualquer pessoa instale sua aplicação com um único comando: <code>helm install release-name ./minha-aplicacao</code>.</p>

<h2>2. Values: Parametrizando Comportamentos</h2>

<p>Values (valores) são o mecanismo pelo qual você torna um Chart flexível. Ao invés de codificar imagens Docker, réplicas ou limites de recursos diretamente nos templates YAML, você os coloca no arquivo <code>values.yaml</code> como variáveis que podem ser sobrescritas.</p>

<h3>Estrutura e Hierarquia de Values</h3>

<p>O arquivo <code>values.yaml</code> é um arquivo YAML contendo valores padrão para sua aplicação. Quando você instala um Chart, o Helm mescla esse arquivo com valores fornecidos via CLI ou arquivos adicionais:</p>

<pre><code class="language-yaml"># values.yaml - Arquivo padrão do Chart

replicaCount: 3

image:

repository: minha-aplicacao

pullPolicy: IfNotPresent

tag: &quot;2.4.1&quot;

service:

type: ClusterIP

port: 80

targetPort: 8080

resources:

limits:

cpu: 500m

memory: 512Mi

requests:

cpu: 250m

memory: 256Mi

ingress:

enabled: true

className: nginx

hosts:

  • host: app.example.com

paths:

  • path: /

pathType: Prefix

tls:

  • secretName: app-tls

hosts:

  • app.example.com

autoscaling:

enabled: false

minReplicas: 1

maxReplicas: 10

targetCPUUtilizationPercentage: 80</code></pre>

<p>A beleza dos Values está na <strong>sobrescrita em camadas</strong>. Você pode fornecer valores em múltiplos níveis:</p>

<ol>

<li><strong>Padrão</strong>: <code>values.yaml</code> do Chart</li>

<li><strong>CLI</strong>: via flag <code>-f arquivo.yaml</code> ou <code>--set chave=valor</code></li>

<li><strong>Ambiente</strong>: usando arquivos como <code>values-prod.yaml</code>, <code>values-dev.yaml</code></li>

</ol>

<p>Exemplo de uso prático:</p>

<pre><code class="language-bash"># Usar valores padrão

helm install minha-release ./minha-aplicacao

Sobrescrever via CLI

helm install minha-release ./minha-aplicacao \

--set replicaCount=5 \

--set image.tag=3.0.0

Usar arquivo de valores customizado

helm install minha-release ./minha-aplicacao \

-f values-producao.yaml

Combinar múltiplos arquivos (último sobrescreve anterior)

helm install minha-release ./minha-aplicacao \

-f values.yaml \

-f values-prod.yaml \

--set replicaCount=10</code></pre>

<p>A hierarquia é importante: valores fornecidos via <code>--set</code> sobrescrevem tudo; valores de <code>-f</code> sobrescrevem padrões; e padrões são usados como base.</p>

<h2>3. Templates: Gerando YAML Dinamicamente</h2>

<p>Templates são onde a mágica acontece. Eles são arquivos YAML enriquecidos com lógica de template (usando Go templating, o mesmo do Docker Compose). O Helm processa esses templates, substituindo placeholders por valores reais, e gera YAML válido para o Kubernetes.</p>

<h3>Sintaxe Básica de Templates</h3>

<p>Um template Helm usa a sintaxe <code>{{ }}</code> para inserir variáveis e lógica. Aqui está um exemplo de um <code>deployment.yaml</code> típico:</p>

<pre><code class="language-yaml"># templates/deployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: {{ include &quot;minha-aplicacao.fullname&quot; . }}

labels:

{{- include &quot;minha-aplicacao.labels&quot; . | nindent 4 }}

spec:

{{- if not .Values.autoscaling.enabled }}

replicas: {{ .Values.replicaCount }}

{{- end }}

selector:

matchLabels:

{{- include &quot;minha-aplicacao.selectorLabels&quot; . | nindent 6 }}

template:

metadata:

labels:

{{- include &quot;minha-aplicacao.selectorLabels&quot; . | nindent 8 }}

spec:

serviceAccountName: {{ include &quot;minha-aplicacao.serviceAccountName&quot; . }}

securityContext:

{{- toYaml .Values.podSecurityContext | nindent 8 }}

containers:

  • name: {{ .Chart.Name }}

securityContext:

{{- toYaml .Values.securityContext | nindent 12 }} image: &quot;{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}&quot;

imagePullPolicy: {{ .Values.image.pullPolicy }}

ports:

  • name: http

containerPort: {{ .Values.service.targetPort }}

protocol: TCP

livenessProbe:

httpGet:

path: /healthz

port: http

initialDelaySeconds: 30

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: http

initialDelaySeconds: 5

periodSeconds: 5

resources:

{{- toYaml .Values.resources | nindent 12 }}

env:

  • name: ENVIRONMENT

value: {{ .Values.environment | quote }}

  • name: LOG_LEVEL

value: {{ .Values.logLevel | quote }}</code></pre>

<p>Vamos decompor os elementos principais:</p>

<p><strong>1. Variáveis simples:</strong></p>

<pre><code class="language-yaml">replicas: {{ .Values.replicaCount }} # Substitui pelo valor de replicaCount

image: {{ .Values.image.repository }} # Acessa valores aninhados</code></pre>

<p><strong>2. Funções e pipes:</strong></p>

<pre><code class="language-yaml">image: &quot;{{ .Values.image.tag | default .Chart.AppVersion }}&quot;

Usa .Values.image.tag, ou .Chart.AppVersion se vazio (função default)

labels: {{- include &quot;minha-aplicacao.labels&quot; . | nindent 4 }}

Inclui um template auxiliar (_helpers.tpl) e indenta o resultado</code></pre>

<p><strong>3. Lógica condicional:</strong></p>

<pre><code class="language-yaml">{{- if not .Values.autoscaling.enabled }}

replicas: {{ .Values.replicaCount }}

{{- end }}

Só inclui a linha se autoscaling NÃO estiver ativado</code></pre>

<p><strong>4. Loops:</strong></p>

<pre><code class="language-yaml">env:

{{- range $key, $value := .Values.env }}

  • name: {{ $key }}

value: {{ $value | quote }}

{{- end }}

Itera sobre um mapa de variáveis de ambiente</code></pre>

<h3>Templates Auxiliares (_helpers.tpl)</h3>

<p>O arquivo <code>_helpers.tpl</code> contém macros reutilizáveis. Evita duplicação e garante consistência:</p>

<pre><code class="language-tpl">{{/*

Expandir o nome do Chart.

*/}}

{{- define &quot;minha-aplicacao.name&quot; -}}

{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix &quot;-&quot; }}

{{- end }}

{{/*

Criar um nome totalmente qualificado para a aplicação.

*/}}

{{- define &quot;minha-aplicacao.fullname&quot; -}}

{{- if .Values.fullnameOverride }}

{{- .Values.fullnameOverride | trunc 63 | trimSuffix &quot;-&quot; }}

{{- else }}

{{- $name := default .Chart.Name .Values.nameOverride }}

{{- if contains $name .Release.Name }}

{{- .Release.Name | trunc 63 | trimSuffix &quot;-&quot; }}

{{- else }}

{{- printf &quot;%s-%s&quot; .Release.Name $name | trunc 63 | trimSuffix &quot;-&quot; }}

{{- end }}

{{- end }}

{{- end }}

{{/*

Labels comuns

*/}}

{{- define &quot;minha-aplicacao.labels&quot; -}}

helm.sh/chart: {{ include &quot;minha-aplicacao.chart&quot; . }}

{{ include &quot;minha-aplicacao.selectorLabels&quot; . }}

{{- if .Chart.AppVersion }}

app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}

{{- end }}

app.kubernetes.io/managed-by: {{ .Release.Service }}

{{- end }}

{{/*

Seletor de labels

*/}}

{{- define &quot;minha-aplicacao.selectorLabels&quot; -}}

app.kubernetes.io/name: {{ include &quot;minha-aplicacao.name&quot; . }}

app.kubernetes.io/instance: {{ .Release.Name }}

{{- end }}</code></pre>

<p>Essas macros garantem que nomes, labels e metadados sejam consistentes em todos os manifestos.</p>

<h3>Renderização em Tempo Real</h3>

<p>Para validar seus templates <strong>antes</strong> de instalar, use:</p>

<pre><code class="language-bash"># Ver o YAML gerado sem instalar

helm template minha-release ./minha-aplicacao

Com valores customizados

helm template minha-release ./minha-aplicacao \

-f values-prod.yaml \

--set replicaCount=5

Salvar em arquivo para revisão

helm template minha-release ./minha-aplicacao &gt; manifesto.yaml

cat manifesto.yaml</code></pre>

<p>Isso é crucial para debugging — você vê exatamente qual YAML será aplicado.</p>

<h2>4. Releases: Instalação e Gerenciamento</h2>

<p>Um Release é uma instância de um Chart rodando no seu cluster Kubernetes. Se um Chart é como um pacote (similar a um .deb no apt), uma Release é como um programa instalado no seu computador. Você pode ter múltiplas Releases do mesmo Chart com configurações diferentes.</p>

<h3>Ciclo de Vida de uma Release</h3>

<pre><code class="language-bash"># 1. Instalar uma Release

helm install minha-release ./minha-aplicacao

Resultado: Release &quot;minha-release&quot; instalada no namespace default

2. Listar Releases

helm list # Todas as Releases em todos namespaces

helm list -n producao # Apenas no namespace &#039;producao&#039;

helm list --all-namespaces # Mais explícito

3. Ver status e detalhes

helm status minha-release # Status atual

helm get values minha-release # Valores usados nesta Release

helm get manifest minha-release # YAML gerado e instalado

helm get notes minha-release # Notas pós-instalação (NOTES.txt)

4. Atualizar uma Release

helm upgrade minha-release ./minha-aplicacao \

--set replicaCount=5

Resultará em um novo revision

5. Histórico de mudanças

helm history minha-release # Todas as revisões

helm history minha-release -o yaml # Em formato YAML

6. Reverter para versão anterior

helm rollback minha-release 1 # Volta à revisão 1

helm rollback minha-release # Volta à revisão anterior

7. Desinstalar

helm uninstall minha-release # Remove toda a Release</code></pre>

<h3>Exemplo Prático: Fluxo Completo</h3>

<p>Vamos simular um fluxo real:</p>

<pre><code class="language-bash"># 1. Criar um Chart básico

helm create meu-site

2. Customizar values.yaml para nossa aplicação

cat &gt; meu-site/values.yaml &lt;&lt;EOF

replicaCount: 2

image:

repository: nginx

tag: &quot;1.21.0&quot;

pullPolicy: IfNotPresent

service:

type: LoadBalancer

port: 80

targetPort: 80

resources:

requests:

cpu: 100m

memory: 128Mi

limits:

cpu: 200m

memory: 256Mi

EOF

3. Validar o Chart

helm lint meu-site

Output: ==&gt; Linting meu-site

1 chart(s) linted, 0 chart(s) failed

4. Ver o YAML antes de instalar

helm template meu-site ./meu-site --set replicaCount=3

5. Instalar no cluster

helm install website meu-site \

--namespace producao \

--create-namespace \

-f meu-site/values.yaml

6. Verificar a instalação

helm list -n producao

helm status website -n producao

kubectl get pods -n producao

7. Fazer upgrade para nova versão

helm upgrade website meu-site \

--namespace producao \

--set image.tag=1.22.0

8. Ver histórico

helm history website -n producao

9. Se algo der errado, reverter

helm rollback website -n producao

helm status website -n producao

10. Desinstalar quando não precisar mais

helm uninstall website -n producao</code></pre>

<h3>Namespaces e Isolamento</h3>

<p>Releases podem ser instaladas em diferentes namespaces, permitindo isolamento perfeito:</p>

<pre><code class="language-bash"># Instalar a mesma aplicação em múltiplos ambientes

helm install app-dev meu-site -n desenvolvimento

helm install app-prod meu-site -n producao --set replicaCount=5

Cada uma é independente

helm list -n desenvolvimento

helm list -n producao

Upgrades isolados por namespace

helm upgrade app-dev meu-site -n desenvolvimento --set image.tag=2.0.0

helm upgrade app-prod meu-site -n producao --set image.tag=2.0.0

Ambas continuam rodando independentemente</code></pre>

<h3>Estratégia de Versionamento</h3>

<p>Para manter Releases estáveis, mantenha uma estratégia clara:</p>

<pre><code class="language-bash"># Use tags semânticas

helm install app-v1.0.0 meu-site --set version=1.0.0

Para upgrades menores, use upgrade

helm upgrade app-v1.0.0 meu-site --set version=1.1.0

Para mudanças maiores, considere release novo

helm install app-v2.0.0 meu-site --set version=2.0.0

Manter ambas rodando em paralelo é possível

helm list # Mostra app-v1.0.0 e app-v2.0.0</code></pre>

<h2>Integrando Tudo: Um Exemplo Real</h2>

<p>Vamos colocar todos os conceitos em prática com uma aplicação real simples (uma API Python):</p>

<p><strong>Chart.yaml:</strong></p>

<pre><code class="language-yaml">apiVersion: v2

name: api-python

description: Uma API Python com FastAPI

type: application

version: 1.0.0

appVersion: &quot;0.1.0&quot;</code></pre>

<p><strong>values.yaml:</strong></p>

<pre><code class="language-yaml">replicaCount: 3

image:

repository: meu-registo.azurecr.io/api-python

pullPolicy: IfNotPresent

tag: &quot;0.1.0&quot;

service:

type: ClusterIP

port: 80

targetPort: 8000

ingress:

enabled: true

className: nginx

hosts:

  • host: api.exemplo.com

paths:

  • path: /

pathType: Prefix

resources:

requests:

cpu: 250m

memory: 256Mi

limits:

cpu: 500m

memory: 512Mi

env:

DEBUG: &quot;false&quot;

LOG_LEVEL: &quot;info&quot;

DATABASE_URL: &quot;postgresql://user:pass@postgres:5432/db&quot;</code></pre>

<p><strong>templates/deployment.yaml:</strong></p>

<pre><code class="language-yaml">apiVersion: apps/v1

kind: Deployment

metadata:

name: {{ include &quot;api-python.fullname&quot; . }}

labels:

{{- include &quot;api-python.labels&quot; . | nindent 4 }}

spec:

replicas: {{ .Values.replicaCount }}

selector:

matchLabels:

{{- include &quot;api-python.selectorLabels&quot; . | nindent 6 }}

template:

metadata:

labels:

{{- include &quot;api-python.selectorLabels&quot; . | nindent 8 }}

spec:

containers:

  • name: {{ .Chart.Name }}

image: &quot;{{ .Values.image.repository }}:{{ .Values.image.tag }}&quot;

imagePullPolicy: {{ .Values.image.pullPolicy }}

ports:

  • name: http

containerPort: {{ .Values.service.targetPort }}

livenessProbe:

httpGet:

path: /health

port: http

initialDelaySeconds: 30

periodSeconds: 10

readinessProbe:

httpGet:

path: /ready

port: http

initialDelaySeconds: 5

periodSeconds: 5

resources:

{{- toYaml .Values.resources | nindent 12 }}

env:

{{- range $key, $value := .Values.env }}

  • name: {{ $key }}

value: {{ $value | quote }}

{{- end }}</code></pre>

<p><strong>Instalação e uso:</strong></p>

<pre><code class="language-bash"># Desenvolvimento (poucos recursos, debug ativado)

helm install api-dev ./api-python \

--namespace dev \

--create-namespace \

--set replicaCount=1 \

--set env.DEBUG=true \

--set env.LOG_LEVEL=debug \

--set resources.requests.cpu=100m

Produção (muitos recursos, debug desativado)

helm install api-prod ./api-python \

--namespace prod \

--create-namespace \

--set replicaCount=5 \

--set ingress.hosts[0].host=api.producao.com \

--set resources.limits.cpu=1000m \

--set resources.limits.memory=1Gi

Upgrade em produção

helm upgrade api-prod ./api-python \

--namespace prod \

--set image.tag=0.2.0 \

--set replicaCount=10</code></pre>

<h2>Conclusão</h2>

<p>Helm não é apenas um gerenciador de pacotes — é um framework para abstrair a complexidade do Kubernetes mantendo flexibilidade. Você aprendeu que:</p>

<ol>

<li><strong>Charts são pacotes reutilizáveis</strong> que encapsulam toda a configuração de uma aplicação em Kubernetes, seguindo uma estrutura padrão (Chart.yaml, values.yaml, templates/). Eles permitem compartilhar aplicações de forma versionada e documentada.</li>

</ol>

<ol>

<li><strong>Values são o mecanismo de parametrização</strong> que torna Charts adaptáveis a diferentes ambientes sem modificar templates. A combinação de arquivo padrão, sobrescrita via arquivo e CLI oferece flexibilidade máxima para seus deployments.</li>

</ol>

<ol>

<li><strong>Templates geram YAML dinamicamente</strong> usando Go templating, transformando valores em manifestos Kubernetes válidos. Funcionalidades como condicionais, loops, funções e templates auxiliares evitam duplicação e garantem consistência.</li>

</ol>

<ol>

<li><strong>Releases são instâncias de Charts instaladas</strong> no seu cluster, com histórico completo de versões e capacidade de rollback. Você pode rodar múltiplas releases do mesmo Chart com diferentes configurações, oferecendo isolamento perfeito entre ambientes.</li>

</ol>

<h2>Referências</h2>

<ul>

<li><a href="https://helm.sh/docs/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Helm</a></li>

<li><a href="https://helm.sh/docs/chart_best_practices/" target="_blank" rel="noopener noreferrer">Helm Chart Best Practices</a></li>

<li><a href="https://pkg.go.dev/text/template" target="_blank" rel="noopener noreferrer">Go Template Language Reference</a></li>

<li><a href="https://kubernetes.io/docs/" target="_blank" rel="noopener noreferrer">Kubernetes Official Documentation</a></li>

<li><a href="https://artifacthub.io/" target="_blank" rel="noopener noreferrer">Helm Hub - Repository de Charts Públicos</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Docker & Kubernetes

O que Todo Dev Deve Saber sobre Ingress em Kubernetes: Nginx Ingress Controller e Roteamento de Tráfego
O que Todo Dev Deve Saber sobre Ingress em Kubernetes: Nginx Ingress Controller e Roteamento de Tráfego

O que é Ingress no Kubernetes Ingress é um objeto de API do Kubernetes que ge...

O que Todo Dev Deve Saber sobre Volumes em Docker: bind mounts, named volumes e tmpfs Comparados
O que Todo Dev Deve Saber sobre Volumes em Docker: bind mounts, named volumes e tmpfs Comparados

O Problema: Persistência de Dados em Containers Quando você cria um container...

Guia Completo de CIS Benchmark para Kubernetes: Hardening e Auditoria de Cluster
Guia Completo de CIS Benchmark para Kubernetes: Hardening e Auditoria de Cluster

O que é CIS Benchmark para Kubernetes O CIS Benchmark (Center for Internet Se...