# 容器化部署
## 🎯 学习目标
通过本章学习,您将能够:
- 理解现代容器化技术的核心概念和优势
- 掌握Docker容器化和Kubernetes编排技术
- 学会为Chat-Room项目设计容器化部署方案
- 实现自动化部署和运维管理流程
## 🐳 容器化架构
### 容器化技术栈
```mermaid
graph TB
subgraph "容器化技术栈"
A[应用层
Application Layer] --> A1[Chat-Room服务
Chat-Room Services]
A --> A2[Web界面
Web Interface]
A --> A3[API网关
API Gateway]
B[容器层
Container Layer] --> B1[Docker容器
Docker Containers]
B --> B2[容器镜像
Container Images]
B --> B3[容器网络
Container Network]
C[编排层
Orchestration Layer] --> C1[Kubernetes
K8s Cluster]
C --> C2[Docker Compose
Local Development]
C --> C3[服务发现
Service Discovery]
D[基础设施层
Infrastructure Layer] --> D1[云平台
Cloud Platform]
D --> D2[虚拟机
Virtual Machines]
D --> D3[物理服务器
Physical Servers]
end
A --> B
B --> C
C --> D
style A fill:#e8f5e8
style D fill:#f8d7da
```
### 部署架构图
```mermaid
graph LR
subgraph "开发环境"
A[开发者
Developer] --> B[Git仓库
Git Repository]
end
subgraph "CI/CD流水线"
B --> C[构建
Build]
C --> D[测试
Test]
D --> E[打包
Package]
E --> F[镜像仓库
Image Registry]
end
subgraph "部署环境"
F --> G[Kubernetes集群
K8s Cluster]
G --> H[Chat-Room服务
Chat-Room Services]
G --> I[数据库
Database]
G --> J[监控系统
Monitoring]
end
style A fill:#e8f5e8
style G fill:#fff3cd
style H fill:#f8d7da
```
## 🔧 容器化实现
### Chat-Room Docker配置
```dockerfile
# Dockerfile - Chat-Room服务容器化
FROM python:3.11-slim
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
g++ \
make \
libffi-dev \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
COPY requirements-dev.txt .
# 安装Python依赖
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建非root用户
RUN groupadd -r chatroom && useradd -r -g chatroom chatroom
RUN chown -R chatroom:chatroom /app
USER chatroom
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8000/health')" || exit 1
# 暴露端口
EXPOSE 8000 8001
# 启动命令
CMD ["python", "-m", "server.main"]
```
```yaml
# docker-compose.yml - 本地开发环境
version: '3.8'
services:
# Chat-Room服务器
chatroom-server:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
- "8001:8001"
environment:
- DATABASE_URL=postgresql://chatroom:password@postgres:5432/chatroom
- REDIS_URL=redis://redis:6379/0
- LOG_LEVEL=INFO
volumes:
- ./logs:/app/logs
- ./config:/app/config
depends_on:
- postgres
- redis
networks:
- chatroom-network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# PostgreSQL数据库
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_DB=chatroom
- POSTGRES_USER=chatroom
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "5432:5432"
networks:
- chatroom-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U chatroom"]
interval: 10s
timeout: 5s
retries: 5
# Redis缓存
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- chatroom-network
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# Nginx反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/ssl:/etc/nginx/ssl
- ./static:/var/www/static
depends_on:
- chatroom-server
networks:
- chatroom-network
restart: unless-stopped
# 监控系统
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
networks:
- chatroom-network
restart: unless-stopped
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
- ./monitoring/grafana:/etc/grafana/provisioning
depends_on:
- prometheus
networks:
- chatroom-network
restart: unless-stopped
volumes:
postgres_data:
redis_data:
prometheus_data:
grafana_data:
networks:
chatroom-network:
driver: bridge
```
### Kubernetes部署配置
```yaml
# k8s/namespace.yaml - 命名空间
apiVersion: v1
kind: Namespace
metadata:
name: chatroom
labels:
name: chatroom
environment: production
---
# k8s/configmap.yaml - 配置映射
apiVersion: v1
kind: ConfigMap
metadata:
name: chatroom-config
namespace: chatroom
data:
DATABASE_URL: "postgresql://chatroom:password@postgres-service:5432/chatroom"
REDIS_URL: "redis://redis-service:6379/0"
LOG_LEVEL: "INFO"
MAX_CONNECTIONS: "1000"
WORKER_PROCESSES: "4"
---
# k8s/secret.yaml - 密钥管理
apiVersion: v1
kind: Secret
metadata:
name: chatroom-secrets
namespace: chatroom
type: Opaque
data:
database-password: cGFzc3dvcmQ= # base64编码的password
jwt-secret: c2VjcmV0LWtleQ== # base64编码的secret-key
api-key: YXBpLWtleS12YWx1ZQ== # base64编码的api-key-value
---
# k8s/deployment.yaml - 应用部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: chatroom-server
namespace: chatroom
labels:
app: chatroom-server
version: v1.0.0
spec:
replicas: 3
selector:
matchLabels:
app: chatroom-server
template:
metadata:
labels:
app: chatroom-server
version: v1.0.0
spec:
containers:
- name: chatroom-server
image: chatroom/server:latest
ports:
- containerPort: 8000
name: http
- containerPort: 8001
name: websocket
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: chatroom-config
key: DATABASE_URL
- name: REDIS_URL
valueFrom:
configMapKeyRef:
name: chatroom-config
key: REDIS_URL
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: chatroom-secrets
key: database-password
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumeMounts:
- name: config-volume
mountPath: /app/config
- name: logs-volume
mountPath: /app/logs
volumes:
- name: config-volume
configMap:
name: chatroom-config
- name: logs-volume
emptyDir: {}
restartPolicy: Always
---
# k8s/service.yaml - 服务定义
apiVersion: v1
kind: Service
metadata:
name: chatroom-service
namespace: chatroom
labels:
app: chatroom-server
spec:
selector:
app: chatroom-server
ports:
- name: http
port: 80
targetPort: 8000
protocol: TCP
- name: websocket
port: 8001
targetPort: 8001
protocol: TCP
type: ClusterIP
---
# k8s/ingress.yaml - 入口控制器
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: chatroom-ingress
namespace: chatroom
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/websocket-services: chatroom-service
spec:
tls:
- hosts:
- chat.example.com
secretName: chatroom-tls
rules:
- host: chat.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: chatroom-service
port:
number: 80
- path: /ws
pathType: Prefix
backend:
service:
name: chatroom-service
port:
number: 8001
---
# k8s/hpa.yaml - 水平自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: chatroom-hpa
namespace: chatroom
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: chatroom-server
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 50
periodSeconds: 60
```
### 部署脚本
```python
# deploy/deployment_manager.py - 部署管理器
import subprocess
import yaml
import json
import time
from typing import Dict, List, Any, Optional
from pathlib import Path
import logging
class DeploymentManager:
"""
部署管理器
功能:
1. Docker镜像构建和推送
2. Kubernetes资源部署
3. 部署状态监控
4. 回滚和故障恢复
"""
def __init__(self, config_path: str = "deploy/config.yaml"):
self.config_path = Path(config_path)
self.config = self._load_config()
self.logger = self._setup_logging()
def _load_config(self) -> Dict[str, Any]:
"""加载部署配置"""
if self.config_path.exists():
with open(self.config_path, 'r') as f:
return yaml.safe_load(f)
# 默认配置
return {
"docker": {
"registry": "docker.io",
"repository": "chatroom",
"tag": "latest"
},
"kubernetes": {
"namespace": "chatroom",
"context": "default"
}
}
def _setup_logging(self) -> logging.Logger:
"""设置日志"""
logger = logging.getLogger("deployment")
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def build_docker_image(self, dockerfile: str = "Dockerfile",
tag: Optional[str] = None) -> bool:
"""构建Docker镜像"""
try:
if not tag:
tag = f"{self.config['docker']['repository']}:{self.config['docker']['tag']}"
self.logger.info(f"构建Docker镜像: {tag}")
cmd = ["docker", "build", "-t", tag, "-f", dockerfile, "."]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
self.logger.info("Docker镜像构建成功")
return True
else:
self.logger.error(f"Docker镜像构建失败: {result.stderr}")
return False
except Exception as e:
self.logger.error(f"构建Docker镜像时发生错误: {e}")
return False
def push_docker_image(self, tag: Optional[str] = None) -> bool:
"""推送Docker镜像"""
try:
if not tag:
tag = f"{self.config['docker']['repository']}:{self.config['docker']['tag']}"
self.logger.info(f"推送Docker镜像: {tag}")
cmd = ["docker", "push", tag]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
self.logger.info("Docker镜像推送成功")
return True
else:
self.logger.error(f"Docker镜像推送失败: {result.stderr}")
return False
except Exception as e:
self.logger.error(f"推送Docker镜像时发生错误: {e}")
return False
def deploy_to_kubernetes(self, manifest_dir: str = "k8s") -> bool:
"""部署到Kubernetes"""
try:
manifest_path = Path(manifest_dir)
if not manifest_path.exists():
self.logger.error(f"Kubernetes清单目录不存在: {manifest_dir}")
return False
self.logger.info("开始部署到Kubernetes")
# 应用所有YAML文件
for yaml_file in manifest_path.glob("*.yaml"):
self.logger.info(f"应用清单文件: {yaml_file}")
cmd = ["kubectl", "apply", "-f", str(yaml_file)]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
self.logger.error(f"应用清单文件失败: {result.stderr}")
return False
self.logger.info("Kubernetes部署成功")
return True
except Exception as e:
self.logger.error(f"部署到Kubernetes时发生错误: {e}")
return False
def check_deployment_status(self, deployment_name: str = "chatroom-server") -> Dict[str, Any]:
"""检查部署状态"""
try:
namespace = self.config["kubernetes"]["namespace"]
cmd = ["kubectl", "get", "deployment", deployment_name,
"-n", namespace, "-o", "json"]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
deployment_info = json.loads(result.stdout)
status = deployment_info.get("status", {})
return {
"ready": status.get("readyReplicas", 0),
"desired": status.get("replicas", 0),
"available": status.get("availableReplicas", 0),
"updated": status.get("updatedReplicas", 0),
"conditions": status.get("conditions", [])
}
else:
self.logger.error(f"获取部署状态失败: {result.stderr}")
return {}
except Exception as e:
self.logger.error(f"检查部署状态时发生错误: {e}")
return {}
def wait_for_deployment(self, deployment_name: str = "chatroom-server",
timeout: int = 300) -> bool:
"""等待部署完成"""
try:
namespace = self.config["kubernetes"]["namespace"]
self.logger.info(f"等待部署完成: {deployment_name}")
cmd = ["kubectl", "rollout", "status", f"deployment/{deployment_name}",
"-n", namespace, f"--timeout={timeout}s"]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
self.logger.info("部署完成")
return True
else:
self.logger.error(f"部署超时或失败: {result.stderr}")
return False
except Exception as e:
self.logger.error(f"等待部署时发生错误: {e}")
return False
def rollback_deployment(self, deployment_name: str = "chatroom-server") -> bool:
"""回滚部署"""
try:
namespace = self.config["kubernetes"]["namespace"]
self.logger.info(f"回滚部署: {deployment_name}")
cmd = ["kubectl", "rollout", "undo", f"deployment/{deployment_name}",
"-n", namespace]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
self.logger.info("部署回滚成功")
return True
else:
self.logger.error(f"部署回滚失败: {result.stderr}")
return False
except Exception as e:
self.logger.error(f"回滚部署时发生错误: {e}")
return False
def full_deployment_pipeline(self) -> bool:
"""完整部署流水线"""
self.logger.info("开始完整部署流水线")
# 1. 构建Docker镜像
if not self.build_docker_image():
return False
# 2. 推送Docker镜像
if not self.push_docker_image():
return False
# 3. 部署到Kubernetes
if not self.deploy_to_kubernetes():
return False
# 4. 等待部署完成
if not self.wait_for_deployment():
self.logger.error("部署失败,开始回滚")
self.rollback_deployment()
return False
# 5. 验证部署状态
status = self.check_deployment_status()
if status.get("ready", 0) == status.get("desired", 0):
self.logger.info("部署流水线完成")
return True
else:
self.logger.error("部署验证失败")
return False
# 使用示例
def demo_containerization_deployment():
"""容器化部署演示"""
print("=== Chat-Room容器化部署演示 ===")
deployment_manager = DeploymentManager()
print("1. 构建Docker镜像...")
# success = deployment_manager.build_docker_image()
# print(f"构建结果: {'成功' if success else '失败'}")
print("2. 部署到Kubernetes...")
# success = deployment_manager.deploy_to_kubernetes()
# print(f"部署结果: {'成功' if success else '失败'}")
print("3. 检查部署状态...")
# status = deployment_manager.check_deployment_status()
# print(f"部署状态: {status}")
# 模拟部署状态
mock_status = {
"ready": 3,
"desired": 3,
"available": 3,
"updated": 3
}
print(f"模拟部署状态: {mock_status}")
print("部署完成!")
print("\n4. 部署配置说明:")
print("- Docker多阶段构建优化镜像大小")
print("- Kubernetes水平自动扩缩容")
print("- 健康检查和就绪探针")
print("- 配置和密钥管理")
print("- 服务发现和负载均衡")
print("- SSL/TLS终端和入口控制")
if __name__ == "__main__":
demo_containerization_deployment()
```
## 🎯 实践练习
### 练习1:多环境部署策略
```python
class MultiEnvironmentDeployment:
"""
多环境部署策略练习
要求:
1. 实现开发、测试、生产环境配置
2. 支持蓝绿部署和金丝雀发布
3. 实现环境间的配置管理
4. 添加部署审批和回滚机制
"""
def deploy_to_environment(self, env: str, strategy: str) -> bool:
"""部署到指定环境"""
# TODO: 实现多环境部署
pass
def canary_deployment(self, percentage: int) -> bool:
"""金丝雀部署"""
# TODO: 实现金丝雀部署
pass
```
### 练习2:监控和日志集成
```python
class MonitoringIntegration:
"""
监控和日志集成练习
要求:
1. 集成Prometheus和Grafana监控
2. 实现ELK日志收集和分析
3. 设置告警和通知机制
4. 添加性能指标和业务指标
"""
def setup_monitoring(self, config: Dict[str, Any]) -> bool:
"""设置监控系统"""
# TODO: 实现监控设置
pass
def configure_logging(self, log_config: Dict[str, Any]) -> bool:
"""配置日志系统"""
# TODO: 实现日志配置
pass
```
## ✅ 学习检查
完成本章学习后,请确认您能够:
- [ ] 理解容器化技术的核心概念和优势
- [ ] 编写Dockerfile和docker-compose配置
- [ ] 设计Kubernetes部署清单和策略
- [ ] 实现自动化部署和CI/CD流水线
- [ ] 配置服务发现和负载均衡
- [ ] 完成实践练习
## 📚 下一步
容器化部署掌握后,请继续学习:
- [CI/CD自动化](./cicd-automation.md)
---
**恭喜!您已经掌握了现代容器化部署技术!** 🐳