Files
cs-note/hzh/Gen2D/15-配置级联机制.md
T

201 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [config, viper, environment-variables, yaml, deployment, configuration-management]
create time: 2026-06-03 11:10
---
# 15. 配置级联机制
## 概述
Viper 三层配置级联 — YAML 文件 -> 环境变量 -> 默认值,一处配置随处运行。
## 正文
### 配置加载流程
```mermaid
flowchart LR
subgraph "配置源(优先级从低到高)"
D["默认值\nsetDefaults()"]
Y["YAML 文件\nconfig.yaml"]
E["环境变量\n.env / system env"]
end
subgraph "Viper 引擎"
V["Viper\n合并 + 覆盖"]
end
subgraph "输出"
C["Config Struct\n全局配置对象"]
S["各组件\nServer / DB / Redis / ..."]
end
D -->|"1. 设置默认值"| V
Y -->|"2. 读取 YAML"| V
E -->|"3. 绑定 ENV"| V
V -->|"Unmarshal"| C
C -->|"注入"| S
style D fill:#9e9e9e,stroke:#333,color:#fff
style Y fill:#2196f3,stroke:#333,color:#fff
style E fill:#f44336,stroke:#333,color:#fff
style V fill:#ff9800,stroke:#333,color:#fff
```
**优先级规则**:`ENV > YAML > Default`
环境变量始终拥有最高优先级,可以覆盖任何 YAML 配置;YAML 配置覆盖默认值。
---
### 配置结构体
```go
type Config struct {
Server ServerConfig // HTTP 服务
Database DatabaseConfig // MySQL 数据库
JWT JWTConfig // JWT 签名
Log LogConfig // 日志
Redis RedisConfig // Redis 缓存
LLM LLMConfig // 大语言模型
ImageGen ImageGenConfig // 文生图 API
Qiniu QiniuConfig // 七牛云存储
WorkerPool WorkerPoolConfig // 协程池
TaskQueue TaskQueueConfig // 任务队列
}
```
| 配置块 | 关键字段 | 默认值 |
|--------|----------|--------|
| `Server` | `port`, `mode` | `8080`, `debug` |
| `Database` | `dsn` | `gen2d:password@tcp(127.0.0.1:3306)/gen2d` |
| `JWT` | `secret`, `expire` | `gen2d-dev-secret`, `7200s` |
| `Log` | `level`, `format` | `info`, `text` |
| `Redis` | `addr`, `password`, `db` | `localhost:6379`, `""`, `0` |
| `LLM` | `base_url`, `api_key`, `model` | `api.openai.com/v1`, `""`, `gpt-4o` |
| `ImageGen` | `base_url`, `model`, `timeout` | `api.suchuang.vip/v1`, `gpt-image-2-token`, `120s` |
| `Qiniu` | `bucket`, `cdn_host`, `url_expire` | `""`, `""`, `3600s` |
| `WorkerPool` | `workers`, `queue_size`, `max_per_user` | `NumCPU*4`, `100`, `2` |
| `TaskQueue` | `driver`, `memory.buffer_size` | `memory`, `100` |
---
### 环境变量绑定
每个配置字段都有对应的环境变量绑定,命名规则为 `GEN2D_` 前缀 + 大写下划线格式:
```go
func bindEnvVars(v *viper.Viper) {
v.BindEnv("server.port", "GEN2D_PORT")
v.BindEnv("server.mode", "GEN2D_MODE")
v.BindEnv("database.dsn", "GEN2D_DSN")
v.BindEnv("jwt.secret", "GEN2D_JWT_SECRET")
v.BindEnv("llm.api_key", "GEN2D_LLM_API_KEY")
v.BindEnv("redis.addr", "GEN2D_REDIS_ADDR")
v.BindEnv("qiniu.access_key", "GEN2D_QINIU_ACCESS_KEY")
// ... 共 25+ 个绑定
}
```
| 配置路径 | 环境变量 | 说明 |
|----------|----------|------|
| `server.port` | `GEN2D_PORT` | HTTP 端口 |
| `server.mode` | `GEN2D_MODE` | `debug` / `release` |
| `database.dsn` | `GEN2D_DSN` | MySQL 连接串 |
| `jwt.secret` | `GEN2D_JWT_SECRET` | JWT 签名密钥 |
| `llm.base_url` | `GEN2D_LLM_BASE_URL` | LLM API 地址 |
| `llm.api_key` | `GEN2D_LLM_API_KEY` | LLM API 密钥 |
| `image_gen.base_url` | `GEN2D_IMAGE_BASE_URL` | 文生图 API 地址 |
| `redis.addr` | `GEN2D_REDIS_ADDR` | Redis 地址 |
| `taskqueue.driver` | `GEN2D_TASKQUEUE_DRIVER` | `memory` / `rabbitmq` |
---
### 使用场景
```mermaid
flowchart TD
subgraph "开发环境"
D1["config.yaml\n本地配置文件"]
D2[".env\n环境变量覆盖敏感值"]
D3["默认值\n开箱即用"]
end
subgraph "测试环境"
T1["环境变量\nCI/CD 管线注入"]
T2["默认值\n兜底"]
end
subgraph "生产环境"
P1["K8s ConfigMap\n非敏感配置"]
P2["K8s Secret\n敏感配置(密钥、DSN)"]
P3["默认值\n兜底"]
end
D1 --> D3
D2 --> D1
T1 --> T2
P1 --> P3
P2 --> P1
```
| 环境 | 主配置源 | 敏感配置 | 说明 |
|------|----------|----------|------|
| 开发 | `config.yaml` | `.env` 文件 | 直观、可版本控制 |
| 测试 | 环境变量 | 环境变量 | CI/CD 管线注入 |
| 生产 | ConfigMap | Secret | K8s 原生管理 |
---
### 加载过程详解
```mermaid
sequenceDiagram
participant Main as main.go
participant Viper as Viper
participant YAML as config.yaml
participant ENV as 环境变量
participant Cfg as Config Struct
Main->>Viper: Load()
Main->>Viper: setDefaults(v)
Note over Viper: 设置 25+ 默认值
Viper->>YAML: ReadInConfig()
YAML-->>Viper: 配置内容
Viper->>Viper: bindEnvVars(v)
Note over Viper: 绑定 25+ 环境变量
Viper->>ENV: 读取环境变量
ENV-->>Viper: 覆盖对应字段
Viper->>Cfg: Unmarshal(&cfg)
Cfg-->>Main: 返回完整配置
```
关键步骤:
1. **加载 `.env` 文件** — `godotenv.Load()` 从项目根目录读取 `.env`
2. **设置默认值** — `setDefaults(v)` 为所有字段提供合理的默认值
3. **读取 YAML** — `v.ReadInConfig()` 从 `internal/config/config.yaml` 加载
4. **绑定环境变量** — `bindEnvVars(v)` 将每个字段映射到 `GEN2D_*` 环境变量
5. **反序列化** — `v.Unmarshal(&cfg)` 将合并后的配置映射到 Go 结构体
> **容错设计**:YAML 文件不存在时不报错,仅使用环境变量 + 默认值。这确保了零配置即可启动。
---
### 与部署的关系
配置级联机制与部署架构紧密配合:
| 部署方式 | 配置策略 | 示例 |
|----------|----------|------|
| `go run` 本地开发 | YAML + `.env` | `config.yaml` 配置 DB,`.env` 配置 API Key |
| `docker compose` | `.env` 文件注入 | `env_file: ./backend/.env` |
| Kubernetes | ConfigMap + Secret | `GEN2D_DSN` 从 Secret 注入 |
## 关联文档
- [[14-部署架构]] — 配置管理在部署中的应用
- [[01-系统总览]] — 配置在启动流程中的位置
- [[02-协程池]] — WorkerPoolConfig 控制并发参数
- [[00-索引]] — 返回文档总览