跳到主要内容

Pod 与工作负载

Pod 基础

Pod 是 K8s 最小调度单元,包含一个或多个共享网络和存储的容器。

pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
app: myapp
env: production
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
# 资源请求和限制
resources:
requests:
cpu: "100m" # 0.1 核
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
# 环境变量
env:
- name: NODE_ENV
value: "production"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
# 存活探针
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
# 就绪探针
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# 启动探针(慢启动应用)
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30
periodSeconds: 10
# 优雅停机
terminationGracePeriodSeconds: 30
restartPolicy: Always

探针类型

探针用途失败行为
livenessProbe存活检查重启容器
readinessProbe就绪检查从 Service 端点移除
startupProbe启动检查阻塞其他探针直到成功

探测方式:

# HTTP 检查
livenessProbe:
httpGet:
path: /health
port: 8080

# TCP 检查
livenessProbe:
tcpSocket:
port: 3306

# 执行命令
livenessProbe:
exec:
command: ["cat", "/tmp/healthy"]

Deployment

管理无状态应用,提供滚动更新和回滚。

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: default
spec:
replicas: 3 # 副本数
selector:
matchLabels:
app: myapp
# 滚动更新策略
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多多创建 1 个 Pod
maxUnavailable: 0 # 不允许有不可用 Pod
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /health
port: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080

滚动更新与回滚

# 更新镜像
kubectl set image deployment/myapp app=myapp:2.0

# 查看更新状态
kubectl rollout status deployment/myapp

# 查看更新历史
kubectl rollout history deployment/myapp

# 回滚到上一版本
kubectl rollout undo deployment/myapp

# 回滚到指定版本
kubectl rollout undo deployment/myapp --to-revision=2

# 暂停/恢复更新
kubectl rollout pause deployment/myapp
kubectl rollout resume deployment/myapp

StatefulSet

管理有状态应用(数据库、消息队列),提供稳定网络标识和持久存储。

statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless # 必须关联 Headless Service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
volumeMounts:
- name: data
mountPath: /var/lib/mysql
# 自动创建 PVC
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 10Gi
---
# Headless Service
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None # Headless
selector:
app: mysql
ports:
- port: 3306

Deployment vs StatefulSet

特性DeploymentStatefulSet
Pod 名称随机后缀(myapp-abc123)有序编号(mysql-0, mysql-1)
创建顺序并行串行(0 → 1 → 2)
删除顺序并行逆序(2 → 1 → 0)
持久存储共享 PVC每个 Pod 独立 PVC
网络标识不稳定稳定 DNS(mysql-0.mysql-headless)
适用Web 应用、API数据库、Kafka、ZooKeeper

DaemonSet

每个 Node 运行一个 Pod,适合日志采集、监控代理。

daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true # 使用宿主网络
containers:
- name: node-exporter
image: prom/node-exporter:v1.7.0
ports:
- containerPort: 9100
hostPort: 9100
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
tolerations: # 容忍 Master 节点
- effect: NoSchedule
operator: Exists

Job 和 CronJob

job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
spec:
backoffLimit: 3 # 最大重试次数
activeDeadlineSeconds: 300 # 超时时间
template:
spec:
containers:
- name: migrate
image: myapp:latest
command: ["npx", "prisma", "migrate", "deploy"]
restartPolicy: Never
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-backup
spec:
schedule: "0 2 * * *" # 每天 2 点
concurrencyPolicy: Forbid # 禁止并发
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: backup-tool:latest
command: ["/backup.sh"]
restartPolicy: OnFailure

kubectl 常用命令

# ===== Pod 操作 =====
kubectl get pods -o wide # 查看 Pod(含 Node 信息)
kubectl describe pod myapp-xxx # 详细信息
kubectl logs myapp-xxx -f # 实时日志
kubectl logs myapp-xxx -c sidecar # 多容器指定
kubectl exec -it myapp-xxx -- sh # 进入容器
kubectl delete pod myapp-xxx # 删除 Pod

# ===== Deployment 操作 =====
kubectl get deploy # 查看 Deployment
kubectl scale deploy myapp --replicas=5 # 扩缩容
kubectl apply -f deployment.yaml # 声明式部署

# ===== 调试 =====
kubectl get events --sort-by=.lastTimestamp # 事件
kubectl top pods # Pod 资源使用
kubectl top nodes # Node 资源使用

常见面试问题

Q1: Pod 的生命周期是怎样的?

答案

Pod 状态:Pending → Running → Succeeded/Failed

  1. Pending:等待调度或拉取镜像
  2. Running:至少一个容器运行中
  3. Succeeded:所有容器成功退出(Job)
  4. Failed:至少一个容器失败退出
  5. Unknown:kubelet 失联

容器重启策略:Always(默认)、OnFailureNever

Q2: Deployment 如何实现零停机更新?

答案

  1. 配置 readinessProbe:确保新 Pod 就绪后才接收流量
  2. 设置 maxSurge: 1, maxUnavailable: 0:先创建新 Pod 再删除旧 Pod
  3. 配置 terminationGracePeriodSeconds:留出连接排空时间
  4. 应用代码支持 SIGTERM 优雅关闭

Q3: StatefulSet 的 Pod 为什么需要稳定的网络标识?

答案

有状态应用(如 MySQL 主从、Kafka Broker)需要:

  1. 稳定的 DNS:其他节点通过 mysql-0.mysql-headless 持续连接
  2. 有序创建/删除:主节点先启动,从节点后启动
  3. 独立 PVC:每个实例有自己的持久存储
  4. Pod 重建后仍保持原有标识(名称、存储不变)

Q4: 如何让 DaemonSet 在所有节点(包括 Master)上运行?

答案

Master 节点通常有 NoSchedule 污点。给 DaemonSet 添加 tolerations:

tolerations:
- effect: NoSchedule
operator: Exists

相关链接