Docker Compose 环境变量管理
概述
环境变量是配置容器化应用程序的重要方式,它们允许在不修改代码的情况下改变应用程序的行为。Docker Compose 提供了多种方式来管理环境变量,包括 .env 文件、变量替换、多环境配置等。本文将详细介绍这些功能的使用方法。
环境变量基础
1. 在 Compose 文件中直接定义
version: '3.8'
services:
web:
image: nginx
environment:
- NGINX_HOST=example.com
- NGINX_PORT=80
- DEBUG=true
# 或使用映射格式
environment:
NGINX_HOST: example.com
NGINX_PORT: 80
DEBUG: "true" # 注意:所有值都是字符串
2. 从主机环境继承
services:
app:
image: myapp
environment:
- NODE_ENV # 从主机环境继承
- DATABASE_URL=${DATABASE_URL} # 变量替换
- API_KEY=${API_KEY:-default_key} # 带默认值
.env 文件
1. 基本 .env 文件
创建 .env 文件(与 docker-compose.yml 同目录):
# .env
# 应用配置
APP_NAME=MyApplication
APP_VERSION=1.0.0
APP_ENV=production
DEBUG=false
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=postgres
DB_PASSWORD=secretpassword
# Redis 配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=redispassword
# API 配置
API_URL=https://api.example.com
API_KEY=your-api-key
API_TIMEOUT=30
# 端口配置
WEB_PORT=80
API_PORT=3000
DB_PORT_EXTERNAL=5432
2. 在 Compose 文件中使用 .env 变量
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "${WEB_PORT}:80"
environment:
- APP_NAME=${APP_NAME}
- APP_VERSION=${APP_VERSION}
api:
build: .
ports:
- "${API_PORT}:3000"
environment:
- NODE_ENV=${APP_ENV}
- DEBUG=${DEBUG}
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:${DB_PORT}/${DB_NAME}
- REDIS_URL=redis://:${REDIS_PASSWORD}@redis:${REDIS_PORT}
- API_URL=${API_URL}
- API_KEY=${API_KEY}
depends_on:
- db
- redis
db:
image: postgres:13
ports:
- "${DB_PORT_EXTERNAL}:5432"
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:6-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
ports:
- "${REDIS_PORT}:6379"
volumes:
postgres_data:
3. 多个 .env 文件
services:
app:
image: myapp
env_file:
- .env # 基础配置
- .env.local # 本地覆盖
- ./config/.env.prod # 生产环境配置
文件示例
# .env (基础配置)
APP_NAME=MyApp
DEBUG=false
LOG_LEVEL=info
# .env.local (本地开发覆盖)
DEBUG=true
LOG_LEVEL=debug
DATABASE_URL=postgresql://localhost:5432/myapp_dev
# .env.prod (生产环境)
DATABASE_URL=postgresql://prod-db:5432/myapp
REDIS_URL=redis://prod-redis:6379
API_URL=https://api.production.com
变量替换和默认值
1. 基本变量替换
services:
app:
image: myapp:${TAG}
ports:
- "${PORT}:3000"
environment:
- DATABASE_URL=${DATABASE_URL}
2. 默认值
services:
app:
image: myapp:${TAG:-latest} # 默认值为 latest
ports:
- "${PORT:-3000}:3000" # 默认端口 3000
environment:
- NODE_ENV=${NODE_ENV:-development}
- LOG_LEVEL=${LOG_LEVEL:-info}
- MAX_CONNECTIONS=${MAX_CONNECTIONS:-100}
3. 必需变量
services:
app:
image: myapp
environment:
- DATABASE_URL=${DATABASE_URL:?DATABASE_URL is required}
- API_KEY=${API_KEY:?API_KEY must be set}
4. 变量替换示例
# .env
APP_NAME=myapp
ENVIRONMENT=production
VERSION=1.2.3
REPLICAS=3
version: '3.8'
services:
app:
image: ${APP_NAME}:${VERSION}
deploy:
replicas: ${REPLICAS}
environment:
- APP_ENV=${ENVIRONMENT}
- SERVICE_NAME=${APP_NAME}-${ENVIRONMENT}
- BUILD_DATE=${BUILD_DATE:-$(date)}
多环境配置
1. 环境特定的 Compose 文件
docker-compose.yml (基础配置)
version: '3.8'
services:
app:
build: .
environment:
- NODE_ENV=${NODE_ENV:-development}
volumes:
- .:/usr/src/app
depends_on:
- db
db:
image: postgres:13
environment:
- POSTGRES_DB=${DB_NAME:-myapp}
- POSTGRES_USER=${DB_USER:-postgres}
- POSTGRES_PASSWORD=${DB_PASSWORD:-password}
docker-compose.override.yml (开发环境覆盖)
version: '3.8'
services:
app:
ports:
- "3000:3000"
environment:
- DEBUG=true
- LOG_LEVEL=debug
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
db:
ports:
- "5432:5432"
volumes:
- postgres_dev_data:/var/lib/postgresql/data
volumes:
postgres_dev_data:
docker-compose.prod.yml (生产环境)
version: '3.8'
services:
app:
image: myapp:${VERSION}
restart: always
environment:
- NODE_ENV=production
- DEBUG=false
deploy:
replicas: 3
resources:
limits:
memory: 512M
reservations:
memory: 256M
db:
restart: always
volumes:
- postgres_prod_data:/var/lib/postgresql/data
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
volumes:
postgres_prod_data:
external: true
2. 环境特定的 .env 文件
# .env.development
NODE_ENV=development
DEBUG=true
LOG_LEVEL=debug
DATABASE_URL=postgresql://postgres:password@localhost:5432/myapp_dev
REDIS_URL=redis://localhost:6379
API_URL=http://localhost:3000
# .env.staging
NODE_ENV=staging
DEBUG=false
LOG_LEVEL=info
DATABASE_URL=postgresql://user:pass@staging-db:5432/myapp_staging
REDIS_URL=redis://staging-redis:6379
API_URL=https://api.staging.example.com
# .env.production
NODE_ENV=production
DEBUG=false
LOG_LEVEL=warn
DATABASE_URL=postgresql://user:pass@prod-db:5432/myapp
REDIS_URL=redis://prod-redis:6379
API_URL=https://api.example.com
3. 使用脚本管理环境
deploy.sh
#!/bin/bash
ENVIRONMENT=${1:-development}
case $ENVIRONMENT in
development)
echo "Deploying to development environment..."
cp .env.development .env
docker-compose up -d
;;
staging)
echo "Deploying to staging environment..."
cp .env.staging .env
docker-compose -f docker-compose.yml -f docker-compose.staging.yml up -d
;;
production)
echo "Deploying to production environment..."
cp .env.production .env
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
;;
*)
echo "Unknown environment: $ENVIRONMENT"
echo "Usage: $0 [development|staging|production]"
exit 1
;;
esac
敏感信息管理
1. 使用 Docker Secrets (Swarm 模式)
version: '3.8'
services:
app:
image: myapp
secrets:
- db_password
- api_key
environment:
- DATABASE_PASSWORD_FILE=/run/secrets/db_password
- API_KEY_FILE=/run/secrets/api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true
2. 外部密钥管理
services:
app:
image: myapp
environment:
- VAULT_ADDR=${VAULT_ADDR}
- VAULT_TOKEN=${VAULT_TOKEN}
command: |
sh -c '
export DATABASE_PASSWORD=$$(vault kv get -field=password secret/database)
export API_KEY=$$(vault kv get -field=key secret/api)
exec node server.js
'
3. 运行时密钥注入
#!/bin/bash
# start.sh
# 从外部密钥管理系统获取密钥
DATABASE_PASSWORD=$(aws secretsmanager get-secret-value --secret-id prod/db/password --query SecretString --output text)
API_KEY=$(aws secretsmanager get-secret-value --secret-id prod/api/key --query SecretString --output text)
# 导出环境变量
export DATABASE_PASSWORD
export API_KEY
# 启动应用
docker-compose up -d
环境变量验证
1. 启动前验证
services:
app:
image: myapp
environment:
- NODE_ENV=${NODE_ENV:?NODE_ENV is required}
- DATABASE_URL=${DATABASE_URL:?DATABASE_URL is required}
- API_KEY=${API_KEY:?API_KEY is required}
healthcheck:
test: ["CMD", "node", "health-check.js"]
interval: 30s
timeout: 10s
retries: 3
2. 应用内验证
// health-check.js
const requiredEnvVars = [
'NODE_ENV',
'DATABASE_URL',
'API_KEY',
'REDIS_URL'
];
const missingVars = requiredEnvVars.filter(varName => !process.env[varName]);
if (missingVars.length > 0) {
console.error('Missing required environment variables:', missingVars);
process.exit(1);
}
console.log('All required environment variables are set');
process.exit(0);
调试和故障排除
1. 查看环境变量
# 查看服务的环境变量
docker-compose exec app env
# 查看特定变量
docker-compose exec app echo $NODE_ENV
# 验证 .env 文件加载
docker-compose config
2. 环境变量调试
services:
debug:
image: alpine
environment:
- DEBUG_VAR=${DEBUG_VAR:-not_set}
command: |
sh -c '
echo "Environment variables:"
env | sort
echo "\nSpecific variables:"
echo "DEBUG_VAR: $$DEBUG_VAR"
echo "NODE_ENV: $$NODE_ENV"
'
3. 变量替换测试
# 测试变量替换
docker-compose config
# 查看解析后的配置
docker-compose config --resolve-image-digests
# 验证特定服务配置
docker-compose config --services
最佳实践
1. 文件组织
project/
├── docker-compose.yml
├── docker-compose.override.yml
├── docker-compose.prod.yml
├── .env
├── .env.example
├── .env.local
├── .gitignore
└── scripts/
├── deploy.sh
└── env-setup.sh
2. .env.example 模板
# .env.example
# 复制此文件为 .env 并填入实际值
# 应用配置
APP_NAME=myapp
APP_VERSION=1.0.0
NODE_ENV=development
DEBUG=true
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=postgres
DB_PASSWORD=your_password_here
# Redis 配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
# API 配置
API_URL=https://api.example.com
API_KEY=your_api_key_here
# 端口配置
WEB_PORT=80
API_PORT=3000
3. .gitignore 配置
# 环境变量文件
.env
.env.local
.env.production
.env.staging
# 但保留示例文件
!.env.example
# 密钥文件
secrets/
*.key
*.pem
4. 环境变量命名规范
# 使用一致的命名规范
APP_NAME=myapp
APP_VERSION=1.0.0
APP_ENV=production
# 数据库相关
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=postgres
DB_PASSWORD=password
# 服务相关
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=password
# API 相关
API_BASE_URL=https://api.example.com
API_KEY=secret_key
API_TIMEOUT=30
# 功能开关
FEATURE_NEW_UI=true
FEATURE_ANALYTICS=false
5. 安全建议
- 永远不要将包含敏感信息的 .env 文件提交到版本控制
- 使用 .env.example 作为模板
- 在生产环境中使用外部密钥管理系统
- 定期轮换密钥和密码
- 使用最小权限原则
6. 验证脚本
#!/bin/bash
# validate-env.sh
required_vars=(
"APP_NAME"
"NODE_ENV"
"DATABASE_URL"
"API_KEY"
)
missing_vars=()
for var in "${required_vars[@]}"; do
if [[ -z "${!var}" ]]; then
missing_vars+=("$var")
fi
done
if [[ ${#missing_vars[@]} -ne 0 ]]; then
echo "Error: Missing required environment variables:"
printf ' - %s\n' "${missing_vars[@]}"
exit 1
fi
echo "All required environment variables are set."
总结
环境变量是 Docker Compose 应用配置的核心机制。通过合理使用 .env 文件、变量替换、多环境配置等功能,可以实现灵活、安全的应用配置管理。
关键要点:
- 使用 .env 文件集中管理配置
- 为不同环境创建专门的配置文件
- 使用变量替换和默认值提高灵活性
- 妥善管理敏感信息,避免泄露
- 建立清晰的命名规范和文件组织结构
- 实施环境变量验证和调试机制
正确的环境变量管理是构建可维护、可扩展的容器化应用的基础。