容器化改造实战
问题
公司决定将传统虚拟机部署的应用迁移到 Kubernetes 容器化部署,如何规划和执行?
答案
容器化改造路线图
Phase 1:评估与筛选
| 评估维度 | 高优先(先容器化) | 暂缓容器化 |
|---|---|---|
| 应用类型 | 无状态 Web/API | 有状态数据库 |
| 变更频率 | 频繁发布(周/日级) | 很少变更 |
| 依赖 | 标准化(Linux + 语言运行时) | 依赖特殊硬件/驱动 |
| 团队能力 | 开发团队了解容器 | 团队刚接触 |
Phase 2:编写 Dockerfile
# 多阶段构建 - 减小镜像体积
# Stage 1: 构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Stage 2: 运行
FROM node:20-alpine
# 安全:不用 root 运行
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -D appuser
WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
USER appuser
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -q --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/main.js"]
Dockerfile 最佳实践
- 多阶段构建:编译镜像和运行镜像分离,减小体积
- 非 root 运行:创建专用用户,避免容器逃逸后获得主机 root
- COPY 顺序:先 COPY
package.json,再 COPY 源码,利用缓存 - 使用 alpine 基础镜像:体积从 1GB 降到 100MB 以下
Phase 3:Kubernetes 部署清单
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
spec:
replicas: 3
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # 滚动更新不减少可用实例
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: registry.example.com/web-app:v1.2.3 # 不用 latest
ports:
- containerPort: 3000
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 20
env:
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-credentials
key: host
Phase 4:灰度切流
# 通过 Nginx upstream 权重控制流量
# 先将 10% 流量切到 K8s
upstream backend {
server vm-app-01:3000 weight=9; # 旧 VM
server k8s-ingress:80 weight=1; # 新 K8s
}
# 观察 1~2 天无异常后,逐步调整为 50%、100%
# 或者通过 DNS 权重
# k8s.example.com A 10.0.1.1 weight=10
# k8s.example.com A 10.0.2.1 weight=90
常见面试问题
Q1: 容器化改造中最常见的坑有哪些?
答案:
| 问题 | 说明 | 解决方案 |
|---|---|---|
| 日志写本地文件 | 容器重启后丢失 | 输出到 stdout,由日志系统收集 |
| 硬编码 IP/路径 | 容器环境 IP 动态分配 | 用环境变量或服务发现 |
| 时区问题 | 容器默认 UTC | 挂载 /etc/localtime 或设置 TZ 环境变量 |
| 资源未设限 | 单个 Pod 吃满节点 | 必须设置 requests 和 limits |
| 镜像过大 | 拉取慢、部署慢 | 多阶段构建、alpine 基础镜像 |
| Session 丢失 | 多副本时 Session 不共享 | Session 存 Redis |