Appearance
Kubernetes 详解:容器编排
Kubernetes(K8s)是容器编排的事实标准,由 Google 基于 Borg 系统经验开源。它负责容器的自动化部署、扩缩容、负载均衡、自愈、滚动更新,是微服务运行的"操作系统"。
一、为什么需要 K8s?
1.1 没有 K8s 的运维困境
场景:30 个微服务,每个 3 个实例 = 90 个容器
运维的一天:
8:00 服务器 A 宕机,手动把 15 个容器迁移到其他机器
9:30 流量上涨,手动启动 10 个新实例
10:00 新版本发布,手动停旧起新,一台一台操作
11:00 某服务 CPU 100%,手动重启
14:00 又一台服务器宕机...
问题:
❌ 全是手工操作,运维 996
❌ 故障恢复靠"人盯着"
❌ 发布靠"一个一个来"
❌ 资源利用率低,每台机器跑什么全靠 Excel1.2 有了 K8s 之后
K8s 自动处理的一切:
✅ 容器调度:自动选择最优节点运行容器
✅ 自愈:容器挂了自动重启,节点宕机自动迁移
✅ 弹性伸缩:CPU 高了自动加实例,低了自动减
✅ 滚动更新:新版本逐步替换旧版本,不中断服务
✅ 服务发现:容器 IP 变来变去,Service 提供固定访问入口
✅ 负载均衡:自动分发请求到多个实例
✅ 配置管理:ConfigMap/Secret 管理配置和密码
✅ 存储管理:自动挂载持久化存储
运维只需要:kubectl apply -f deployment.yaml,剩下的 K8s 全包了二、核心概念
2.1 架构全景
┌──────────────────────────────────────────────────────────────────┐
│ K8s 集群架构 │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Control Plane(控制平面) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │API Server│ │Scheduler │ │Controller│ │ etcd │ │ │
│ │ │ 统一入口 │ │ 调度器 │ │ Manager │ │ 状态存储 │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Worker 1 │ │ Worker 2 │ │ Worker 3 │ │
│ │ │ │ │ │ │ │
│ │ ┌──┐ ┌──┐ │ │ ┌──┐ ┌──┐ │ │ ┌──┐ ┌──┐ │ │
│ │ │Po│ │Po│ │ │ │Po│ │Po│ │ │ │Po│ │Po│ │ │
│ │ │d │ │d │ │ │ │d │ │d │ │ │ │d │ │d │ │ │
│ │ └──┘ └──┘ │ │ └──┘ └──┘ │ │ └──┘ └──┘ │ │
│ │ kubelet │ │ kubelet │ │ kubelet │ │
│ │ kube-proxy │ │ kube-proxy │ │ kube-proxy │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 控制平面负责:调度、管理、存储状态 │
│ Worker 负责:运行容器 │
└──────────────────────────────────────────────────────────────────┘2.2 核心对象层级
┌──────────────────────────────────────────────────────────────┐
│ 从大到小:Cluster → Node → Pod → Container │
│ │
│ Cluster(集群) │
│ └── Node(节点,物理机/虚拟机) │
│ └── Pod(最小调度单元,1 个或多个容器) │
│ └── Container(容器,Docker 容器) │
│ │
│ 类比: │
│ 集群 = 整栋楼 │
│ 节点 = 每层楼 │
│ Pod = 每个房间(共享网络和存储) │
│ 容器 = 房间里的人 │
└──────────────────────────────────────────────────────────────┘2.3 十大核心对象速览
| 对象 | 缩写 | 一句话 | 类比 |
|---|---|---|---|
| Pod | po | 最小调度单元,1 个或多个容器 | 豆荚(容器在豆荚里) |
| Deployment | deploy | 管理 Pod 副本、滚动更新、回滚 | 工头,管一批 Pod 的生死 |
| Service | svc | 给 Pod 提供固定访问入口(IP + DNS) | 前台,不管 Pod 怎么换,入口不变 |
| ConfigMap | cm | 非敏感配置(环境变量/配置文件) | 配置字典 |
| Secret | - | 敏感配置(密码/Token/TLS 证书) | 加密配置字典 |
| Ingress | ing | 七层负载均衡,HTTP/HTTPS 路由 | 大堂门禁,按 URL 分流 |
| Namespace | ns | 逻辑隔离(dev/test/prod) | 不同楼层,互不干扰 |
| StatefulSet | sts | 有状态应用(数据库/消息队列) | 带编号的 Pod,固定身份 |
| DaemonSet | ds | 每个节点跑一个 Pod(日志/监控) | 每层楼一个保安 |
| PersistentVolume | pv | 持久化存储(不会随 Pod 销毁) | 保险柜 |
三、核心对象详解
3.1 Pod — 最小调度单元
yaml
apiVersion: v1
kind: Pod
metadata:
name: order-service
labels:
app: order-service
spec:
containers:
- name: order-service
image: registry.example.com/order-service:1.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
resources:
requests: # 最低保证资源
memory: "256Mi"
cpu: "250m"
limits: # 最高限制资源
memory: "512Mi"
cpu: "500m"
livenessProbe: # 存活探针:容器挂了就重启
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe: # 就绪探针:准备好了才接流量
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5探针类型:
| 探针 | 作用 | 失败后果 |
|---|---|---|
| livenessProbe | 容器是否活着 | 重启容器 |
| readinessProbe | 容器是否准备好接流量 | 从 Service 摘除,不重启 |
| startupProbe | 启动是否完成 | 在成功前禁用 liveness 和 readiness |
3.2 Deployment — 管理 Pod 副本
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3 # 3 个副本
selector:
matchLabels:
app: order-service
strategy:
type: RollingUpdate # 滚动更新
rollingUpdate:
maxSurge: 1 # 更新时最多多 1 个 Pod
maxUnavailable: 0 # 更新时最少可用 3 个 Pod
template: # Pod 模板
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: registry.example.com/order-service:1.0
ports:
- containerPort: 8080滚动更新过程:
更新前:3 个 Pod 都运行 v1.0
┌──┐ ┌──┐ ┌──┐
│v1│ │v1│ │v1│
└──┘ └──┘ └──┘
更新开始:kubectl set image → v2.0
步骤 1: 步骤 2: 步骤 3: 步骤 4:
┌──┐┌──┐ ┌──┐┌──┐ ┌──┐┌──┐ ┌──┐┌──┐┌──┐
│v2││v1│ │v2││v2│ │v2││v2│ │v2││v2││v2│
└──┘└──┘ └──┘└──┘ └──┘└──┘ └──┘└──┘└──┘
┌──┐ ┌──┐
│v1│ │v1│ (已删除)
└──┘ └──┘
整个过程服务不中断,用户无感知3.3 Service — 固定访问入口
yaml
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
type: ClusterIP # 集群内部访问
selector:
app: order-service # 通过标签选择 Pod
ports:
- port: 8080 # Service 端口
targetPort: 8080 # Pod 端口
protocol: TCPService 类型:
| 类型 | 访问范围 | 场景 |
|---|---|---|
| ClusterIP | 集群内部 | 微服务间调用 |
| NodePort | 集群外部(NodeIP:Port) | 开发测试 |
| LoadBalancer | 云负载均衡器 | 生产环境 |
| ExternalName | DNS 别名 | 外部服务映射 |
3.4 Ingress — HTTP 路由
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- host: api.example.com
http:
paths:
- path: /order
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8080
- path: /user
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80803.5 ConfigMap + Secret
yaml
# ConfigMap(非敏感配置)
apiVersion: v1
kind: ConfigMap
metadata:
name: order-service-config
data:
application.yml: |
spring:
datasource:
url: jdbc:mysql://mysql:3306/order_db
redis:
host: redis
---
# Secret(敏感配置,Base64 编码)
apiVersion: v1
kind: Secret
metadata:
name: order-service-secret
type: Opaque
data:
db-password: cm9vdDEyMw== # echo -n 'root123' | base64
jwt-secret: bXktc2VjcmV0LWtleQ==在 Pod 中使用:
yaml
spec:
containers:
- name: order-service
image: order-service:1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: order-service-secret
key: db-password
volumeMounts:
- name: config
mountPath: /app/config
volumes:
- name: config
configMap:
name: order-service-config四、弹性伸缩
4.1 HPA(水平 Pod 自动伸缩)
yaml
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
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80HPA 工作流程:
┌──────────────────────────────────────────────────────────────┐
│ 监控 → 计算 → 决策 → 扩缩容 │
│ │
│ 1. Metrics Server 采集每个 Pod 的 CPU/内存 │
│ 2. HPA 每 15 秒计算平均使用率 │
│ 3. 目标副本数 = ceil(当前副本数 × 当前使用率 / 目标使用率) │
│ 4. 操作 Deployment 的 replicas 字段 │
│ │
│ 示例: │
│ 当前 3 个副本,CPU 平均 85%,目标 70% │
│ 目标副本数 = ceil(3 × 85/70) = ceil(3.64) = 4 │
│ → 扩容到 4 个副本 │
│ │
│ 冷却时间:默认扩容后 3 分钟内不缩容,缩容后 5 分钟内不扩容 │
│ 防止抖动:频繁扩缩容比短期高负载损害更大 │
└──────────────────────────────────────────────────────────────┘4.2 VPA(垂直 Pod 自动伸缩)
yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: order-service-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
updatePolicy:
updateMode: "Auto" # 自动调整 Pod 的 CPU/内存限额五、常用命令
5.1 资源管理
bash
# 查看资源
kubectl get pods # 查看 Pod
kubectl get pods -o wide # 查看 Pod 详情(含 IP/节点)
kubectl get deployments # 查看 Deployment
kubectl get services # 查看 Service
kubectl get all # 查看所有资源
# 查看详情
kubectl describe pod <pod-name> # Pod 详细信息
kubectl logs -f <pod-name> # 实时日志
kubectl logs <pod-name> --tail=100 # 最后 100 行日志
# 进入容器
kubectl exec -it <pod-name> -- /bin/bash5.2 更新与回滚
bash
# 更新镜像
kubectl set image deployment/order-service order-service=registry/order-service:v2.0
# 查看更新状态
kubectl rollout status deployment/order-service
# 查看历史版本
kubectl rollout history deployment/order-service
# 回滚到上一版本
kubectl rollout undo deployment/order-service
# 回滚到指定版本
kubectl rollout undo deployment/order-service --to-revision=35.3 扩缩容
bash
# 手动扩容
kubectl scale deployment/order-service --replicas=5
# 查看 HPA 状态
kubectl get hpa
# 查看 HPA 详情
kubectl describe hpa order-service-hpa5.4 调试
bash
# 查看 Pod 事件
kubectl describe pod <pod-name> | grep Events -A 20
# 查看最近事件
kubectl get events --sort-by=.metadata.creationTimestamp
# 临时运行调试 Pod
kubectl run debug --rm -it --image=busybox -- sh
# 端口转发(本地调试)
kubectl port-forward pod/<pod-name> 8080:8080六、微服务部署实战
6.1 完整部署清单
yaml
# order-service-deployment.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
---
apiVersion: v1
kind: ConfigMap
metadata:
name: order-service-config
namespace: production
data:
application.yml: |
spring:
datasource:
url: jdbc:mysql://mysql:3306/order_db
redis:
host: redis
---
apiVersion: v1
kind: Secret
metadata:
name: order-service-secret
namespace: production
type: Opaque
data:
db-password: cm9vdDEyMw==
---
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:1.0
ports:
- containerPort: 8080
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: order-service-secret
key: db-password
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
volumeMounts:
- name: config
mountPath: /app/config
volumes:
- name: config
configMap:
name: order-service-config
---
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: production
spec:
selector:
app: order-service
ports:
- port: 8080
targetPort: 8080
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 706.2 一键部署
bash
# 应用所有配置
kubectl apply -f order-service-deployment.yaml
# 查看部署状态
kubectl get all -n production
# 查看 Pod 日志
kubectl logs -f -l app=order-service -n production --tail=50七、面试要点
Q1:Pod 是什么?为什么 Pod 是 K8s 最小调度单元?
Pod 是一组共享网络和存储的容器集合。K8s 不直接调度容器,而是调度 Pod,因为同一 Pod 内的容器需要紧密协作(如 sidecar 模式),共享 localhost 网络和存储卷。
Q2:Deployment 和 StatefulSet 的区别?
| 维度 | Deployment | StatefulSet |
|---|---|---|
| Pod 标识 | 随机名称(order-xxx-yyy) | 固定序号(order-0, order-1) |
| 网络标识 | 无固定 DNS | 固定 DNS(order-0.svc.ns) |
| 存储 | 共享 PV | 每个 Pod 独立 PVC |
| 启停顺序 | 并行 | 按序号顺序(0→1→2) |
| 适用 | 无状态(Web、API) | 有状态(MySQL、Kafka) |
Q3:Service 如何实现负载均衡?
Service 通过 selector 标签匹配 Pod,kube-proxy 在每台节点上维护 iptables/IPVS 规则。请求到达 Service IP 时,kube-proxy 按随机或轮询分发到后端 Pod。ClusterIP 是虚拟 IP,只在集群内可达。
Q4:滚动更新和蓝绿发布的区别?
| 维度 | 滚动更新 | 蓝绿发布 |
|---|---|---|
| 方式 | 逐个替换 Pod | 新老版本各一套完整环境 |
| 资源 | 只需少量额外资源 | 需要双倍资源 |
| 回滚 | 逐步回滚 | 瞬间切换流量 |
| 验证 | 渐进式验证 | 完整验证后再切换 |
Q5:livenessProbe 和 readinessProbe 的区别?
livenessProbe 检查容器是否活着,失败则重启容器;readinessProbe 检查容器是否准备好接流量,失败则从 Service 摘除,不重启。典型场景:应用启动中,readiness 未就绪,但 liveness 正常。
Q6:HPA 如何决定扩缩容?
HPA 每 15 秒通过 Metrics Server 采集指标,计算 目标副本数 = ceil(当前副本数 × 当前值 / 目标值)。扩容冷却 3 分钟,缩容冷却 5 分钟,防止抖动。
Q7:K8s 如何实现自愈?
Controller Manager 持续监控集群状态,发现实际状态与期望状态不一致时自动修复:Pod 挂了 → 重启;节点宕机 → 在其他节点重新调度;Deployment 副本数不够 → 自动补齐。
