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
| 特性 | Deployment | StatefulSet |
|---|---|---|
| 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
- Pending:等待调度或拉取镜像
- Running:至少一个容器运行中
- Succeeded:所有容器成功退出(Job)
- Failed:至少一个容器失败退出
- Unknown:kubelet 失联
容器重启策略:Always(默认)、OnFailure、Never
Q2: Deployment 如何实现零停机更新?
答案:
- 配置
readinessProbe:确保新 Pod 就绪后才接收流量 - 设置
maxSurge: 1, maxUnavailable: 0:先创建新 Pod 再删除旧 Pod - 配置
terminationGracePeriodSeconds:留出连接排空时间 - 应用代码支持
SIGTERM优雅关闭
Q3: StatefulSet 的 Pod 为什么需要稳定的网络标识?
答案:
有状态应用(如 MySQL 主从、Kafka Broker)需要:
- 稳定的 DNS:其他节点通过
mysql-0.mysql-headless持续连接 - 有序创建/删除:主节点先启动,从节点后启动
- 独立 PVC:每个实例有自己的持久存储
- Pod 重建后仍保持原有标识(名称、存储不变)
Q4: 如何让 DaemonSet 在所有节点(包括 Master)上运行?
答案:
Master 节点通常有 NoSchedule 污点。给 DaemonSet 添加 tolerations:
tolerations:
- effect: NoSchedule
operator: Exists