本文目录导读:

我来为你详细介绍如何编写适配容器运行环境的代码,包括最佳实践和代码示例。
环境变量配置
配置文件示例
# config.yaml - 容器环境配置
app:
name: my-app
version: 1.0.0
database:
host: ${DB_HOST:-localhost}
port: ${DB_PORT:-5432}
username: ${DB_USER:-admin}
password: ${DB_PASSWORD}
database: ${DB_NAME:-myapp}
redis:
host: ${REDIS_HOST:-localhost}
port: ${REDIS_PORT:-6379}
password: ${REDIS_PASSWORD:-}
logging:
level: ${LOG_LEVEL:-info}
format: ${LOG_FORMAT:-json}
Python 示例
import os
import logging
from dotenv import load_dotenv
class Config:
"""容器环境配置管理"""
def __init__(self):
# 尝试加载 .env 文件(本地开发)
load_dotenv()
# 应用配置
self.app_name = os.getenv('APP_NAME', 'my-app')
self.debug = os.getenv('DEBUG', 'false').lower() == 'true'
# 数据库配置
self.db_config = {
'host': os.getenv('DB_HOST', 'localhost'),
'port': int(os.getenv('DB_PORT', '5432')),
'username': os.getenv('DB_USER', 'admin'),
'password': os.getenv('DB_PASSWORD', ''),
'database': os.getenv('DB_NAME', 'myapp')
}
# Redis 配置
self.redis_config = {
'host': os.getenv('REDIS_HOST', 'localhost'),
'port': int(os.getenv('REDIS_PORT', '6379')),
'password': os.getenv('REDIS_PASSWORD', '')
}
# 服务发现配置
self.service_discovery = os.getenv('SERVICE_DISCOVERY', 'dns').lower()
def get_database_url(self):
"""获取数据库连接URL"""
return (f"postgresql://{self.db_config['username']}:"
f"{self.db_config['password']}@"
f"{self.db_config['host']}:{self.db_config['port']}/"
f"{self.db_config['database']}")
# 初始化配置
config = Config()
logger = logging.getLogger(__name__)
服务发现与连接
Docker Compose 服务发现示例
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- DB_HOST=postgres
- REDIS_HOST=redis
- SERVICE_DISCOVERY=dns
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
postgres:
image: postgres:15
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
健康检查与重试机制
import time
import random
from functools import wraps
import logging
logger = logging.getLogger(__name__)
def retry_connection(max_retries=5, base_delay=1, backoff=2):
"""连接重试装饰器"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
last_exception = None
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
last_exception = e
if attempt < max_retries - 1:
delay = base_delay * (backoff ** attempt)
jitter = random.uniform(0, delay * 0.1)
total_delay = delay + jitter
logger.warning(
f"Connection attempt {attempt + 1}/{max_retries} failed: {e}. "
f"Retrying in {total_delay:.2f}s"
)
time.sleep(total_delay)
logger.error(f"All {max_retries} connection attempts failed")
raise last_exception
return wrapper
return decorator
class DatabaseConnector:
"""数据库连接器(支持容器环境)"""
def __init__(self, config):
self.config = config
self.connection = None
@retry_connection(max_retries=5)
def connect(self):
"""连接到数据库"""
import psycopg2
self.connection = psycopg2.connect(
host=self.config.db_config['host'],
port=self.config.db_config['port'],
user=self.config.db_config['username'],
password=self.config.db_config['password'],
database=self.config.db_config['database'],
connect_timeout=5 # 设置连接超时
)
# 验证连接
with self.connection.cursor() as cursor:
cursor.execute("SELECT 1")
result = cursor.fetchone()
logger.info("Database connection established successfully")
return self.connection
def disconnect(self):
"""断开连接"""
if self.connection and not self.connection.closed:
self.connection.close()
logger.info("Database connection closed")
# 健康检查端点
def health_check():
"""健康检查函数"""
health_status = {
'status': 'healthy',
'checks': {}
}
# 检查数据库连接
try:
if db_connector.connection and not db_connector.connection.closed:
health_status['checks']['database'] = 'connected'
else:
health_status['checks']['database'] = 'disconnected'
health_status['status'] = 'unhealthy'
except Exception as e:
health_status['checks']['database'] = f'error: {str(e)}'
health_status['status'] = 'unhealthy'
return health_status
优雅关闭与信号处理
import signal
import sys
import asyncio
class GracefulShutdown:
"""优雅关闭处理器"""
def __init__(self):
self.shutdown_requested = False
self.shutdown_tasks = []
# 注册信号处理器
signal.signal(signal.SIGTERM, self.handle_signal)
signal.signal(signal.SIGINT, self.handle_signal)
def register_shutdown_task(self, task, name=None):
"""注册关闭任务"""
self.shutdown_tasks.append({
'task': task,
'name': name or f'task_{len(self.shutdown_tasks)}'
})
def handle_signal(self, signum, frame):
"""处理关闭信号"""
signal_name = signal.Signals(signum).name
logger.info(f"Received signal: {signal_name}")
if self.shutdown_requested:
logger.warning("Force shutdown requested")
sys.exit(1)
self.shutdown_requested = True
asyncio.create_task(self.graceful_shutdown())
async def graceful_shutdown(self, timeout=30):
"""优雅关闭"""
logger.info("Starting graceful shutdown...")
# 设置关闭超时
shutdown_timeout = time.time() + timeout
# 执行关闭任务
for task in reversed(self.shutdown_tasks):
remaining_time = shutdown_timeout - time.time()
if remaining_time <= 0:
logger.warning(f"Shutdown timeout reached for task: {task['name']}")
break
try:
await asyncio.wait_for(
task['task'](),
timeout=remaining_time
)
logger.info(f"Task '{task['name']}' completed shutdown")
except asyncio.TimeoutError:
logger.warning(f"Task '{task['name']}' shutdown timeout")
except Exception as e:
logger.error(f"Task '{task['name']}' shutdown error: {e}")
logger.info("Graceful shutdown completed")
sys.exit(0)
# 使用示例
def init_app():
"""初始化应用"""
shutdown_handler = GracefulShutdown()
# 注册关闭任务
shutdown_handler.register_shutdown_task(
db_connector.disconnect,
name='database_disconnect'
)
# 启动应用
logger.info("Application started in container environment")
# 保持运行
try:
asyncio.get_event_loop().run_forever()
except KeyboardInterrupt:
pass
Dockerfile 优化
# Dockerfile 多阶段构建
FROM python:3.11-slim as builder
WORKDIR /app
# 安装构建依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 复制并安装依赖
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# 第二阶段:运行环境
FROM python:3.11-slim
WORKDIR /app
# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 复制依赖和代码
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser . .
# 设置环境变量
ENV PATH=/home/appuser/.local/bin:$PATH \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8080/health')"
# 切换为非root用户
USER appuser
# 启动命令
CMD ["python", "app.py"]
日志与监控
import json
import logging
from datetime import datetime
class ContainerLogger:
"""容器日志处理器"""
def __init__(self, name='app'):
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.INFO)
# JSON 格式日志(适合容器环境)
handler = logging.StreamHandler()
handler.setFormatter(ContainerJsonFormatter())
self.logger.addHandler(handler)
def info(self, message, extra=None):
self._log(logging.INFO, message, extra)
def error(self, message, extra=None):
self._log(logging.ERROR, message, extra)
def _log(self, level, message, extra=None):
log_data = {
'message': message,
'timestamp': datetime.utcnow().isoformat(),
'level': logging.getLevelName(level),
}
if extra:
log_data.update(extra)
self.logger.log(level, json.dumps(log_data))
class ContainerJsonFormatter(logging.Formatter):
"""JSON 格式日志格式化器"""
def format(self, record):
log_data = {
'timestamp': datetime.utcnow().isoformat(),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
'line': record.lineno
}
# 添加异常信息
if record.exc_info:
log_data['exception'] = self.formatException(record.exc_info)
return json.dumps(log_data)
# 指标收集
class ContainerMetrics:
"""容器指标收集"""
def __init__(self):
self.metrics = {}
def increment_counter(self, name, value=1):
"""增加计数器"""
if name not in self.metrics:
self.metrics[name] = 0
self.metrics[name] += value
def record_gauge(self, name, value):
"""记录指标值"""
self.metrics[name] = value
def get_metrics(self):
"""获取所有指标"""
return {
'metrics': self.metrics,
'timestamp': datetime.utcnow().isoformat()
}
环境适配最佳实践
配置文件模板
# application.yml
server:
port: ${SERVER_PORT:8080}
graceful_shutdown_timeout: 30
spring:
profiles:
active: ${SPRING_PROFILES_ACTIVE:default}
database:
url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
pool:
min: ${DB_POOL_MIN:2}
max: ${DB_POOL_MAX:10}
logging:
level:
root: ${LOG_LEVEL:INFO}
pattern:
console: ${LOG_PATTERN:json}
management:
endpoints:
web:
exposure:
include: health,metrics,info
health:
readinessstate:
enabled: true
通过以上代码示例和最佳实践,你的应用将能够很好地适应容器运行环境,关键点包括:
- 使用环境变量配置
- 实现服务发现和健康检查
- 处理优雅关闭
- 优化容器镜像
- 使用结构化日志
- 实现指标监控
这些实践将确保你的应用在 Kubernetes、Docker Swarm 等容器编排平台上运行良好。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播