容器化部署
问题
微服务如何使用 Docker 和 Kubernetes 进行容器化部署?Docker 和 K8s 的核心概念是什么?
答案
Docker 基础
Docker 将应用和依赖打包成容器镜像,保证在任何环境中运行一致。
Spring Boot Dockerfile(多阶段构建)
# 构建阶段
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
# 非 root 用户运行
RUN addgroup -S spring && adduser -S spring -G spring
USER spring
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
docker-compose.yml(本地开发环境)
version: '3.8'
services:
order-service:
build: ./order-service
ports:
- "8081:8080"
environment:
- SPRING_PROFILES_ACTIVE=dev
- NACOS_SERVER=nacos:8848
depends_on:
- mysql
- redis
- nacos
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: order_db
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:7-alpine
nacos:
image: nacos/nacos-server:v2.2.3
environment:
MODE: standalone
volumes:
mysql_data:
Kubernetes 核心概念
| 概念 | 说明 |
|---|---|
| Pod | 最小部署单元,包含一个或多个容器 |
| Deployment | 管理 Pod 的副本数、滚动更新 |
| Service | 为 Pod 提供稳定的网络访问入口 |
| Ingress | HTTP 路由入口(类似 Nginx 反向代理) |
| ConfigMap | 配置数据(环境变量、配置文件) |
| Secret | 敏感数据(密码、证书) |
| Namespace | 资源隔离(dev/staging/prod) |
| HPA | 水平自动扩缩容 |
K8s 部署配置
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: registry.example.com/order-service:v1.2.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "1Gi"
readinessProbe: # 就绪探针
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
livenessProbe: # 存活探针
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 滚动更新时最多多 1 个 Pod
maxUnavailable: 0 # 更新时不允许不可用
service.yaml + HPA
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
部署策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 滚动更新 | 逐步替换旧 Pod | 默认策略,零停机 |
| 蓝绿部署 | 两套环境切换 | 需要快速回滚 |
| 金丝雀发布 | 小比例流量先灰度 | 高风险变更 |
常见面试问题
Q1: Docker 和虚拟机有什么区别?
答案:
| 对比 | Docker 容器 | 虚拟机 |
|---|---|---|
| 隔离级别 | 进程级(共享内核) | 操作系统级(独立内核) |
| 启动速度 | 秒级 | 分钟级 |
| 资源占用 | MB 级 | GB 级 |
| 性能 | 接近原生 | 有虚拟化开销 |
| 镜像大小 | 几十 MB | 几 GB |
Docker 更轻量,适合微服务部署。
Q2: K8s 的 Pod 和 Container 的关系?
答案:
- Pod 是 K8s 最小调度单元,可以包含多个 Container
- 同一 Pod 内的容器共享网络和存储(localhost 通信)
- 通常一个 Pod 运行一个主容器(业务应用),可加 Sidecar(如日志采集、Service Mesh 代理)
Q3: 如何实现零停机部署?
答案:
- 滚动更新:K8s Deployment 默认策略,逐步替换 Pod
- 就绪探针:新 Pod 通过健康检查后才接收流量
- 优雅停机:Spring Boot 配置
server.shutdown=graceful,处理完正在执行的请求再关闭 - preStop Hook:Pod 删除前等待一段时间,让负载均衡感知到
lifecycle:
preStop:
exec:
command: ["sleep", "10"] # 等待 10s 让流量切走