Gerenciamento de Configurações em Microsserviços: Variáveis, ConfigMaps e Segredos

Uma das maiores dores em microsserviços não é o código – é a configuração. URLs de banco de dados, chaves de API, endpoints de serviços vizinhos, credenciais, feature flags, timeouts… Tudo isso muda entre ambientes (desenvolvimento, homologação, produção) e precisa ser gerenciado de forma segura, auditable e sem exigir rebuild das imagens.

Em Go, a abordagem idiomática é usar variáveis de ambiente combinadas com arquivos de configuração (quando necessário). Em Kubernetes, entram os ConfigMaps e Secrets. Em sistemas mais críticos, ferramentas como HashiCorp Vault ou AWS Secrets Manager entram em cena.

Neste post, vamos explorar as melhores práticas para gerenciar configurações em microsserviços, com exemplos em Go, desde o desenvolvimento local até a produção em Kubernetes.

Por que configuração é um desafio em microsserviços?

Em um monólito, você tem um único arquivo de configuração. Em microsserviços, cada serviço tem suas próprias configurações – e elas podem variar por réplica, ambiente e região. Os principais desafios:

  • Segurança: credenciais não podem ficar no código ou em repositórios.
  • Consistência: mesma configuração para todas as réplicas de um serviço.
  • Rotação: trocar senhas sem reiniciar o serviço.
  • Auditoria: saber quem mudou o quê e quando.

1. Variáveis de ambiente: o padrão ouro para configuração em Go

A 12-factor app recomenda armazenar configurações em variáveis de ambiente. Go lê isso de forma trivial:

package main

import (
    "fmt"
    "log"
    "os"
    "strconv"
)

type Config struct {
    Port         int
    DatabaseURL  string
    RedisAddr    string
    LogLevel     string
}

func LoadConfig() *Config {
    port, _ := strconv.Atoi(getEnv("PORT", "8080"))
    return &Config{
        Port:         port,
        DatabaseURL:  getEnv("DATABASE_URL", "postgres://localhost:5432/app?sslmode=disable"),
        RedisAddr:    getEnv("REDIS_ADDR", "localhost:6379"),
        LogLevel:     getEnv("LOG_LEVEL", "info"),
    }
}

func getEnv(key, defaultValue string) string {
    if value := os.Getenv(key); value != "" {
        return value
    }
    return defaultValue
}

func main() {
    cfg := LoadConfig()
    fmt.Printf("Rodando na porta %d\n", cfg.Port)
}

Vantagens: simples, universal, segura (se você não logar as variáveis).
Desvantagens: para muitas configurações, o comando de execução fica enorme; difícil gerenciar hierarquias.

2. Arquivos de configuração (YAML, JSON, TOML) – quando usar

Para configurações estruturadas (ex: múltiplos bancos, timeouts por endpoint), arquivos são mais limpos.

import "github.com/spf13/viper"

func LoadConfigWithViper() (*Config, error) {
    viper.SetConfigName("config")   // config.yaml
    viper.SetConfigType("yaml")
    viper.AddConfigPath(".")
    viper.AddConfigPath("/etc/app/")
    viper.AutomaticEnv() // override por env vars

    if err := viper.ReadInConfig(); err != nil {
        return nil, err
    }

    var cfg Config
    if err := viper.Unmarshal(&cfg); err != nil {
        return nil, err
    }
    return &cfg, nil
}

Exemplo de config.yaml:

port: 8080
database_url: postgres://localhost:5432/app
redis_addr: localhost:6379
features:
  checkout_v2: true
  use_new_recommendations: false

Vantagem: hierarquia, legibilidade.
Desvantagem: arquivo pode ficar desatualizado entre ambientes; risco de commitar segredos.

Boa prática: nunca commite segredos no arquivo. Use variáveis de ambiente ou secrets para valores sensíveis.

3. Configuração em Kubernetes: ConfigMaps e Secrets

No Kubernetes, a configuração é injetada no pod via:

  • ConfigMap: para configurações não sensíveis (URLs, log levels, feature flags).
  • Secret: para dados sensíveis (senhas, tokens, chaves API) – armazenados em base64 (mas não é criptografia; use encryption at rest no cluster).

Criando um ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: info
  REDIS_ADDR: redis-service.default.svc.cluster.local:6379
  config.yaml: |
    port: 8080
    features:
      checkout_v2: true

Criando um Secret

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  DATABASE_URL: cG9zdGdyZXM6Ly91c2VyOnBhc3NAcG9zdGdyZXM6NTQzMi9hcHA=

Usando no Deployment

spec:
  containers:
  - name: api
    image: myapp:latest
    env:
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: LOG_LEVEL
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: DATABASE_URL
    volumeMounts:
    - name: config-volume
      mountPath: /app/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

4. Ferramentas avançadas: Vault, AWS Secrets Manager, Doppler

Para produção com alta segurança, variáveis de ambiente e Secrets do K8s podem não ser suficientes (secrets são base64 e podem ser vistos por quem tem acesso ao cluster). Use:

FerramentaIdeal paraGo SDK
HashiCorp VaultSegredos dinâmicos, rotação, auditoriagithub.com/hashicorp/vault/api
AWS Secrets ManagerAmbiente AWS, rotação automáticaAWS SDK for Go
DopplerGerenciamento centralizado (SaaS)github.com/dopplerhq/doppler-go-sdk

Exemplo com Vault:

import vault "github.com/hashicorp/vault/api"

client, _ := vault.NewClient(vault.DefaultConfig())
client.SetToken(os.Getenv("VAULT_TOKEN"))

secret, _ := client.Logical().Read("secret/data/database")
dbPassword := secret.Data["data"].(map[string]interface{})["password"]

5. Hot reload: atualizando configuração sem restart

Em Go, você pode recarregar configuração dinamicamente usando:

  • FSNotify para monitorar arquivos.
  • Polling periódico de variáveis de ambiente ou Secrets.
  • Integração com Vault com leases e renovação.
func WatchConfig(ctx context.Context, cfg *Config) {
    ticker := time.NewTicker(30 * time.Second)
    go func() {
        for {
            select {
            case <-ctx.Done():
                return
            case <-ticker.C:
                // recarrega de fonte externa
                newCfg := reloadFromVault()
                cfg.mu.Lock()
                *cfg = *newCfg
                cfg.mu.Unlock()
            }
        }
    }()
}

Atenção: hot reload só é seguro para configurações que não afetam estruturas críticas (ex: pool de conexões). Para mudanças profundas, prefira restart.

6. Boas práticas para configurações em Go

PráticaPor quê
✅ Use os.Getenv com defaults razoáveisDesenvolvimento local funciona sem setup
✅ Valide a configuração no startup (fail fast)Evita operação com erro silencioso
✅ Não logue segredos nuncaUm log pode expor credenciais
✅ Separe configuração por ambiente (DEV, HOM, PROD)Evita acidentes
✅ Use variáveis de ambiente para segredos em desenvolvimentoSimples e seguro
✅ Em produção, prefira Secrets + VaultMais segurança

Exemplo prático: serviço Go com configuração flexível

type Config struct {
    HTTPPort    int
    DatabaseURL string
    RedisURL    string
    Features    FeatureFlags
}

type FeatureFlags struct {
    NewCheckout bool
    AIRecommend bool
}

func LoadConfig() (*Config, error) {
    viper.SetConfigName("config")
    viper.AddConfigPath(".")
    viper.AutomaticEnv()
    viper.SetEnvPrefix("APP")
    viper.BindEnv("http_port", "PORT")
    viper.BindEnv("database_url", "DATABASE_URL")
    viper.BindEnv("redis_url", "REDIS_URL")
    viper.BindEnv("features.new_checkout")
    viper.BindEnv("features.ai_recommend")

    if err := viper.ReadInConfig(); err != nil {
        log.Printf("Nenhum arquivo de configuração encontrado, usando defaults")
    }

    var cfg Config
    if err := viper.Unmarshal(&cfg); err != nil {
        return nil, err
    }
    return &cfg, nil
}

Caso real: modernização com gestão de configurações

Um cliente da Jacobus operava com dezenas de variáveis de ambiente hardcoded em scripts de deploy. Cada ambiente (dev, staging, prod) exigia rebuild da imagem. Implementamos:

  • ConfigMaps para configurações comuns.
  • Secrets (via Kubernetes) para credenciais de banco.
  • Vault para chaves de API de provedores externos (rotação automática).
  • Viper no código Go para fallback e hierarquia.

Resultado: tempo de deploy caiu 80%. Rotação de segredos passou a ser automática. Zero credenciais em repositórios.

Conclusão

Gerenciar configurações em microsserviços exige disciplina, mas as ferramentas são maduras. Comece com variáveis de ambiente e arquivos YAML locais. Em Kubernetes, use ConfigMaps e Secrets. Para segurança máxima, adicione Vault. O importante é nunca, jamais, colocar segredos no código ou no repositório.

Na Jacobus Software, aplicamos essas práticas em todos os projetos. Configuração é infraestrutura – trate-a com o mesmo rigor que trata o código.


🔐 Quer organizar a configuração dos seus microsserviços?

Nossos especialistas implementam pipelines de configuração com Kubernetes, Vault e CI/CD – seguros, auditáveis e fáceis de gerenciar.

👉 Fale com a Jacobus Software

Rolar para cima