Docker/K8s 云原生部署与容器化实践
·
Docker/K8s 云原生部署与容器化实践

一、场景痛点:容器化改造的挑战
容器化已经成为现代应用部署的标准方式,它解决了"在我机器上能跑"的问题,实现了环境一致性。但容器化也带来了新的挑战:如何构建高效的多阶段镜像、如何管理容器网络、如何实现滚动更新和回滚、如何保证容器安全……
Kubernetes 作为容器编排的事实标准,提供了强大的服务管理能力。但 K8s 的复杂性也让很多团队望而却步。本文将系统性地介绍 Docker 镜像优化和 K8s 部署的最佳实践。
二、底层机制与原理深度剖析
2.1 Docker 镜像构建原理
flowchart TD
A[Dockerfile] --> B[Docker Daemon]
B --> C{构建阶段}
subgraph 多阶段构建
D[Stage 1: Build] --> E[编译产物]
D --> F[依赖安装]
E --> G[Stage 2: Runtime]
G --> H[精简镜像]
end
B --> I[Layer Cache]
I --> D
H --> J[Image Registry]
J --> K[Container Registry]
Docker 镜像的分层存储是性能优化的关键:利用好构建缓存可以大幅缩短构建时间;利用好多阶段构建可以大幅减小镜像体积。
2.2 K8s 核心架构
flowchart LR
subgraph 控制平面
A[API Server]
B[etcd]
C[Scheduler]
D[Controller Manager]
end
subgraph 工作节点
E[Kubelet]
F[Kube Proxy]
G[Container Runtime]
H[Pod 1]
I[Pod 2]
end
A --> E
E --> H
E --> I
G --> H
G --> I
三、生产级代码实现与最佳实践
3.1 优化的 Dockerfile
# ==================== 多阶段构建优化 ====================
# 第一阶段:构建
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
# 先复制依赖文件,利用 Maven 缓存
COPY pom.xml .
RUN mvn dependency:go-offline -B
# 复制源码并构建
COPY src ./src
RUN mvn package -DskipTests -B
# 第二阶段:运行
FROM eclipse-temurin:21-jre-alpine
# 安全运行配置
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 只复制构建产物
COPY --from=builder /app/target/*.jar app.jar
# 设置文件权限
RUN chown -R appuser:appgroup /app
# 切换为非 root 用户
USER appuser
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
# 镜像标签
LABEL maintainer="dev@example.com" \
version="1.0.0" \
description="Order Service"
EXPOSE 8080
# 使用 exec form 避免 shell 处理
ENTRYPOINT ["java", "-jar", "app.jar"]
# ==================== 前端应用优化 Dockerfile ====================
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
# 利用缓存
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
# 构建
ENV NODE_ENV=production
RUN npm run build
# 运行阶段
FROM nginx:alpine
# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 安全配置
RUN chown -R nginx:nginx /usr/share/nginx/html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chmod -R 755 /usr/share/nginx/html
USER nginx
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -qO- http://localhost/health || exit 1
CMD ["nginx", "-g", "daemon off;"]
3.2 Kubernetes 部署配置
# ==================== K8s Deployment 配置 ====================
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: production
labels:
app: order-service
version: v1
spec:
# 副本数
replicas: 3
# 滚动更新策略
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
# Pod 选择器
selector:
matchLabels:
app: order-service
# Pod 模板
template:
metadata:
labels:
app: order-service
version: v1
spec:
# 服务账号
serviceAccountName: order-service-sa
# 亲和性调度
affinity:
# Pod 反亲和,避免单点
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: order-service
topologyKey: kubernetes.io/hostname
# 节点亲和
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: node-type
operator: In
values:
- compute-optimized
# 容忍污点
tolerations:
- key: "node-type"
operator: "Equal"
value: "compute-optimized"
effect: "NoSchedule"
# 初始化容器
initContainers:
- name: wait-for-db
image: busybox:1.36
command:
- sh
- -c
- |
echo "Waiting for database..."
until nc -z db-service 5432; do
echo "Database not ready, waiting..."
sleep 2
done
echo "Database is ready"
containers:
- name: order-service
image: registry.example.com/order-service:1.0.0
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
protocol: TCP
- name: grpc
containerPort: 9090
protocol: TCP
# 资源限制
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2000m"
memory: "2Gi"
# 环境变量
env:
- name: SPRING_PROFILES_ACTIVE
value: "production"
- name: JAVA_OPTS
value: "-Xms1g -Xmx2g -XX:+UseG1GC"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-secret
key: host
# 就绪探针
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: http
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
# 存活探针
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: http
initialDelaySeconds: 60
periodSeconds: 15
successThreshold: 1
failureThreshold: 3
# 启动探针(慢启动应用)
startupProbe:
httpGet:
path: /actuator/health
port: http
initialDelaySeconds: 0
periodSeconds: 10
failureThreshold: 30
# 卷挂载
volumeMounts:
- name: app-logs
mountPath: /app/logs
- name: config
mountPath: /app/config
readOnly: true
volumes:
- name: app-logs
emptyDir: {}
- name: config
configMap:
name: order-service-config
# Pod 中断预算
terminationGracePeriodSeconds: 60
3.3 Helm Chart 模板
# ==================== Helm Values 配置 ====================
# values.yaml
replicaCount: 3
image:
repository: registry.example.com/order-service
pullPolicy: Always
service:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 8080
- name: grpc
port: 90
targetPort: 9090
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
hosts:
- host: order.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: order-service-tls
hosts:
- order.example.com
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# 探针配置
probes:
readiness:
initialDelaySeconds: 30
periodSeconds: 10
liveness:
initialDelaySeconds: 60
periodSeconds: 15
startup:
failureThreshold: 30
# 配置文件
config:
spring:
profiles:
active: production
database:
pool:
size: 20
maxSize: 50
3.4 K8s 服务网格配置
# ==================== Istio 虚拟服务配置 ====================
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: order-service
namespace: production
spec:
hosts:
- order-service
- order.example.com
gateways:
- ingressgateway
http:
- match:
- uri:
prefix: /api/orders
route:
- destination:
host: order-service
port:
number: 80
weight: 100
# 超时配置
timeout: 10s
# 重试配置
retries:
attempts: 3
perTryTimeout: 5s
retryOn: connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes
# 熔断
circuitBreaker:
simpleCircuitBreaker:
threshold:
errorPercentage: 50
interval: 10s
baseEjectionTime: 30s
---
# 目标规则
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: order-service
namespace: production
spec:
host: order-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
connectTimeout: 10s
http:
h2UpgradePolicy: UPGRADE
http1MaxPendingRequests: 100
http2MaxRequests: 1000
loadBalancer:
simple: LEAST_REQUEST
outlierDetection:
consecutiveGatewayErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
四、边界分析与 Trade-offs
4.1 容器化注意事项
| 考量 | 建议 |
|---|---|
| 镜像体积 | 使用多阶段构建,删除无用依赖 |
| 安全性 | 以非 root 用户运行,限制特权 |
| 日志 | 使用 stdout/stderr,配置日志收集 |
| 健康检查 | 配置就绪探针和存活探针 |
| 优雅关闭 | 处理 SIGTERM 信号 |
4.2 K8s 部署策略选择
| 策略 | 适用场景 | 风险 |
|---|---|---|
| RollingUpdate | 无停机要求的常规发布 | 可能同时运行两个版本 |
| Blue-Green | 需要快速回滚的场景 | 资源占用翻倍 |
| Canary | 新功能验证、金丝雀测试 | 复杂度较高 |
| A/B Testing | 功能对比测试 | 需要流量管理 |
五、总结
云原生容器化部署需要系统性的规划:
- 镜像优化:多阶段构建、精简体积、安全配置
- K8s 部署:资源限制、健康探针、调度策略
- 服务治理:Ingress、Service Mesh、流量管理
- 运维监控:日志、指标、追踪
- 安全加固:网络策略、Pod 安全上下文、密钥管理
容器化和 K8s 是现代应用部署的基础设施,掌握其最佳实践对于构建可靠、可扩展的系统至关重要。
更多推荐
所有评论(0)