Criando seu próprio Helm chart

1. Introdução ao Helm e sua importância no ecossistema DevOps

Helm é o gerenciador de pacotes oficial do Kubernetes, funcionando como um "apt-get" ou "yum" para clusters. No contexto DevOps, ele resolve um problema crítico: a complexidade de gerenciar múltiplos arquivos YAML para cada aplicação. Com Helm, você empacota todos os recursos Kubernetes (Deployments, Services, ConfigMaps, etc.) em um único chart versionável.

Os conceitos fundamentais são:
- Chart: pacote contendo templates e configurações
- Release: instância de um chart em execução no cluster
- Repository: local onde charts são armazenados e versionados
- Values: arquivo central de configuração que torna o chart parametrizável

Criar seu próprio Helm chart traz benefícios diretos: reutilização entre projetos, versionamento semântico de infraestrutura, padronização de deploys e facilidade para rollbacks.

2. Estrutura de um Helm chart do zero

Vamos criar um chart para uma aplicação web simples. Primeiro, a estrutura de diretórios:

meu-app/
├── Chart.yaml
├── values.yaml
├── templates/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── _helpers.tpl
└── .helmignore

O arquivo Chart.yaml contém metadados essenciais:

apiVersion: v2
name: meu-app
description: Chart para aplicação web exemplo
type: application
version: 0.1.0
appVersion: "1.16.0"

O values.yaml é o ponto central de configuração:

replicaCount: 3

image:
  repository: nginx
  tag: latest
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

3. Templates: a alma do Helm chart

A sintaxe de templates usa Go templates com funções específicas do Helm. Exemplo de templates/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "meu-app.fullname" . }}
  labels:
    {{- include "meu-app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "meu-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "meu-app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.port }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

O arquivo _helpers.tpl define funções reutilizáveis:

{{- define "meu-app.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- define "meu-app.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }}
{{ include "meu-app.selectorLabels" . }}
{{- end }}

{{- define "meu-app.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

Uso de condicionais (if/else) e loops (range):

{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "meu-app.serviceAccountName" . }}
{{- end }}

{{- range .Values.extraPorts }}
  - name: {{ .name }}
    containerPort: {{ .port }}
{{- end }}

4. Gerenciamento de dependências e subcharts

Declare dependências no Chart.yaml:

dependencies:
  - name: nginx-ingress
    version: "4.8.0"
    repository: "https://kubernetes.github.io/ingress-nginx"
    condition: nginx-ingress.enabled

Atualize as dependências:

helm dependency update meu-app/

Isso gera o arquivo Chart.lock com versões fixas. Subcharts permitem reutilizar componentes como bancos de dados ou ingress controllers sem duplicar configurações.

5. Boas práticas de versionamento e testes locais

Versionamento semântico: altere version no Chart.yaml para cada mudança significativa. A appVersion reflete a versão da aplicação empacotada.

Testes locais essenciais:

# Validar sintaxe e boas práticas
helm lint meu-app/

# Renderizar templates sem instalar
helm template meu-app/ --debug

# Simular install completo
helm install meu-app-release meu-app/ --dry-run --debug

O comando helm template é particularmente útil para depurar erros de template antes de qualquer deploy real.

6. Publicação e distribuição do Helm chart

Empacotando o chart:

helm package meu-app/
# Gera: meu-app-0.1.0.tgz

Para hospedar, uma opção simples é usar GitHub Pages:

# No repositório gh-pages branch
mkdir -p docs/charts
mv meu-app-0.1.0.tgz docs/charts/
helm repo index docs/charts/ --url https://seuuser.github.io/meu-repo/charts

Adicione o repositório e instale:

helm repo add meu-repo https://seuuser.github.io/meu-repo/charts
helm install meu-app meu-repo/meu-app --version 0.1.0

7. Integração contínua e automação com Helm

Exemplo de pipeline com GitHub Actions:

name: Helm CI/CD

on:
  push:
    branches: [main]
    paths:
      - 'charts/**'

jobs:
  lint-and-package:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Helm
        uses: azure/setup-helm@v3
        with:
          version: 'latest'
      - name: Lint charts
        run: helm lint charts/meu-app/
      - name: Package chart
        run: helm package charts/meu-app/
      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./charts

Para deploy automatizado em staging:

helm upgrade --install meu-app-staging meu-app/ \
  --set replicaCount=2 \
  --set image.tag=staging-latest \
  --namespace staging

# Rollback se necessário
helm rollback meu-app-staging 1 --namespace staging

Conclusão

Criar seu próprio Helm chart transforma o deploy Kubernetes de um processo manual e propenso a erros em algo padronizado, versionado e automatizado. Com templates parametrizados, dependências gerenciadas e pipelines CI/CD, você ganha consistência entre ambientes e facilidade para escalar. Comece com charts simples e evolua gradualmente, sempre validando com helm lint e helm template antes de qualquer deploy real.

Referências