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 文件、变量替换、多环境配置等功能,可以实现灵活、安全的应用配置管理。

关键要点:

  1. 使用 .env 文件集中管理配置
  2. 为不同环境创建专门的配置文件
  3. 使用变量替换和默认值提高灵活性
  4. 妥善管理敏感信息,避免泄露
  5. 建立清晰的命名规范和文件组织结构
  6. 实施环境变量验证和调试机制

正确的环境变量管理是构建可维护、可扩展的容器化应用的基础。

powered by Gitbook© 2025 编外计划 | 最后修改: 2025-08-29 15:40:15

results matching ""

    No results matching ""