Configuração: Viper, Env e Arquivos de Configuração
Operadores configuram CLIs e serviços Go através de flags, variáveis de ambiente e arquivos.
Busque em todas as páginas da documentação
Operadores configuram CLIs e serviços Go através de flags, variáveis de ambiente e arquivos.
Viper (github.com/spf13/viper) centraliza essa camada: padrões no código, YAML/TOML/JSON opcionais em disco, substituições de env, e vinculação de flags do cobra.
O mesmo módulo frequentemente alimenta tanto cmd/server quanto cmd/tool, então as regras de configuração permanecem consistentes entre os binários.
A configuração no estilo do Twelve-factor mantém segredos fora do controle de versão e permite que contêineres injetem variáveis de ambiente em tempo de execução.
Viper lê múltiplas fontes e expõe GetString, GetInt e similares após a mesclagem.
Documente a precedência (flags batem env batem arquivo batem padrões) no README para que engenheiros de plantão saibam qual valor vence.
Cartão de receita de referência rápida - pronto para copiar e colar.
viper.SetDefault("api.timeout", "30s")
viper.SetConfigName("config")
viper.AddConfigPath(".")
_ = viper.ReadInConfig()
viper.SetEnvPrefix("MYAPP")
viper.AutomaticEnv()
viper.BindPFlags(cmd.Flags())
timeout := viper.GetDuration("api.timeout")Quando usar isso:
--config mais variáveis de ambiente MYAPP_*.package main
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func main() {
var cfgFile string
root := &cobra.Command{Use: "worker"}
root.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
root.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
viper.SetDefault("api.url", "http://localhost:8080")
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName("config")
viper.AddConfigPath(".")
}
_ = viper.ReadInConfig() // arquivo opcional
viper.SetEnvPrefix("WORKER")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
return viper.BindPFlags(cmd.Flags())
}
root.RunE = func(cmd *cobra.Command, args []string) error {
fmt.Println("api", viper.GetString("api.url"))
return nil
}
if err := root.Execute(); err != nil {
os.Exit(1)
}
}O que isso demonstra:
PersistentPreRunE carrega a configuração antes que cada subcomando seja executado.SetEnvKeyReplacer mapeia api.url para WORKER_API_URL.BindPFlags permite que --api.url substitua arquivo e env em tempo de execução.ReadInConfig carrega o primeiro arquivo encontrado nos caminhos de busca.WatchConfig e OnConfigChange habilitam recarga a quente (mais comum em servidores do que CLIs).Unmarshal ou UnmarshalKey projetam configurações em structs para acesso seguro a tipos.| Prioridade (alta para baixa) | Fonte |
|---|---|
| 1 | Flags explícitas de CLI vinculadas com BindPFlags |
| 2 | Variáveis de ambiente (AutomaticEnv) |
| 3 | Arquivo de configuração |
| 4 | SetDefault no código |
Documente qualquer desvio se a ordem do seu PreRun for diferente.
api:
url: https://api.example.com
timeout: 30s
database:
dsn: postgres://localhost:5432/appapi.url em acessadores viper.config.example.yaml com placeholders seguros.if viper.GetString("api.url") == "" { return err }.mapstructure para configurações grandes em vez de chamadas Get* dispersas.viper.Reset() ou use uma nova instância viper via viper.New() para evitar poluição global.viper.New() por teste ou viper.Reset() em t.Cleanup.API_URL não mapeia para api.url sem regras de . para _. Correção: SetEnvKeyReplacer(strings.NewReplacer(".", "_")).ReadInConfig ignorado quando o arquivo é opcional. Correção: distinguir ConfigFileNotFoundError de falhas de análise.30s, não 30). Correção: validar na inicialização ou usar inteiros para segundos.viper.AllSettings() despeja senhas. Correção: redigir chaves secretas conhecidas em impressoras de debug.| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| envconfig / caarlos0/env | Apenas env de struct, sem arquivos | Você precisa de hierarquias YAML |
| koanf | Cadeias de mesclagem explícitas | Equipe já usa viper+cobra |
| os.Getenv manual | Duas variáveis de ambiente no total | Muitas chaves aninhadas |
| apenas flags | Ferramentas de CI efêmeras | Operadores precisam de arquivos de configuração |
Raramente.
Controladores de longa execução sim; CLIs de execução única leem a configuração uma vez no início.
Chame AddConfigPath para /etc/myapp, $HOME/.myapp e . na ordem.
O primeiro arquivo legível vence, a menos que você use --config explícito.
Sim.
Chame viper.BindPFlags com um pflag.FlagSet ou leia valores após flag.Parse da stdlib.
Carregue do env ou de gerenciadores de segredos; nunca comite DSNs reais.
Valide a presença na inicialização com mensagens de erro claras.
Monte YAML como arquivos e defina AddConfigPath para o ponto de montagem, ou projete chaves para variáveis de ambiente.
Documente quais chaves o chart define.
Use viper.New(), defina env com t.Setenv, escreva arquivos de configuração temporários e afirme os resultados de GetString.
Evite o viper global em testes paralelos.
Sim, com as tags de compilação e importações de parser apropriadas.
YAML é o mais comum para configuração de operador editada por humanos.
GetInt retorna 0 para chaves ausentes, a menos que SetDefault ou um arquivo forneça um valor.
Use ponteiros em structs quando 0 for válido e ambíguo.
Frequentemente sim - um pacote internal/config carrega viper uma vez e expõe uma struct tipada para ambos os binários.
A seção de observabilidade cobre camadas semelhantes para serviços de produção.
CLIs reutilizam os mesmos nomes de env ao envolver esses serviços.
Versões de Stack: Esta página foi escrita para Go 1.26.x (GC padrão Green Tea, go fix modernizers - verifique o patch na compilação), chi (última - verifique na compilação), gin (última - verifique na compilação), echo (última - verifique na compilação), google.golang.org/grpc (última - verifique na compilação), sigs.k8s.io/controller-runtime (última - verifique na compilação), kubebuilder (última - verifique na compilação), tinygo (última - verifique os alvos de placa na compilação), wazero (última - verifique na compilação) e golangci-lint (última - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026