198 lines
6.2 KiB
Markdown
198 lines
6.2 KiB
Markdown
# 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
|
||
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 - 部署架构](14-deployment.md) | 配置管理在部署中的应用 |
|
||
| [01 - 系统总览](01-system-overview.md) | 配置在启动流程中的位置 |
|
||
| [02 - 协程池](02-worker-pool.md) | WorkerPoolConfig 控制并发参数 |
|
||
| [00 - 索引](00-index.md) | 返回文档总览 |
|