应用配置管理 #

Config Vars 概述 #

Heroku 使用 Config Vars(环境变量)来管理应用配置,遵循 12-Factor App 方法论,将配置与代码分离。

为什么使用环境变量? #

优势 说明
安全性 敏感信息不进入代码仓库
灵活性 不同环境使用不同配置
可移植性 配置独立于代码
易于管理 集中管理所有配置

基本操作 #

设置环境变量 #

bash
# 设置单个变量
heroku config:set KEY=value

# 设置多个变量
heroku config:set KEY1=value1 KEY2=value2 KEY3=value3

# 设置包含空格的值
heroku config:set "MESSAGE=Hello World"

# 设置 JSON 值
heroku config:set CONFIG='{"name":"myapp","debug":false}'

查看环境变量 #

bash
# 查看所有环境变量
heroku config

# 输出示例
# === myapp Config Vars
# DATABASE_URL:  postgres://user:pass@host:5432/db
# NODE_ENV:      production
# SECRET_KEY:    your-secret-key

# 获取单个变量值
heroku config:get DATABASE_URL

# 导出环境变量到文件
heroku config -s > .env

删除环境变量 #

bash
# 删除单个变量
heroku config:unset KEY

# 删除多个变量
heroku config:unset KEY1 KEY2 KEY3

应用中使用环境变量 #

Node.js #

javascript
// 直接使用
const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;
const secret = process.env.SECRET_KEY;

// 使用 dotenv(本地开发)
require('dotenv').config();

// 配置对象
const config = {
  port: parseInt(process.env.PORT, 10) || 3000,
  database: {
    url: process.env.DATABASE_URL,
    pool: parseInt(process.env.DB_POOL_SIZE, 10) || 5
  },
  jwt: {
    secret: process.env.JWT_SECRET,
    expiresIn: process.env.JWT_EXPIRES_IN || '7d'
  },
  redis: {
    url: process.env.REDIS_URL
  }
};

module.exports = config;

Python #

python
import os
from dotenv import load_dotenv

# 加载 .env 文件(本地开发)
load_dotenv()

# 读取环境变量
DATABASE_URL = os.getenv('DATABASE_URL')
SECRET_KEY = os.getenv('SECRET_KEY', 'default-secret')
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
PORT = int(os.getenv('PORT', 5000))

# 配置类
class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY')
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

Ruby #

ruby
# 直接使用
database_url = ENV['DATABASE_URL']
secret_key = ENV['SECRET_KEY']

# 默认值
port = ENV.fetch('PORT', 3000)
debug = ENV.fetch('DEBUG', 'false') == 'true'

# Rails 配置
config.database_url = ENV['DATABASE_URL']
config.secret_key_base = ENV['SECRET_KEY_BASE']

Java #

java
// 读取环境变量
String databaseUrl = System.getenv("DATABASE_URL");
String secretKey = System.getenv("SECRET_KEY");

// 带默认值
String port = System.getenv().getOrDefault("PORT", "8080");

// Spring Boot 配置
@Configuration
public class AppConfig {
    
    @Value("${DATABASE_URL}")
    private String databaseUrl;
    
    @Value("${SECRET_KEY:default-secret}")
    private String secretKey;
}

本地开发配置 #

使用 .env 文件 #

bash
# 创建 .env 文件
cat > .env << 'EOF'
DATABASE_URL=postgres://localhost:5432/myapp_dev
SECRET_KEY=dev-secret-key
NODE_ENV=development
DEBUG=true
EOF

# 添加到 .gitignore
echo ".env" >> .gitignore

Node.js dotenv 配置 #

javascript
// 安装 dotenv
// npm install dotenv

// 在入口文件最顶部加载
require('dotenv').config();

// 或使用 ES Modules
import 'dotenv/config';

// 指定 .env 文件路径
require('dotenv').config({ path: '.env.local' });

Python dotenv 配置 #

python
# 安装 python-dotenv
# pip install python-dotenv

from dotenv import load_dotenv

# 加载 .env 文件
load_dotenv()

# 指定文件路径
load_dotenv('.env.local')

环境变量管理策略 #

按环境分类 #

text
┌─────────────────────────────────────────┐
│           环境变量分层                    │
├─────────────────────────────────────────┤
│                                         │
│  基础配置(所有环境)                     │
│  ├── APP_NAME                          │
│  └── LOG_LEVEL                         │
│                                         │
│  环境特定配置                            │
│  ├── Development                       │
│  │   ├── DEBUG=true                    │
│  │   └── LOG_LEVEL=debug               │
│  │                                     │
│  ├── Staging                           │
│  │   ├── DEBUG=false                   │
│  │   └── LOG_LEVEL=info                │
│  │                                     │
│  └── Production                        │
│      ├── DEBUG=false                   │
│      └── LOG_LEVEL=warn                │
│                                         │
│  敏感配置(仅生产环境)                   │
│  ├── DATABASE_URL                      │
│  ├── SECRET_KEY                        │
│  └── API_KEYS                          │
│                                         │
└─────────────────────────────────────────┘

多应用配置 #

bash
# 为不同应用设置配置
heroku config:set --app myapp-staging NODE_ENV=staging
heroku config:set --app myapp-production NODE_ENV=production

# 使用管道传递配置
heroku config -s --app myapp-staging | heroku config:set --app myapp-production

敏感信息处理 #

密钥管理最佳实践 #

bash
# 1. 使用强随机密钥
heroku config:set SECRET_KEY=$(openssl rand -hex 32)

# 2. 定期轮换密钥
heroku config:set NEW_SECRET_KEY=$(openssl rand -hex 32)
# 更新应用使用新密钥
heroku config:unset OLD_SECRET_KEY

# 3. 不同服务使用不同密钥
heroku config:set JWT_SECRET=$(openssl rand -hex 32)
heroku config:set SESSION_SECRET=$(openssl rand -hex 32)
heroku config:set ENCRYPTION_KEY=$(openssl rand -hex 32)

数据库连接字符串 #

bash
# Heroku 自动设置 DATABASE_URL
# 格式: postgres://user:password@host:port/database

# 应用中使用
const { Pool } = require('pg');
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { rejectUnauthorized: false }
});

API 密钥管理 #

javascript
// 配置多个 API 密钥
const apiKeys = {
  stripe: process.env.STRIPE_API_KEY,
  sendgrid: process.env.SENDGRID_API_KEY,
  twilio: {
    sid: process.env.TWILIO_ACCOUNT_SID,
    token: process.env.TWILIO_AUTH_TOKEN
  }
};

// 验证必需的 API 密钥
const requiredKeys = [
  'STRIPE_API_KEY',
  'SENDGRID_API_KEY'
];

requiredKeys.forEach(key => {
  if (!process.env[key]) {
    console.error(`Missing required API key: ${key}`);
    process.exit(1);
  }
});

配置验证 #

启动时验证 #

javascript
// config/validate.js
const requiredEnvVars = [
  'DATABASE_URL',
  'SECRET_KEY',
  'NODE_ENV'
];

const validateEnv = () => {
  const missing = requiredEnvVars.filter(key => !process.env[key]);
  
  if (missing.length > 0) {
    console.error('Missing required environment variables:');
    missing.forEach(key => console.error(`  - ${key}`));
    process.exit(1);
  }
  
  console.log('✓ All required environment variables are set');
};

module.exports = { validateEnv };

类型验证 #

javascript
// 使用 joi 验证环境变量
const Joi = require('joi');

const envSchema = Joi.object({
  NODE_ENV: Joi.string()
    .valid('development', 'staging', 'production')
    .default('development'),
  PORT: Joi.number().default(3000),
  DATABASE_URL: Joi.string().required(),
  SECRET_KEY: Joi.string().min(32).required(),
  REDIS_URL: Joi.string().uri(),
  DEBUG: Joi.boolean().default(false)
}).unknown();

const { error, value: env } = envSchema.validate(process.env);

if (error) {
  console.error('Environment validation error:', error.message);
  process.exit(1);
}

module.exports = env;

配置更新策略 #

零停机更新 #

bash
# 1. 设置新配置
heroku config:set NEW_CONFIG=value

# 2. 部署新代码(使用新配置)
git push heroku main

# 3. 验证后删除旧配置
heroku config:unset OLD_CONFIG

配置变更触发重启 #

bash
# 修改配置会自动创建新 Release 并重启应用
heroku config:set KEY=value

# 查看变更历史
heroku releases

配置模板 #

开发环境模板 #

bash
# .env.example - 提交到代码仓库
NODE_ENV=development
PORT=3000
DATABASE_URL=postgres://localhost:5432/myapp_dev
SECRET_KEY=your-dev-secret-key-at-least-32-characters
DEBUG=true
LOG_LEVEL=debug

生产环境模板 #

bash
# 生产环境配置清单
NODE_ENV=production
PORT=3000
DATABASE_URL=<from-heroku-postgres-addon>
SECRET_KEY=<generated-secure-key>
DEBUG=false
LOG_LEVEL=warn
REDIS_URL=<from-heroku-redis-addon>

故障排查 #

配置未生效 #

bash
# 检查配置是否设置
heroku config:get KEY

# 检查应用是否重启
heroku releases

# 手动重启应用
heroku restart

配置值包含特殊字符 #

bash
# 使用引号包裹
heroku config:set "MESSAGE=Hello, World!"

# 转义特殊字符
heroku config:set 'JSON={"key":"value"}'

配置过大 #

bash
# 单个配置值限制 32KB
# 总配置限制 64KB

# 如果配置过大,考虑:
# 1. 使用外部配置服务
# 2. 存储在数据库中
# 3. 使用文件存储

下一步 #

配置管理掌握后,接下来学习 Procfile 详解 了解如何定义应用进程!

最后更新:2026-03-28