跳到主要内容

配置管理

问题

Go 项目中如何管理配置?多环境配置怎么处理?

答案

配置来源优先级

命令行参数 > 环境变量 > 配置文件 > 默认值

Viper 实现

import "github.com/spf13/viper"

type Config struct {
Server ServerConfig `mapstructure:"server"`
DB DBConfig `mapstructure:"db"`
Redis RedisConfig `mapstructure:"redis"`
}

type ServerConfig struct {
Port int `mapstructure:"port"`
Timeout time.Duration `mapstructure:"timeout"`
}

func LoadConfig() (*Config, error) {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("./configs")
viper.AddConfigPath(".")

// 环境变量覆盖
viper.AutomaticEnv()
viper.SetEnvPrefix("APP")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

// 默认值
viper.SetDefault("server.port", 8080)
viper.SetDefault("server.timeout", "30s")

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
}
# configs/config.yaml
server:
port: 8080
timeout: 30s

db:
dsn: "user:pass@tcp(localhost:3306)/app?parseTime=true"
max_open: 25
max_idle: 5

redis:
addr: "localhost:6379"

多环境配置

# 通过环境变量切换
APP_ENV=production go run ./cmd/server

# 或在代码中
env := os.Getenv("APP_ENV")
viper.SetConfigName("config." + env) // config.production.yaml

纯环境变量方案

适合容器化部署(12-Factor App):

import "github.com/caarlos0/env/v10"

type Config struct {
Port int `env:"PORT" envDefault:"8080"`
DBHost string `env:"DB_HOST,required"`
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
}

func LoadConfig() (*Config, error) {
cfg := &Config{}
return cfg, env.Parse(cfg)
}

常见面试问题

Q1: 配置中不应该出现什么?

答案

  • 密钥/密码:用 Vault 或 K8s Secrets
  • 代码逻辑:配置只控制行为参数
  • 环境特定的硬编码:IP、端口应走环境变量

Q2: Viper vs 环境变量 vs 配置文件?

答案

  • 本地开发:YAML 配置文件(可读性好)
  • Docker/K8s:环境变量(容器化标准)
  • 复杂项目:Viper 支持两者兼容 + 热更新

相关链接