7. 容器化与微服务
7. 容器化与微服务
7.1 容器技术基础
7.1.1 Docker 核心概念
镜像(Image)
- 只读的文件系统模板
- 包含运行应用所需的所有内容
- 分层存储结构
容器(Container)
- 镜像的运行实例
- 轻量级、可移植的执行环境
- 与宿主机和其他容器隔离
仓库(Registry)
- 存储和分发镜像的服务
- Docker Hub、Harbor等
7.1.2 Docker 基本操作
拉取镜像
docker pull nginx:latest
查看镜像列表
docker images
运行容器
docker run -d -p 8080:80 --name my-nginx nginx
查看运行中的容器
docker ps
查看所有容器
docker ps -a
停止容器
docker stop my-nginx
删除容器
docker rm my-nginx
删除镜像
docker rmi nginx:latest
查看容器日志
docker logs -f my-nginx
进入容器
docker exec -it my-nginx /bin/bash
7.1.3 Dockerfile 编写
基础镜像
FROM node:16-alpine
设置工作目录
WORKDIR /app
复制依赖文件
COPY package*.json ./
安装依赖
RUN npm ci --only=production
复制应用代码
COPY . .
暴露端口
EXPOSE 3000
健康检查
HEALTHCHECK --interval=30s --timeout=3s
CMD node healthcheck.js
启动命令
CMD [“node”, “server.js”]
多阶段构建示例
构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
生产阶段
FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD [“node”, “dist/server.js”]
7.1.4 Docker Compose
docker-compose.yml 示例
version: ‘3.8’
services:
web:
build: ./web
ports:
- “3000:3000”
environment:
- NODE_ENV=production
- DB_HOST=db
depends_on:
- db
- redis
volumes:
- ./logs:/app/logs
networks:
- app-network
db:
image: postgres:14
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=secret
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
redis:
image: redis:7-alpine
networks:
- app-network
nginx:
image: nginx:alpine
ports:
- “80:80”
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- web
networks:
- app-network
volumes:
db-data:
networks:
app-network:
driver: bridge
常用命令
启动服务
docker-compose up -d
查看服务状态
docker-compose ps
查看日志
docker-compose logs -f web
停止服务
docker-compose down
重启服务
docker-compose restart web
构建并启动
docker-compose up -d --build
7.2 微服务架构
7.2.1 微服务设计原则
单一职责原则
- 每个服务专注于单一业务功能
- 高内聚、低耦合
服务自治
- 独立部署、独立扩展
- 拥有独立的数据库
去中心化治理
- 技术栈自由选择
- 数据管理去中心化
故障隔离
- 服务间故障不相互影响
- 熔断、降级机制
7.2.2 微服务架构模式
API Gateway 模式
// Express Gateway 配置示例
module.exports = {
apiEndpoints: {
users: {
host: ‘',
paths: '/api/users/’
},
orders: {
host: ‘',
paths: '/api/orders/’
}
},
serviceEndpoints: {
userService: {
url: ‘http://user-service:3001’
},
orderService: {
url: ‘http://order-service:3002’
}
},
policies: [‘cors’, ‘rate-limit’, ‘jwt’, ‘proxy’],
pipelines: {
userPipeline: {
apiEndpoints: [‘users’],
policies: [
{
cors: {
action: {
origin: ‘*’
}
}
},
{
jwt: {
action: {
secretOrPublicKey: process.env.JWT_SECRET
}
}
},
{
‘rate-limit’: {
action: {
max: 100,
windowMs: 60000
}
}
},
{
proxy: {
action: {
serviceEndpoint: ‘userService’
}
}
}
]
}
}
};
服务发现模式
// Consul 服务注册
const Consul = require(‘consul’);
const consul = new Consul();
// 注册服务
function registerService() {
const service = {
name: ‘user-service’,
id: ‘user-service-1’,
address: ‘192.168.1.100’,
port: 3001,
check: {
http: ‘http://192.168.1.100:3001/health’,
interval: ‘10s’
}
};
consul.agent.service.register(service, (err) => {
if (err) throw err;
console.log(‘Service registered’);
});
}
// 发现服务
async function discoverService(serviceName) {
return new Promise((resolve, reject) => {
consul.health.service(serviceName, (err, result) => {
if (err) reject(err);
const services = result
.filter(entry => entry.Checks.every(check => check.Status === ‘passing’))
.map(entry => entry.Service);
resolve(services);
});
});
}
7.2.3 服务间通信
RESTful API
// 用户服务
const express = require(‘express’);
const app = express();
app.get(‘/api/users/:id’, async (req, res) => {
try {
const user = await User.findById(req.params.id);
res.json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post(‘/api/users’, async (req, res) => {
try {
const user = await User.create(req.body);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
gRPC 通信
// user.proto
syntax = “proto3”;
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (User) {}
rpc CreateUser (CreateUserRequest) returns (User) {}
}
message GetUserRequest {
string id = 1;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message User {
string id = 1;
string name = 2;
string email = 3;
}
// gRPC 服务端实现
const grpc = require(‘@grpc/grpc-js’);
const protoLoader = require(‘@grpc/proto-loader’);
const packageDefinition = protoLoader.loadSync(‘user.proto’);
const userProto = grpc.loadPackageDefinition(packageDefinition).user;
const server = new grpc.Server();
server.addService(userProto.UserService.service, {
getUser: async (call, callback) => {
try {
const user = await User.findById(call.request.id);
callback(null, user);
} catch (error) {
callback(error);
}
},
createUser: async (call, callback) => {
try {
const user = await User.create(call.request);
callback(null, user);
} catch (error) {
callback(error);
}
}
});
server.bindAsync(‘0.0.0.0:50051’,
grpc.ServerCredentials.createInsecure(),
() => {
server.start();
console.log(‘gRPC server running on port 50051’);
}
);
消息队列通信
// RabbitMQ 生产者
const amqp = require(‘amqplib’);
async function publishMessage(queue, message) {
const connection = await amqp.connect(‘amqp://localhost’);
const channel = await connection.createChannel();
await channel.assertQueue(queue, { durable: true });
channel.sendToQueue(queue, Buffer.from(JSON.stringify(message)), {
persistent: true
});
console.log(‘Message sent:’, message);
setTimeout(() => {
connection.close();
}, 500);
}
// RabbitMQ 消费者
async function consumeMessages(queue) {
const connection = await amqp.connect(‘amqp://localhost’);
const channel = await connection.createChannel();
await channel.assertQueue(queue, { durable: true });
channel.prefetch(1);
channel.consume(queue, async (msg) => {
const content = JSON.parse(msg.content.toString());
console.log(‘Received:’, content);
try {
// 处理消息
await processMessage(content);
channel.ack(msg);
} catch (error) {
console.error('Error processing message:', error);
channel.nack(msg, false, true); // 重新入队
}
});
}
7.2.4 分布式事务
Saga 模式
// 订单 Saga 编排
class OrderSaga {
async createOrder(orderData) {
const sagaLog = [];
try {
// 1. 创建订单
const order = await this.orderService.create(orderData);
sagaLog.push({ step: 'createOrder', data: order });
// 2. 扣减库存
await this.inventoryService.reserve(order.items);
sagaLog.push({ step: 'reserveInventory', data: order.items });
// 3. 处理支付
const payment = await this.paymentService.process(order.total);
sagaLog.push({ step: 'processPayment', data: payment });
// 4. 发送通知
await this.notificationService.send(order.userId, 'Order confirmed');
return order;
} catch (error) {
// 补偿事务
await this.compensate(sagaLog);
throw error;
}
}
async compensate(sagaLog) {
for (let i = sagaLog.length - 1; i >= 0; i–) {
const step = sagaLog[i];
try {
switch (step.step) {
case 'createOrder':
await this.orderService.cancel(step.data.id);
break;
case 'reserveInventory':
await this.inventoryService.release(step.data);
break;
case 'processPayment':
await this.paymentService.refund(step.data.id);
break;
}
} catch (err) {
console.error(`Compensation failed for ${step.step}:`, err);
}
}
}
}
两阶段提交(2PC)
// 分布式事务协调器
class TransactionCoordinator {
async executeTransaction(participants, operation) {
const prepared = [];
// Phase 1: Prepare
for (const participant of participants) {
try {
await participant.prepare(operation);
prepared.push(participant);
} catch (error) {
// 回滚已准备的参与者
await this.abort(prepared);
throw error;
}
}
// Phase 2: Commit
try {
for (const participant of prepared) {
await participant.commit();
}
} catch (error) {
await this.abort(prepared);
throw error;
}
}
async abort(participants) {
for (const participant of participants) {
try {
await participant.rollback();
} catch (error) {
console.error(‘Rollback failed:’, error);
}
}
}
}
7.3 Kubernetes(K8s)
7.3.1 核心概念
Pod
- 最小部署单元
- 包含一个或多个容器
- 共享网络和存储
Deployment
- 管理 Pod 的副本
- 声明式更新
- 滚动升级
Service
- 服务发现和负载均衡
- 稳定的网络端点
- ClusterIP、NodePort、LoadBalancer
ConfigMap & Secret
- 配置管理
- 敏感信息存储
7.3.2 资源清单示例
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: myapp:v1.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: “production”
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: db.host
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: db.password
resources:
requests:
memory: “128Mi”
cpu: “100m”
limits:
memory: “256Mi”
cpu: “200m”
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
Service
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com
http:
paths:- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- path: /
ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
db.host: “postgres-service”
db.port: “5432”
cache.ttl: “3600”
app.config: |
server:
port: 3000
timeout: 30
logging:
level: info
Secret
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
db.password: cGFzc3dvcmQxMjM= # base64 encoded
api.key: YXBpa2V5MTIz
7.3.3 常用命令
创建资源
kubectl apply -f deployment.yaml
查看资源
kubectl get pods
kubectl get deployments
kubectl get services
kubectl get ingress
查看详细信息
kubectl describe pod web-app-xxx
kubectl describe deployment web-app
查看日志
kubectl logs web-app-xxx
kubectl logs -f web-app-xxx # 实时日志
kubectl logs web-app-xxx -c container-name # 多容器时指定
进入容器
kubectl exec -it web-app-xxx – /bin/bash
端口转发
kubectl port-forward pod/web-app-xxx 8080:3000
扩缩容
kubectl scale deployment web-app --replicas=5
滚动更新
kubectl set image deployment/web-app web=myapp:v2.0
kubectl rollout status deployment/web-app
回滚
kubectl rollout undo deployment/web-app
kubectl rollout history deployment/web-app
删除资源
kubectl delete pod web-app-xxx
kubectl delete -f deployment.yaml
查看集群信息
kubectl cluster-info
kubectl get nodes
kubectl top nodes
kubectl top pods
7.3.4 Helm 包管理
Chart 结构
mychart/
Chart.yaml # Chart 元数据
values.yaml # 默认配置值
charts/ # 依赖的 Chart
templates/ # 模板文件
deployment.yaml
service.yaml
ingress.yaml
_helpers.tpl # 模板助手
values.yaml
replicaCount: 3
image:
repository: myapp
tag: v1.0
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
host: myapp.example.com
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80
templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include “mychart.fullname” . }}
labels:
{{- include “mychart.labels” . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include “mychart.selectorLabels” . | nindent 6 }}
template:
metadata:
labels:
{{- include “mychart.selectorLabels” . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: “{{ .Values.image.repository }}:{{ .Values.image.tag }}”
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 3000
resources:
{{- toYaml .Values.resources | nindent 10 }}
Helm 命令
创建 Chart
helm create mychart
安装 Chart
helm install myapp ./mychart
helm install myapp ./mychart -f custom-values.yaml
升级
helm upgrade myapp ./mychart
回滚
helm rollback myapp 1
查看发布
helm list
helm status myapp
卸载
helm uninstall myapp
查看模板渲染结果
helm template myapp ./mychart
验证 Chart
helm lint ./mychart
打包
helm package mychart
7.4 监控与日志
7.4.1 Prometheus 监控
prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: ‘kubernetes-pods’
kubernetes_sd_configs:- role: pod
relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: metrics_path
regex: (.+) - source_labels: [address, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?😭\d+)
replacement: $1:$2
target_label: address
- role: pod
应用暴露指标
const express = require(‘express’);
const client = require(‘prom-client’);
const app = express();
// 创建指标
const httpRequestDuration = new client.Histogram({
name: ‘http_request_duration_seconds’,
help: ‘Duration of HTTP requests in seconds’,
labelNames: [‘method’, ‘route’, ‘status_code’]
});
const httpRequestTotal = new client.Counter({
name: ‘http_requests_total’,
help: ‘Total number of HTTP requests’,
labelNames: [‘method’, ‘route’, ‘status_code’]
});
// 中间件记录指标
app.use((req, res, next) => {
const start = Date.now();
res.on(‘finish’, () => {
const duration = (Date.now() - start) / 1000;
const route = req.route ? req.route.path : req.path;
httpRequestDuration
.labels(req.method, route, res.statusCode)
.observe(duration);
httpRequestTotal
.labels(req.method, route, res.statusCode)
.inc();
});
next();
});
// 暴露指标端点
app.get(‘/metrics’, async (req, res) => {
res.set(‘Content-Type’, client.register.contentType);
res.end(await client.register.metrics());
});
7.4.2 ELK 日志收集
Filebeat 配置
filebeat.inputs:
- type: container
paths:- /var/lib/docker/containers//.log
processors: - add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:- logs_path:
logs_path: “/var/lib/docker/containers/”
- logs_path:
- /var/lib/docker/containers//.log
output.elasticsearch:
hosts: [‘ELASTICSEARCHHOST:elasticsearch:{ELASTICSEARCH_HOST:elasticsearch}:ELASTICSEARCHHOST:elasticsearch:{ELASTICSEARCH_PORT:9200}’]
index: “filebeat-%{[agent.version]}-%{+yyyy.MM.dd}”
应用结构化日志
const winston = require(‘winston’);
const { ElasticsearchTransport } = require(‘winston-elasticsearch’);
const logger = winston.createLogger({
level: ‘info’,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new ElasticsearchTransport({
level: ‘info’,
clientOpts: { node: ‘http://elasticsearch:9200’ },
index: ‘app-logs’
})
]
});
// 使用日志
logger.info(‘User logged in’, {
userId: ‘12345’,
email: ‘user@example.com’,
ip: req.ip
});
logger.error(‘Payment failed’, {
orderId: ‘67890’,
amount: 100,
error: error.message
});
7.5 最佳实践
7.5.1 容器化最佳实践
- 使用多阶段构建减小镜像体积
- 使用 .dockerignore排除不必要的文件
- 使用官方基础镜像确保安全性
- 最小化层数合并 RUN 命令
- 不要以 root 用户运行
- 使用健康检查确保服务可用性
- 合理设置资源限制
7.5.2 微服务最佳实践
- 设计合理的服务边界
- 实现服务熔断和降级
- 使用 API 版本控制
- 实现完善的监控和日志
- 采用 CI/CD 自动化部署
- 做好服务文档
- 实施安全策略
7.5.3 K8s 最佳实践
- 使用命名空间隔离环境
- 设置资源请求和限制
- 配置健康检查探针
- 使用 ConfigMap 和 Secret 管理配置
- 实施 RBAC 权限控制
- 使用 HPA 自动扩缩容
- 定期备份 etcd 数据
- 使用 PodDisruptionBudget 保证可用性
更多推荐
所有评论(0)