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

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

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.

1. 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 que segue convenções específicas, similar a um repositório npm ou um pacote Python, mas orientado ao Kubernetes.

Estrutura de um Chart

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

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)

O arquivo Chart.yaml é o coração do Chart. Ele define metadados essenciais:

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: "2.4.1"               # 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

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: helm install release-name ./minha-aplicacao.

2. Values: Parametrizando Comportamentos

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 values.yaml como variáveis que podem ser sobrescritas.

Estrutura e Hierarquia de Values

O arquivo values.yaml é 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:

# values.yaml - Arquivo padrão do Chart
replicaCount: 3

image:
  repository: minha-aplicacao
  pullPolicy: IfNotPresent
  tag: "2.4.1"

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

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

  1. Padrão: values.yaml do Chart
  2. CLI: via flag -f arquivo.yaml ou --set chave=valor
  3. Ambiente: usando arquivos como values-prod.yaml, values-dev.yaml

Exemplo de uso prático:

# 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

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

3. Templates: Gerando YAML Dinamicamente

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.

Sintaxe Básica de Templates

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

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "minha-aplicacao.fullname" . }}
  labels:
    {{- include "minha-aplicacao.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "minha-aplicacao.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "minha-aplicacao.selectorLabels" . | nindent 8 }}
    spec:
      serviceAccountName: {{ include "minha-aplicacao.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
      - name: {{ .Chart.Name }}
        securityContext:
          {{- toYaml .Values.securityContext | nindent 12 }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        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 }}

Vamos decompor os elementos principais:

1. Variáveis simples:

replicas: {{ .Values.replicaCount }}      # Substitui pelo valor de replicaCount
image: {{ .Values.image.repository }}     # Acessa valores aninhados

2. Funções e pipes:

image: "{{ .Values.image.tag | default .Chart.AppVersion }}"
# Usa .Values.image.tag, ou .Chart.AppVersion se vazio (função default)

labels: {{- include "minha-aplicacao.labels" . | nindent 4 }}
# Inclui um template auxiliar (_helpers.tpl) e indenta o resultado

3. Lógica condicional:

{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
# Só inclui a linha se autoscaling NÃO estiver ativado

4. Loops:

env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
  value: {{ $value | quote }}
{{- end }}
# Itera sobre um mapa de variáveis de ambiente

Templates Auxiliares (_helpers.tpl)

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

{{/*
Expandir o nome do Chart.
*/}}
{{- define "minha-aplicacao.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Criar um nome totalmente qualificado para a aplicação.
*/}}
{{- define "minha-aplicacao.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Labels comuns
*/}}
{{- define "minha-aplicacao.labels" -}}
helm.sh/chart: {{ include "minha-aplicacao.chart" . }}
{{ include "minha-aplicacao.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Seletor de labels
*/}}
{{- define "minha-aplicacao.selectorLabels" -}}
app.kubernetes.io/name: {{ include "minha-aplicacao.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

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

Renderização em Tempo Real

Para validar seus templates antes de instalar, use:

# 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 > manifesto.yaml
cat manifesto.yaml

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

4. Releases: Instalação e Gerenciamento

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.

Ciclo de Vida de uma Release

# 1. Instalar uma Release
helm install minha-release ./minha-aplicacao
# Resultado: Release "minha-release" instalada no namespace default

# 2. Listar Releases
helm list                           # Todas as Releases em todos namespaces
helm list -n producao               # Apenas no namespace 'producao'
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

Exemplo Prático: Fluxo Completo

Vamos simular um fluxo real:

# 1. Criar um Chart básico
helm create meu-site

# 2. Customizar values.yaml para nossa aplicação
cat > meu-site/values.yaml <<EOF
replicaCount: 2

image:
  repository: nginx
  tag: "1.21.0"
  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: ==> 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

Namespaces e Isolamento

Releases podem ser instaladas em diferentes namespaces, permitindo isolamento perfeito:

# 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

Estratégia de Versionamento

Para manter Releases estáveis, mantenha uma estratégia clara:

# 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

Integrando Tudo: Um Exemplo Real

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

Chart.yaml:

apiVersion: v2
name: api-python
description: Uma API Python com FastAPI
type: application
version: 1.0.0
appVersion: "0.1.0"

values.yaml:

replicaCount: 3

image:
  repository: meu-registo.azurecr.io/api-python
  pullPolicy: IfNotPresent
  tag: "0.1.0"

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: "false"
  LOG_LEVEL: "info"
  DATABASE_URL: "postgresql://user:pass@postgres:5432/db"

templates/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "api-python.fullname" . }}
  labels:
    {{- include "api-python.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "api-python.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "api-python.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        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 }}

Instalação e uso:

# 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

Conclusão

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

  1. Charts são pacotes reutilizáveis 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.

  2. Values são o mecanismo de parametrização 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.

  3. Templates geram YAML dinamicamente 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.

  4. Releases são instâncias de Charts instaladas 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.

Referências


Artigos relacionados