357 lines
8.8 KiB
Markdown
357 lines
8.8 KiB
Markdown
# 配置管理系统说明
|
||
|
||
## 概述
|
||
|
||
本项目采用分层配置管理系统,支持环境变量和配置文件两种方式,实现敏感信息与应用配置的分离。
|
||
|
||
## 配置文件结构
|
||
|
||
```
|
||
autool/
|
||
├── .env # 环境变量配置(敏感信息,不提交)
|
||
├── .env.example # 环境变量配置模板(提交到版本库)
|
||
├── config/
|
||
│ ├── current_env.txt # 当前环境标识(prod/test)
|
||
│ ├── prod.yaml # 生产环境配置
|
||
│ ├── test.yaml # 测试环境配置
|
||
│ ├── local.yaml # 本地覆盖配置(不提交)
|
||
│ └── local.yaml.example # 本地配置示例
|
||
├── config_loader.py # 配置文件加载模块
|
||
├── env_loader.py # 环境变量加载模块
|
||
└── config_usage_examples.py # 使用示例
|
||
```
|
||
|
||
## 配置优先级
|
||
|
||
配置加载的优先级从高到低为:
|
||
|
||
1. **环境变量**(`.env` 文件或系统环境变量)
|
||
2. **本地配置**(`config/local.yaml` 或 `config/local.json`)
|
||
3. **环境配置**(`config/prod.yaml` 或 `config/test.yaml`)
|
||
|
||
## 快速开始
|
||
|
||
### 1. 配置环境变量(敏感信息)
|
||
|
||
```bash
|
||
# 复制模板文件
|
||
cp .env.example .env
|
||
|
||
# 编辑 .env 文件,填入实际的 API 密钥
|
||
vim .env
|
||
```
|
||
|
||
`.env` 文件示例:
|
||
```bash
|
||
# AI 服务 API 密钥
|
||
GEMINI_API_KEY=your_actual_gemini_api_key_here
|
||
AZURE_API_KEY=your_actual_azure_api_key_here
|
||
QWEN_API_KEY=sk-your_actual_qwen_api_key_here
|
||
GLM_API_KEY=your_actual_glm_api_key_here
|
||
|
||
# 通知服务 Token
|
||
WECHAT_TOKEN_YFZ=your_actual_wechat_token_here
|
||
WECOM_TOKEN_TEAM1=your_actual_wecom_token_here
|
||
|
||
# 系统认证
|
||
IOS_PASSWORD=your_ios_device_password_here
|
||
```
|
||
|
||
### 2. 配置本地开发环境(可选)
|
||
|
||
如果需要覆盖环境配置(如修改路径、调试参数等),可创建本地配置文件:
|
||
|
||
```bash
|
||
# 复制本地配置模板
|
||
cp config/local.yaml.example config/local.yaml
|
||
|
||
# 编辑本地配置
|
||
vim config/local.yaml
|
||
```
|
||
|
||
`config/local.yaml` 示例:
|
||
```yaml
|
||
# 本地开发配置覆盖
|
||
logging:
|
||
level: DEBUG # 覆盖生产环境的 INFO
|
||
|
||
output:
|
||
base_dir: D:/local_output # 使用本地路径
|
||
|
||
redis:
|
||
host: 127.0.0.1 # 使用本地 Redis
|
||
db: 9 # 独立的数据库编号
|
||
```
|
||
|
||
### 3. 在代码中使用配置
|
||
|
||
#### 读取环境变量(推荐用于敏感信息)
|
||
|
||
```python
|
||
from env_loader import get_env, get_env_bool, get_env_int
|
||
|
||
# 读取必需的环境变量
|
||
gemini_api_key = get_env(
|
||
"GEMINI_API_KEY",
|
||
required=True,
|
||
hint="See .env.example for setup instructions"
|
||
)
|
||
|
||
# 读取可选的环境变量(带默认值)
|
||
azure_api_key = get_env("AZURE_API_KEY", default="")
|
||
debug_mode = get_env_bool("DEBUG", default=False)
|
||
timeout = get_env_int("TIMEOUT", default=30)
|
||
```
|
||
|
||
#### 读取配置文件(推荐用于应用配置)
|
||
|
||
```python
|
||
from config_loader import load_config
|
||
|
||
# 加载配置(自动根据 current_env.txt 选择环境)
|
||
config = load_config()
|
||
|
||
# 读取配置项
|
||
output_dir = config.get("output", {}).get("base_dir", "./output")
|
||
log_level = config.get("logging", {}).get("level", "INFO")
|
||
redis_host = config.get("redis", {}).get("host", "localhost")
|
||
```
|
||
|
||
#### 在配置文件中引用环境变量
|
||
|
||
配置文件支持 `${ENV_VAR_NAME}` 格式引用环境变量:
|
||
|
||
`config/prod.yaml`:
|
||
```yaml
|
||
notifications:
|
||
wechat:
|
||
yfz: "${WECHAT_TOKEN_YFZ}" # 从环境变量读取
|
||
wecom:
|
||
team1: "${WECOM_TOKEN_TEAM1}"
|
||
```
|
||
|
||
加载后会自动展开:
|
||
```python
|
||
config = load_config()
|
||
token = config["notifications"]["wechat"]["yfz"] # 自动展开为实际的 token 值
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 敏感信息 vs 应用配置
|
||
|
||
**使用 `.env` 文件的场景**:
|
||
- API 密钥、Token
|
||
- 数据库密码、Redis 密码
|
||
- 系统账户密码
|
||
- 其他不应出现在版本库中的敏感信息
|
||
|
||
**使用配置文件(`config/*.yaml`)的场景**:
|
||
- 应用功能开关
|
||
- 超时设置、重试次数等参数
|
||
- 文件路径、目录配置
|
||
- 日志级别、输出格式等
|
||
- 非敏感的业务配置
|
||
|
||
### 2. 环境隔离
|
||
|
||
```bash
|
||
# 切换到测试环境
|
||
echo "test" > config/current_env.txt
|
||
|
||
# 切换回生产环境
|
||
echo "prod" > config/current_env.txt
|
||
```
|
||
|
||
### 3. 本地开发配置
|
||
|
||
本地配置文件(`config/local.yaml`)用于覆盖环境配置,常见用途:
|
||
|
||
- 使用本地路径替代网络共享路径(提升速度)
|
||
- 启用详细日志(`DEBUG`)
|
||
- 连接本地数据库/Redis(避免影响生产环境)
|
||
- 临时关闭某些功能特性
|
||
|
||
### 4. 团队协作
|
||
|
||
**提交到版本库的文件**:
|
||
- `.env.example` - 环境变量模板,不含真实密钥
|
||
- `config/prod.yaml`, `config/test.yaml` - 环境配置
|
||
- `config/local.yaml.example` - 本地配置示例
|
||
|
||
**不提交到版本库的文件**(已在 `.gitignore` 中):
|
||
- `.env` - 包含真实密钥
|
||
- `config/local.yaml`, `config/local.json` - 个人本地配置
|
||
|
||
## 迁移指南
|
||
|
||
### 从硬编码配置迁移
|
||
|
||
**旧代码**:
|
||
```python
|
||
# 硬编码在代码中
|
||
GEMINI_API_KEY = "AQ.Ab8RN6INSIgaGdgj5hmmYmi35QLw6K3likBz2bP37_I_F6V5aQ"
|
||
OUTPUT_DIR = "./output"
|
||
LOG_LEVEL = "INFO"
|
||
```
|
||
|
||
**新代码**:
|
||
```python
|
||
from env_loader import get_env
|
||
from config_loader import load_config
|
||
|
||
# 敏感信息从环境变量读取
|
||
GEMINI_API_KEY = get_env("GEMINI_API_KEY", required=True)
|
||
|
||
# 应用配置从配置文件读取
|
||
config = load_config()
|
||
OUTPUT_DIR = config.get("output", {}).get("base_dir", "./output")
|
||
LOG_LEVEL = config.get("logging", {}).get("level", "INFO")
|
||
```
|
||
|
||
**配置文件**:
|
||
|
||
`.env`:
|
||
```bash
|
||
GEMINI_API_KEY=AQ.Ab8RN6INSIgaGdgj5hmmYmi35QLw6K3likBz2bP37_I_F6V5aQ
|
||
```
|
||
|
||
`config/prod.yaml`:
|
||
```yaml
|
||
output:
|
||
base_dir: ./output
|
||
logging:
|
||
level: INFO
|
||
```
|
||
|
||
### 向后兼容处理
|
||
|
||
如果配置文件不存在,给出友好提示:
|
||
|
||
```python
|
||
from config_loader import load_config
|
||
|
||
try:
|
||
config = load_config()
|
||
except FileNotFoundError as e:
|
||
print(f"Configuration file not found: {e}")
|
||
print("Please set up the configuration files in the config/ directory")
|
||
# 使用默认配置或退出
|
||
config = {} # 使用空配置或默认值
|
||
```
|
||
|
||
环境变量不存在时的友好提示:
|
||
|
||
```python
|
||
from env_loader import get_env, print_env_setup_guide, check_required_env_vars
|
||
|
||
# 检查必需的环境变量
|
||
missing_vars = check_required_env_vars(["GEMINI_API_KEY", "AZURE_API_KEY"])
|
||
|
||
if missing_vars:
|
||
print(f"Missing required environment variables: {', '.join(missing_vars)}")
|
||
print_env_setup_guide()
|
||
raise ValueError("Please configure environment variables")
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
### Q1: `.env` 文件和 `config/local.yaml` 有什么区别?
|
||
|
||
- `.env` 用于**敏感信息**(API 密钥、密码等),格式固定为 `KEY=VALUE`
|
||
- `config/local.yaml` 用于**本地配置覆盖**(路径、参数等),支持嵌套结构
|
||
|
||
### Q2: 如何验证配置是否生效?
|
||
|
||
```python
|
||
from env_loader import get_env
|
||
from config_loader import load_config
|
||
|
||
# 检查环境变量
|
||
print(f"GEMINI_API_KEY: {get_env('GEMINI_API_KEY', default='<not set>')}")
|
||
|
||
# 检查配置文件
|
||
config = load_config()
|
||
print(f"Environment: {config.get('environment', {}).get('name', 'unknown')}")
|
||
print(f"Log level: {config.get('logging', {}).get('level', 'INFO')}")
|
||
```
|
||
|
||
### Q3: 配置文件支持哪些格式?
|
||
|
||
- **环境变量**:`.env` 文件(`KEY=VALUE` 格式)
|
||
- **配置文件**:`.yaml`、`.yml`、`.json`
|
||
|
||
推荐使用 YAML 格式,因为:
|
||
- 支持注释
|
||
- 支持嵌套结构
|
||
- 可读性更好
|
||
|
||
### Q4: 如何在配置文件中引用环境变量?
|
||
|
||
使用 `${ENV_VAR_NAME}` 格式:
|
||
|
||
```yaml
|
||
notifications:
|
||
wechat:
|
||
yfz: "${WECHAT_TOKEN_YFZ}" # 引用环境变量
|
||
```
|
||
|
||
加载时会自动展开为环境变量的值。
|
||
|
||
### Q5: 环境变量和配置文件冲突时如何处理?
|
||
|
||
环境变量的优先级最高。例如:
|
||
|
||
`.env`:
|
||
```
|
||
LOG_LEVEL=DEBUG
|
||
```
|
||
|
||
`config/prod.yaml`:
|
||
```yaml
|
||
logging:
|
||
level: INFO
|
||
```
|
||
|
||
如果在配置文件中引用环境变量:
|
||
```yaml
|
||
logging:
|
||
level: "${LOG_LEVEL}" # 实际值为 DEBUG(环境变量)
|
||
```
|
||
|
||
## 完整示例
|
||
|
||
参考 `config_usage_examples.py` 文件,包含:
|
||
- 环境变量读取示例
|
||
- 配置文件读取示例
|
||
- 完整的初始化函数
|
||
- 配置验证逻辑
|
||
- 迁移指南
|
||
|
||
## 安全建议
|
||
|
||
1. **永远不要提交包含真实密钥的文件**
|
||
- `.env` 已在 `.gitignore` 中排除
|
||
- 提交前检查:`git status` 确保 `.env` 不在待提交列表中
|
||
|
||
2. **定期轮换 API 密钥**
|
||
- 定期更新 `.env` 中的密钥
|
||
- 旧密钥在服务提供商处失效
|
||
|
||
3. **最小权限原则**
|
||
- API 密钥只授予必需的权限
|
||
- 生产环境和开发环境使用不同的密钥
|
||
|
||
4. **密钥泄露应急处理**
|
||
- 立即在服务提供商处撤销泄露的密钥
|
||
- 生成新密钥并更新 `.env` 文件
|
||
- 检查是否有未授权使用记录
|
||
|
||
## 参考资料
|
||
|
||
- 配置加载模块:`config_loader.py`
|
||
- 环境变量加载模块:`env_loader.py`
|
||
- 使用示例:`config_usage_examples.py`
|
||
- 环境变量模板:`.env.example`
|
||
- 本地配置示例:`config/local.yaml.example`
|