引言:为什么配置管理对Flask应用至关重要
在Flask应用开发中,配置管理是一个看似简单但极其关键的环节。许多开发者在项目初期往往忽视配置管理的重要性,直接将数据库密码、API密钥等敏感信息硬编码在代码中,或者使用简单的全局变量。这种做法在项目规模较小、仅在开发环境运行时可能不会暴露问题,但一旦需要部署到生产环境,或者团队协作开发,问题就会接踵而至。
想象一下这样的场景:你的Flask应用在开发环境中运行良好,数据库连接字符串、密钥等配置都直接写在
app.py
里。当你准备部署到生产环境时,你不得不手动修改这些配置值,不仅容易出错,还可能意外将开发环境的配置提交到代码仓库。更糟糕的是,如果生产环境的数据库密码泄露,攻击者可以轻易获取你的敏感数据。
Flask配置管理的核心挑战在于:
如何在不修改代码的情况下,让同一套应用在不同环境(开发、测试、生产)中使用不同的配置
。这需要我们遵循一些最佳实践,包括:
环境隔离
:确保不同环境的配置完全分离
安全性
:敏感信息不进入代码仓库
可维护性
:配置修改简单直观,易于团队协作
灵活性
:支持多种配置加载方式,适应不同部署场景
本文将详细介绍Flask配置管理的最佳实践,从基础的配置分离到高级的环境变量管理,再到生产环境的安全策略,帮助你构建一个安全、高效、可维护的配置管理体系。
Flask配置基础:从简单到复杂的演进
1. 基础配置方式及其局限性
Flask应用最基础的配置方式是直接在应用实例上设置属性:
from flask import Flask
app = Flask(__name__)
app.config[‘SECRET_KEY’] = ‘my-secret-key’
app.config[‘DEBUG’] = True
app.config[‘DATABASE_URI’] = ‘sqlite:///dev.db’
或者使用
update
方法批量设置:
app.config.update(
SECRET_KEY=’my-secret-key’,
DEBUG=True,
DATABASE_URI=’sqlite:///dev.db’
)
优点
:简单直接,适合快速原型开发。
缺点
:
配置与代码混合,难以维护
敏感信息硬编码,存在安全风险
不同环境需要手动修改代码
无法版本控制不同环境的配置
2. 使用类的配置方式
为了更好地组织配置,我们可以将配置定义为类:
class Config:
SECRET_KEY = ‘my-secret-key’
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = ‘sqlite:///dev.db’
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = ‘postgresql://user:pass@localhost/prod_db’
config = {
‘development’: DevelopmentConfig,
‘production’: ProductionConfig,
‘default’: DevelopmentConfig
}
然后在应用工厂中使用:
def create_app(config_name=’default’):
app = Flask(__name__)
app.config.from_object(config[config_name])
return app
这种方式比直接在应用实例上设置配置要好,但仍然存在硬编码敏感信息的问题。
配置分离策略:让代码与配置真正解耦
1. 配置文件分离
将配置从代码中分离出来,存放在独立的配置文件中。Flask支持从多种格式的文件加载配置:
JSON配置文件
config.json
:
{
“development”: {
“SECRET_KEY”: “dev-secret-key”,
“DEBUG”: true,
“SQLALCHEMY_DATABASE_URI”: “sqlite:///dev.db”
},
“production”: {
“SECRET_KEY”: “prod-secret-key”,
“DEBUG”: false,
“SQLALCHEMY_DATABASE_URI”: “postgresql://user:pass@localhost/prod_db”
}
}
加载方式
:
import json
def create_app(config_name=’development’):
app = Flask(__name__)
with open(‘config.json’) as f:
config_data = json.load(f)
app.config.from_mapping(config_data[config_name])
return app
Python配置文件
config.py
:
import os
class Config:
SECRET_KEY = os.environ.get(‘SECRET_KEY’) or ‘fallback-secret-key’
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = ‘sqlite:///dev.db’
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = os.environ.get(‘DATABASE_URL’) or ‘postgresql://user:pass@localhost/prod_db’
config = {
‘development’: DevelopmentConfig,
‘production’: ProductionConfig,
‘default’: DevelopmentConfig
}
加载方式
:
def create_app(config_name=’development’):
app = Flask(__name__)
app.config.from_object(config[config_name])
return app
2. 环境变量配置(12-Factor App原则)
12-Factor App原则推荐将配置存储在环境变量中,这是最安全、最灵活的方式。Flask可以轻松地从环境变量加载配置:
import os
class Config:
SECRET_KEY = os.environ.get(‘SECRET_KEY’)
if not SECRET_KEY:
raise ValueError(“No SECRET_KEY set for Flask application”)
SQLALCHEMY_DATABASE_URI = os.environ.get(‘DATABASE_URL’)
if not SQLALCHEMY_DATABASE_URI:
raise ValueError(“No DATABASE_URL set for Flask application”)
# 其他配置项
MAIL_SERVER = os.environ.get(‘MAIL_SERVER’)
MAIL_PORT = os.environ.get(‘MAIL_PORT’, 587)
MAIL_USE_TLS = os.environ.get(‘MAIL_USE_TLS’, True)
MAIL_USERNAME = os.environ.get(‘MAIL_USERNAME’)
MAIL_PASSWORD = os.environ.get(‘MAIL_PASSWORD’)
设置环境变量的方式
:
Linux/macOS
:
export SECRET_KEY=’your-secret-key’
export DATABASE_URL=’postgresql://user:pass@localhost/db’
python app.py
Windows
:
set SECRET_KEY=your-secret-key
set DATABASE_URL=postgresql://user:pass@localhost/db
python app.py
使用
.env
文件(推荐)
:
Flask支持通过
python-dotenv
自动加载
.env
文件中的环境变量:
pip install python-dotenv
.env
:
SECRET_KEY=dev-secret-key
DATABASE_URL=sqlite:///dev.db
DEBUG=True
app.py
:
from flask import Flask
from dotenv import load_dotenv
import os
# 加载.env文件
load_dotenv()
app = Flask(__name__)
app.config[‘SECRET_KEY’] = os.getenv(‘SECRET_KEY’)
app.config[‘SQLALCHEMY_DATABASE_URI’] = os.getenv(‘DATABASE_URL’)
app.config[‘DEBUG’] = os.getenv(‘DEBUG’, ‘False’).lower() == ‘true’
注意
:
.env
文件应该添加到
.gitignore
中,永远不要提交到版本控制系统。
高级配置管理:工厂模式与动态加载
1. 应用工厂模式
应用工厂模式是Flask配置管理的最佳实践之一,它允许你在创建应用实例时动态选择配置:
from flask import Flask
import os
def create_app(config_name=None):
“””
应用工厂函数
Args:
config_name: 配置名称,如 ‘development’, ‘production’, ‘testing’
如果为None,则从环境变量FLASK_ENV读取
“””
app = Flask(__name__)
# 确定配置名称
if config_name is None:
config_name = os.getenv(‘FLASK_ENV’, ‘development’)
# 从环境变量加载配置
if config_name == ‘production’:
from config import ProductionConfig
app.config.from_object(ProductionConfig)
elif config_name == ‘testing’:
from config import TestingConfig
app.config.from_object(TestingConfig)
else:
from config import DevelopmentConfig
app.config.from_object(DevelopmentConfig)
# 可以在这里初始化扩展
# db.init_app(app)
# migrate.init_app(app, db)
return app
2. 从配置对象动态加载
Flask的
config
对象支持从多种来源加载配置:
# 从字典加载
app.config.from_mapping({
‘SECRET_KEY’: ‘dev-key’,
‘DEBUG’: True
})
# 从配置类加载
app.config.from_object(‘config.DevelopmentConfig’)
# 从配置文件加载
app.config.from_pyfile(‘config.py’)
# 从环境变量前缀加载
app.config.from_envvar(‘FLASK_CONFIG_FILE’)
3. 配置优先级管理
Flask配置的加载遵循特定的优先级顺序(从高到低):
直接在
app.config
上设置的值
app.config.from_mapping()
加载的值
app.config.from_object()
加载的值
app.config.from_pyfile()
加载的值
app.config.from_envvar()
加载的值
理解这个优先级很重要,因为它决定了配置覆盖的顺序。例如:
app = Flask(__name__)
# 基础配置
app.config[‘SECRET_KEY’] = ‘base-key’
# 从类加载(会覆盖同名配置)
app.config.from_object(‘config.DevelopmentConfig’)
# 最终SECRET_KEY的值取决于DevelopmentConfig中是否定义了SECRET_KEY
生产环境安全配置:保护你的敏感数据
1. 密钥管理最佳实践
生产环境中的密钥(如
SECRET_KEY
、数据库密码、API密钥)必须严格保护:
错误的做法
:
# 永远不要这样做!
app.config[‘SECRET_KEY’] = ‘hardcoded-secret-key’
app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘postgresql://user:password@host/db’
正确的做法
:
import os
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
class ProductionConfig:
SECRET_KEY = os.environ.get(‘SECRET_KEY’)
if not SECRET_KEY:
raise ValueError(“SECRET_KEY environment variable is required”)
# 数据库配置
DB_HOST = os.environ.get(‘DB_HOST’, ‘localhost’)
DB_PORT = os.environ.get(‘DB_PORT’, ‘5432’)
DB_NAME = os.environ.get(‘DB_NAME’)
DB_USER = os.environ.get(‘DB_USER’)
DB_PASSWORD = os.environ.get(‘DB_PASSWORD’)
# 构建数据库URL
if all([DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD]):
SQLALCHEMY_DATABASE_URI = f”postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}”
else:
raise ValueError(“Database configuration environment variables are incomplete”)
# 其他敏感配置
AWS_ACCESS_KEY_ID = os.environ.get(‘AWS_ACCESS_KEY_ID’)
AWS_SECRET_ACCESS_KEY = os.environ.get(‘AWS_SECRET_ACCESS_KEY’)
STRIPE_API_KEY = os.environ.get(‘STRIPE_API_KEY’)
2. 使用密钥管理服务
对于生产环境,建议使用专业的密钥管理服务:
AWS Secrets Manager
:
import boto3
import json
from flask import Flask
def load_aws_secrets():
“””从AWS Secrets Manager加载配置”””
client = boto3.client(‘secretsmanager’)
secret_name = “myapp/production”
try:
response = client.get_secret_value(SecretId=secret_name)
secret = json.loads(response[‘SecretString’])
return secret
except Exception as e:
print(f”Error loading secrets: {e}”)
return {}
def create_app():
app = Flask(__name__)
# 加载AWS密钥
secrets = load_aws_secrets()
app.config.update(secrets)
return app
HashiCorp Vault
:
import hvac
import os
def load_vault_secrets():
“””从Vault加载配置”””
client = hvac.Client(
url=os.environ.get(‘VAULT_ADDR’),
token=os.environ.get(‘VAULT_TOKEN’)
)
secret = client.secrets.kv.v2.read_secret_version(
path=’myapp/production’
)
return secret[‘data’][‘data’]
def create_app():
app = Flask(__name__)
secrets = load_vault_secrets()
app.config.update(secrets)
return app
3. 配置加密与解密
对于必须存储在文件中的敏感配置,可以使用加密:
from cryptography.fernet import Fernet
import os
import base64
def encrypt_config_value(value, key):
“””加密配置值”””
f = Fernet(key)
return f.encrypt(value.encode()).decode()
def decrypt_config_value(encrypted_value, key):
“””解密配置值”””
f = Fernet(key)
return f.decrypt(encrypted_value.encode()).decode()
# 使用示例
# 生成密钥(只需执行一次)
# key = Fernet.generate_key()
# print(f”保存此密钥: {key.decode()}”)
# 加密敏感值
# encrypted_db_password = encrypt_config_value(‘my-secret-password’, key)
# 在应用中使用
# DECRYPTION_KEY = os.environ.get(‘DECRYPTION_KEY’)
# if DECRYPTION_KEY:
# db_password = decrypt_config_value(encrypted_db_password, DECRYPTION_KEY)
环境变量管理工具:简化配置管理
1. python-dotenv详解
python-dotenv
是最流行的环境变量管理工具之一:
pip install python-dotenv
基本用法
:
from dotenv import load_dotenv
import os
# 加载.env文件
load_dotenv()
# 现在可以通过os.getenv()访问环境变量
secret_key = os.getenv(‘SECRET_KEY’)
高级用法
:
from dotenv import load_dotenv, find_dotenv, dotenv_values
# 自动查找.env文件
env_path = find_dotenv(raise_error_if_not_found=True)
# 加载但不设置到os.environ
config = dotenv_values(env_path)
# 覆盖已存在的环境变量
load_dotenv(override=True)
.env文件示例
:
# .env (开发环境)
SECRET_KEY=dev-secret-key-change-in-production
DATABASE_URL=sqlite:///dev.db
DEBUG=True
FLASK_ENV=development
# 第三方API密钥
STRIPE_PUBLISHABLE_KEY=pk_test_123
STRIPE_SECRET_KEY=sk_test_123
2. python-decouple
python-decouple
提供了更强大的类型转换和默认值支持:
pip install python-decouple
from decouple import config
# 基本用法
SECRET_KEY = config(‘SECRET_KEY’)
# 带默认值
DEBUG = config(‘DEBUG’, default=False, cast=bool)
# 必需的配置项(如果不存在会抛出异常)
DATABASE_URL = config(‘DATABASE_URL’, cast=str)
# 类型转换
PORT = config(‘PORT’, default=5000, cast=int)
ALLOWED_HOSTS = config(‘ALLOWED_HOSTS’, cast=lambda v: [s.strip() for s in v.split(‘,’)])
# 从不同文件加载
# config = AutoConfig(‘config/’) # 从config/目录加载
3. dynaconf
dynaconf
是一个功能强大的配置管理库,支持多种格式和来源:
pip install dynaconf
from dynaconf import Dynaconf
settings = Dynaconf(
envvar_prefix=”MYAPP”,
settings_files=[‘settings.toml’, ‘secrets.toml’],
environments=True,
env_switcher=”MYAPP_ENV”
)
# 使用
SECRET_KEY = settings.SECRET_KEY
DATABASE_URL = settings.DATABASE_URL
settings.toml
:
[development]
debug = true
database_url = “sqlite:///dev.db”
[production]
debug = false
database_url = “postgresql://user:pass@localhost/prod_db”
完整的生产级配置示例
1. 项目结构
myapp/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ └── extensions.py
├── config/
│ ├── __init__.py
│ ├── development.py
│ ├── production.py
│ └── testing.py
├── migrations/
├── tests/
├── .env
├── .env.production
├── .gitignore
├── requirements.txt
├── manage.py
└── wsgi.py
2. 配置类定义
config/
init
.py
:
import os
from dotenv import load_dotenv
# 加载基础环境变量
load_dotenv()
class Config:
“””基础配置类”””
SECRET_KEY = os.environ.get(‘SECRET_KEY’) or ‘dev-key-fallback’
# 数据库
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 日志
LOG_LEVEL = os.environ.get(‘LOG_LEVEL’, ‘INFO’)
# 安全
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = ‘Lax’
# 邮件
MAIL_SERVER = os.environ.get(‘MAIL_SERVER’)
MAIL_PORT = os.environ.get(‘MAIL_PORT’, 587)
MAIL_USE_TLS = os.environ.get(‘MAIL_USE_TLS’, ‘True’).lower() == ‘true’
MAIL_USERNAME = os.environ.get(‘MAIL_USERNAME’)
MAIL_PASSWORD = os.environ.get(‘MAIL_PASSWORD’)
# 上传
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), ‘uploads’)
class DevelopmentConfig(Config):
“””开发环境配置”””
DEBUG = True
# 数据库
SQLALCHEMY_DATABASE_URI = os.environ.get(‘DATABASE_URL’) or ‘sqlite:///dev.db’
# 会话
SESSION_COOKIE_SECURE = False
# 日志
LOG_LEVEL = ‘DEBUG’
class TestingConfig(Config):
“””测试环境配置”””
TESTING = True
WTF_CSRF_ENABLED = False
# 数据库
SQLALCHEMY_DATABASE_URI = ‘sqlite:///:memory:’
# 禁用邮件发送
MAIL_SUPPRESS_SEND = True
class ProductionConfig(Config):
“””生产环境配置”””
DEBUG = False
# 数据库
SQLALCHEMY_DATABASE_URI = os.environ.get(‘DATABASE_URL’)
if not SQLALCHEMY_DATABASE_URI:
raise ValueError(“DATABASE_URL environment variable is required for production”)
# 安全
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = ‘Strict’
# 日志
LOG_LEVEL = os.environ.get(‘LOG_LEVEL’, ‘WARNING’)
# 生产环境必须设置的配置
if not os.environ.get(‘SECRET_KEY’):
raise ValueError(“SECRET_KEY environment variable is required for production”)
# 配置字典
config = {
‘development’: DevelopmentConfig,
‘testing’: TestingConfig,
‘production’: ProductionConfig,
‘default’: DevelopmentConfig
}
3. 应用工厂
app/
init
.py
:
from flask import Flask
from config import config
import os
import logging
from logging.handlers import RotatingFileHandler
def create_app(config_name=None):
“””
应用工厂函数
Args:
config_name: 配置名称,如 ‘development’, ‘production’, ‘testing’
如果为None,则从环境变量FLASK_ENV读取
“””
if config_name is None:
config_name = os.getenv(‘FLASK_ENV’, ‘development’)
app = Flask(__name__)
app.config.from_object(config[config_name])
# 初始化扩展
# db.init_app(app)
# migrate.init_app(app, db)
# login_manager.init_app(app)
# 配置日志
configure_logging(app)
# 注册蓝图
from app.routes import main_bp
app.register_blueprint(main_bp)
return app
def configure_logging(app):
“””配置日志”””
if not app.config[‘DEBUG’]:
# 生产环境日志配置
handler = RotatingFileHandler(
‘app.log’,
maxBytes=10240,
backupCount=10
)
handler.setLevel(app.config[‘LOG_LEVEL’])
formatter = logging.Formatter(
‘%(asctime)s – %(name)s – %(levelname)s – %(message)s’
)
handler.setFormatter(formatter)
app.logger.addHandler(handler)
4. 环境文件
.env
(开发环境):
# Flask
FLASK_ENV=development
FLASK_APP=manage.py
# Secret Key (开发环境,可以提交到仓库)
SECRET_KEY=dev-secret-key-change-in-production
# Database
DATABASE_URL=sqlite:///dev.db
# Logging
LOG_LEVEL=DEBUG
# API Keys (开发环境密钥)
STRIPE_PUBLISHABLE_KEY=pk_test_123
STRIPE_SECRET_KEY=sk_test_123
.env.production
(生产环境模板):
# Flask
FLASK_ENV=production
FLASK_APP=manage.py
# Secret Key (必须设置,且不能泄露)
SECRET_KEY=your-very-strong-secret-key-here
# Database
DATABASE_URL=postgresql://user:password@host:port/dbname
# Logging
LOG_LEVEL=WARNING
# API Keys
STRIPE_PUBLISHABLE_KEY=pk_live_…
STRIPE_SECRET_KEY=sk_live_…
# Email
MAIL_SERVER=smtp.gmail.com
MAIL_PORT=587
MAIL_USE_TLS=True
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
5. 启动脚本
manage.py
:
from app import create_app
import os
# 从环境变量读取配置名称
config_name = os.getenv(‘FLASK_ENV’, ‘development’)
app = create_app(config_name)
if __name__ == ‘__main__’:
app.run()
wsgi.py
(生产环境):
import os
from app import create_app
# 生产环境配置
app = create_app(‘production’)
if __name__ == ‘__main__’:
app.run()
6. .gitignore配置
.gitignore
:
# 环境变量文件
.env
.env.*
!.env.example
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Flask
instance/
.webassets-cache
# 日志
*.log
app.log
# 数据库
*.db
*.sqlite
*.sqlite3
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
测试与验证:确保配置正确工作
1. 配置测试
编写测试来验证配置加载是否正确:
import unittest
import os
from app import create_app
class TestConfig(unittest.TestCase):
def test_development_config(self):
“””测试开发环境配置”””
app = create_app(‘development’)
self.assertTrue(app.config[‘DEBUG’])
self.assertFalse(app.config[‘TESTING’])
self.assertEqual(app.config[‘SQLALCHEMY_DATABASE_URI’], ‘sqlite:///dev.db’)
def test_production_config(self):
“””测试生产环境配置”””
# 设置必要的环境变量
os.environ[‘SECRET_KEY’] = ‘test-secret’
os.environ[‘DATABASE_URL’] = ‘postgresql://test:test@localhost/test’
app = create_app(‘production’)
self.assertFalse(app.config[‘DEBUG’])
self.assertTrue(app.config[‘SESSION_COOKIE_SECURE’])
# 清理环境变量
del os.environ[‘SECRET_KEY’]
del os.environ[‘DATABASE_URL’]
def test_config_from_env(self):
“””测试从环境变量加载配置”””
os.environ[‘FLASK_ENV’] = ‘testing’
app = create_app()
self.assertTrue(app.config[‘TESTING’])
del os.environ[‘FLASK_ENV’]
if __name__ == ‘__main__’:
unittest.main()
2. 配置验证脚本
创建一个配置验证脚本,用于部署前检查:
#!/usr/bin/env python
“””
配置验证脚本
在部署前运行此脚本,确保所有必需的环境变量都已设置
“””
import os
import sys
# 必需的环境变量列表
REQUIRED_VARS = [
‘SECRET_KEY’,
‘DATABASE_URL’,
]
# 可选但推荐的环境变量
RECOMMENDED_VARS = [
‘MAIL_SERVER’,
‘MAIL_USERNAME’,
‘AWS_ACCESS_KEY_ID’,
]
def validate_config():
“””验证配置”””
errors = []
warnings = []
print(“🔍 验证配置…”)
# 检查必需变量
for var in REQUIRED_VARS:
if not os.environ.get(var):
errors.append(f”❌ 缺少必需的环境变量: {var}”)
else:
print(f”✅ {var} 已设置”)
# 检查推荐变量
for var in RECOMMENDED_VARS:
if not os.environ.get(var):
warnings.append(f”⚠️ 建议设置环境变量: {var}”)
else:
print(f”✅ {var} 已设置”)
# 输出结果
if errors:
print(“\n❌ 配置验证失败:”)
for error in errors:
print(f” {error}”)
return False
if warnings:
print(“\n⚠️ 配置警告:”)
for warning in warnings:
print(f” {warning}”)
print(“\n✅ 配置验证通过!”)
return True
if __name__ == ‘__main__’:
success = validate_config()
sys.exit(0 if success else 1)
部署策略:不同环境的配置管理
1. Docker部署
Dockerfile
:
FROM python:3.9-slim
WORKDIR /app
# 复制依赖
COPY requirements.txt .
RUN pip install –no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 不复制.env文件,通过环境变量传入
# 设置默认环境变量
ENV FLASK_ENV=production
ENV PYTHONUNBUFFERED=1
# 暴露端口
EXPOSE 5000
# 启动命令
CMD [“gunicorn”, “-w”, “4”, “-b”, “0.0.0.0:5000”, “wsgi:app”]
docker-compose.yml
:
version: ‘3.8’
services:
web:
build: .
ports:
– “8000:5000”
environment:
– FLASK_ENV=production
– SECRET_KEY=${SECRET_KEY}
– DATABASE_URL=${DATABASE_URL}
– MAIL_SERVER=${MAIL_SERVER}
– MAIL_USERNAME=${MAIL_USERNAME}
– MAIL_PASSWORD=${MAIL_PASSWORD}
env_file:
– .env.production
depends_on:
– db
restart: unless-stopped
db:
image: postgres:13
environment:
POSTGRES_DB: myapp
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
– postgres_data:/var/lib/postgresql/data
ports:
– “5432:5432″
volumes:
postgres_data:
2. Systemd部署
/etc/systemd/system/myapp.service
:
[Unit]
Description=My Flask Application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/myapp
Environment=”PATH=/opt/myapp/venv/bin”
EnvironmentFile=/etc/myapp/env
ExecStart=/opt/myapp/venv/bin/gunicorn -w 4 -b 0.0.0.0:8000 wsgi:app
Restart=always
[Install]
WantedBy=multi-user.target
/etc/myapp/env
:
FLASK_ENV=production
SECRET_KEY=your-secret-key
DATABASE_URL=postgresql://user:pass@localhost/db
3. Nginx + Gunicorn配置
nginx.conf
:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ {
alias /opt/myapp/static/;
expires 30d;
}
}
常见陷阱与解决方案
1. 硬编码敏感信息
问题
:将密码、密钥直接写在代码中。
解决方案
:使用环境变量,代码中只使用
os.environ.get()
。
2. 配置文件提交到Git
问题
:
.env
文件包含敏感信息但被提交到仓库。
解决方案
:
将
.env
添加到
.gitignore
创建
.env.example
模板文件
使用
.env.local
覆盖本地配置
3. 环境变量命名冲突
问题
:不同服务使用相同的环境变量名。
解决方案
:使用前缀,如
MYAPP_SECRET_KEY
。
4. 配置优先级混乱
问题
:不清楚哪个配置会生效。
解决方案
:明确配置加载顺序,使用
app.config.from_*()
方法时注意优先级。
5. 生产环境使用开发配置
问题
:忘记切换配置,导致生产环境使用开发配置。
解决方案
:
使用不同的环境变量文件
在应用启动时验证配置
使用CI/CD流程强制检查
总结与最佳实践清单
✅ 配置管理最佳实践清单
永远不要硬编码敏感信息
使用环境变量
使用密钥管理服务
分离配置与代码
使用配置类
使用环境变量文件
使用应用工厂模式
支持多环境配置
便于测试
版本控制策略
提交
.env.example
模板
忽略
.env
文件
使用
.gitignore
正确配置
生产环境安全
使用HTTPS
设置安全的Cookie标志
定期轮换密钥
文档化配置
记录所有必需的环境变量
提供配置示例
自动化验证
部署前验证配置
编写配置测试
监控与日志
记录配置加载情况
监控敏感操作
快速开始模板
# 1. 创建项目结构
mkdir myapp && cd myapp
python -m venv venv
source venv/bin/activate # Linux/macOS
# venv\Scripts\activate # Windows
# 2. 安装依赖
pip install flask python-dotenv
# 3. 创建基本文件
mkdir app config
touch app/__init__.py config/__init__.py .env .env.example .gitignore manage.py
# 4. 编写代码(参考上文示例)
# 5. 测试配置
FLASK_ENV=development python manage.py
# 6. 准备生产环境
cp .env .env.production
# 编辑 .env.production,设置真实配置
通过遵循这些最佳实践,你可以构建一个安全、灵活、可维护的Flask配置管理体系,确保你的应用在任何环境中都能正确运行,同时保护敏感信息不被泄露。记住,好的配置管理是生产级应用的基础。