08-可靠性运维
Kubernetes 集群升级、备份、容灾全解析
学习目标
通过本模块学习,你将掌握:
- etcd 备份与恢复策略
- 集群升级的安全流程
- Velero 应用备份方案
- 容灾与多集群策略
- GitOps 实践(Argo CD/Fleet)
- 生产环境可靠性保障
一、可靠性运维架构
运维体系概览
┌─────────────────────────────────────────────────────────────┐
│ 可靠性运维体系 │
├─────────────────────────────────────────────────────────────┤
│ 备份层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ etcd 快照 │ │ Velero 备份 │ │ GitOps 仓库 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 升级层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 控制面升级 │ │ 节点升级 │ │ 插件升级 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 容灾层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 多集群部署 │ │ 流量切换 │ │ 数据复制 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
可靠性关键指标
指标 | 目标 | 说明 |
---|---|---|
RTO(恢复时间目标) | < 1 小时 | 故障后恢复服务的时间 |
RPO(恢复点目标) | < 15 分钟 | 可容忍的数据丢失时间 |
MTBF(平均故障间隔) | > 720 小时 | 系统正常运行时间 |
MTTR(平均修复时间) | < 30 分钟 | 故障修复时间 |
二、etcd 备份与恢复
2.1 etcd 架构与重要性
etcd 是 Kubernetes 的核心数据存储:
- 存储所有集群状态和配置
- 丢失 etcd = 集群彻底报废
- 必须定期备份和演练恢复
graph TD
A[API Server] -->|读写| B[etcd]
B -->|快照备份| C[备份存储]
C -->|恢复| D[新 etcd 实例]
D -->|重建| E[集群恢复]
2.2 etcd 手动备份
备份脚本
#!/bin/bash
# etcd-backup.sh
BACKUP_DIR="/backup/etcd"
DATE=$(date +%Y%m%d-%H%M%S)
ETCDCTL_API=3
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份 etcd
etcdctl snapshot save ${BACKUP_DIR}/etcd-snapshot-${DATE}.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 验证备份
etcdctl snapshot status ${BACKUP_DIR}/etcd-snapshot-${DATE}.db \
--write-out=table
# 保留最近 7 天的备份
find $BACKUP_DIR -name "etcd-snapshot-*.db" -mtime +7 -delete
# 上传到远程存储(可选)
# aws s3 cp ${BACKUP_DIR}/etcd-snapshot-${DATE}.db s3://my-bucket/etcd-backups/
echo "Backup completed: etcd-snapshot-${DATE}.db"
CronJob 自动备份
apiVersion: batch/v1
kind: CronJob
metadata:
name: etcd-backup
namespace: kube-system
spec:
schedule: "0 */6 * * *" # 每 6 小时备份一次
jobTemplate:
spec:
template:
spec:
hostNetwork: true
containers:
- name: etcd-backup
image: registry.k8s.io/etcd:3.5.9-0
command:
- /bin/sh
- -c
- |
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d-%H%M%S).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 清理旧备份
find /backup -name "etcd-snapshot-*.db" -mtime +7 -delete
volumeMounts:
- name: etcd-certs
mountPath: /etc/kubernetes/pki/etcd
readOnly: true
- name: backup
mountPath: /backup
restartPolicy: OnFailure
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
volumes:
- name: etcd-certs
hostPath:
path: /etc/kubernetes/pki/etcd
type: Directory
- name: backup
hostPath:
path: /var/lib/etcd-backup
type: DirectoryOrCreate
2.3 etcd 恢复流程
恢复脚本
#!/bin/bash
# etcd-restore.sh
BACKUP_FILE="/backup/etcd/etcd-snapshot-20240101-120000.db"
RESTORE_DIR="/var/lib/etcd-restore"
ETCDCTL_API=3
# 停止 kube-apiserver
systemctl stop kube-apiserver
# 停止 etcd
systemctl stop etcd
# 恢复 etcd 数据
etcdctl snapshot restore $BACKUP_FILE \
--data-dir=$RESTORE_DIR \
--name=master-1 \
--initial-cluster=master-1=https://10.0.1.10:2380 \
--initial-cluster-token=etcd-cluster-1 \
--initial-advertise-peer-urls=https://10.0.1.10:2380
# 备份原数据
mv /var/lib/etcd /var/lib/etcd.bak.$(date +%Y%m%d-%H%M%S)
# 使用恢复的数据
mv $RESTORE_DIR /var/lib/etcd
# 修改 etcd 数据目录权限
chown -R etcd:etcd /var/lib/etcd
# 启动 etcd
systemctl start etcd
# 等待 etcd 启动
sleep 10
# 验证 etcd 状态
etcdctl endpoint health \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 启动 kube-apiserver
systemctl start kube-apiserver
echo "Restore completed successfully"
2.4 etcd 性能优化
defrag 碎片整理
#!/bin/bash
# etcd-defrag.sh
ETCDCTL_API=3
# 对所有成员进行碎片整理
etcdctl defrag \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 查看碎片整理效果
etcdctl endpoint status \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
--write-out=table
定期碎片整理 CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: etcd-defrag
namespace: kube-system
spec:
schedule: "0 2 * * 0" # 每周日凌晨 2 点
jobTemplate:
spec:
template:
spec:
hostNetwork: true
containers:
- name: etcd-defrag
image: registry.k8s.io/etcd:3.5.9-0
command:
- /bin/sh
- -c
- |
ETCDCTL_API=3 etcdctl defrag \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
ETCDCTL_API=3 etcdctl endpoint status \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
--write-out=table
volumeMounts:
- name: etcd-certs
mountPath: /etc/kubernetes/pki/etcd
readOnly: true
restartPolicy: OnFailure
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
volumes:
- name: etcd-certs
hostPath:
path: /etc/kubernetes/pki/etcd
type: Directory
三、集群升级策略
3.1 升级原则
升级顺序
1. 备份 etcd
↓
2. 升级控制面(Master)
↓
3. 升级节点(Worker)
↓
4. 升级插件(CNI/CSI)
版本兼容性
- kube-apiserver:不能跨大版本升级
- kubelet:最多落后 apiserver 两个小版本
- kubectl:可以比 apiserver 高一个或低一个小版本
3.2 kubeadm 升级流程
升级控制面
#!/bin/bash
# upgrade-control-plane.sh
# 1. 备份 etcd
./etcd-backup.sh
# 2. 升级 kubeadm
apt-mark unhold kubeadm
apt-get update
apt-get install -y kubeadm=1.28.0-00
apt-mark hold kubeadm
# 3. 查看升级计划
kubeadm upgrade plan
# 4. 执行升级
kubeadm upgrade apply v1.28.0 --yes
# 5. 升级 kubelet 和 kubectl
apt-mark unhold kubelet kubectl
apt-get install -y kubelet=1.28.0-00 kubectl=1.28.0-00
apt-mark hold kubelet kubectl
# 6. 重启 kubelet
systemctl daemon-reload
systemctl restart kubelet
# 7. 验证升级
kubectl get nodes
kubectl version
升级工作节点
#!/bin/bash
# upgrade-worker-node.sh
NODE_NAME=$1
# 1. 标记节点不可调度
kubectl cordon $NODE_NAME
# 2. 驱逐 Pod
kubectl drain $NODE_NAME \
--ignore-daemonsets \
--delete-emptydir-data \
--force \
--grace-period=300
# 3. 升级 kubeadm(在节点上执行)
ssh $NODE_NAME << 'EOF'
apt-mark unhold kubeadm
apt-get update
apt-get install -y kubeadm=1.28.0-00
apt-mark hold kubeadm
# 升级节点配置
kubeadm upgrade node
# 升级 kubelet 和 kubectl
apt-mark unhold kubelet kubectl
apt-get install -y kubelet=1.28.0-00 kubectl=1.28.0-00
apt-mark hold kubelet kubectl
# 重启 kubelet
systemctl daemon-reload
systemctl restart kubelet
EOF
# 4. 取消节点不可调度
kubectl uncordon $NODE_NAME
# 5. 验证节点状态
kubectl get node $NODE_NAME
3.3 灰度升级策略
PodDisruptionBudget 配置
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: app-pdb
namespace: production
spec:
minAvailable: 2 # 至少保持 2 个副本可用
selector:
matchLabels:
app: web
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: db-pdb
namespace: production
spec:
maxUnavailable: 0 # 不允许任何副本不可用
selector:
matchLabels:
app: database
升级 Runbook
# upgrade-runbook.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: upgrade-runbook
namespace: kube-system
data:
upgrade-checklist.md: |
# Kubernetes 升级检查清单
## 准备阶段
- [ ] 查看版本兼容性矩阵
- [ ] 备份 etcd
- [ ] 备份配置文件
- [ ] 通知相关团队
- [ ] 准备回滚方案
## 升级阶段
- [ ] 升级第一个控制面节点
- [ ] 验证控制面功能
- [ ] 升级其他控制面节点
- [ ] 升级工作节点(分批)
- [ ] 升级 CNI 插件
- [ ] 升级 CSI 插件
## 验证阶段
- [ ] 检查所有节点状态
- [ ] 检查所有 Pod 状态
- [ ] 验证服务可用性
- [ ] 运行冒烟测试
- [ ] 检查日志和指标
## 回滚阶段(如需要)
- [ ] 恢复 etcd 快照
- [ ] 降级组件版本
- [ ] 验证系统功能
四、Velero 应用备份
4.1 Velero 安装配置
安装 Velero CLI
# 下载 Velero CLI
wget https://github.com/vmware-tanzu/velero/releases/download/v1.12.0/velero-v1.12.0-linux-amd64.tar.gz
tar -xvf velero-v1.12.0-linux-amd64.tar.gz
sudo mv velero-v1.12.0-linux-amd64/velero /usr/local/bin/
# 验证安装
velero version --client-only
安装 Velero 到集群(使用 S3)
# 创建凭证文件
cat > credentials-velero << EOF
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
EOF
# 安装 Velero
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.8.0 \
--bucket my-backup-bucket \
--backup-location-config region=us-east-1 \
--snapshot-location-config region=us-east-1 \
--secret-file ./credentials-velero \
--use-volume-snapshots=true
Velero 部署 YAML
apiVersion: v1
kind: Namespace
metadata:
name: velero
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: velero
namespace: velero
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: velero
namespace: velero
spec:
replicas: 1
selector:
matchLabels:
app: velero
template:
metadata:
labels:
app: velero
spec:
serviceAccountName: velero
containers:
- name: velero
image: velero/velero:v1.12.0
command:
- /velero
args:
- server
- --features=
env:
- name: VELERO_SCRATCH_DIR
value: /scratch
- name: VELERO_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_LIBRARY_PATH
value: /plugins
- name: AWS_SHARED_CREDENTIALS_FILE
value: /credentials/cloud
volumeMounts:
- name: plugins
mountPath: /plugins
- name: scratch
mountPath: /scratch
- name: cloud-credentials
mountPath: /credentials
resources:
requests:
cpu: 500m
memory: 128Mi
limits:
cpu: 1000m
memory: 512Mi
volumes:
- name: plugins
emptyDir: {}
- name: scratch
emptyDir: {}
- name: cloud-credentials
secret:
secretName: cloud-credentials
4.2 Velero 备份配置
创建定时备份
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: daily-backup
namespace: velero
spec:
schedule: "0 2 * * *" # 每天凌晨 2 点
template:
includedNamespaces:
- production
- staging
excludedNamespaces:
- kube-system
- velero
includedResources:
- '*'
ttl: 720h # 保留 30 天
storageLocation: default
volumeSnapshotLocations:
- default
手动备份命令
# 备份整个集群
velero backup create cluster-backup-$(date +%Y%m%d)
# 备份特定命名空间
velero backup create production-backup \
--include-namespaces production
# 备份特定资源
velero backup create deployment-backup \
--include-resources deployments,services,configmaps
# 备份并包含 PV
velero backup create full-backup \
--include-namespaces production \
--snapshot-volumes=true
# 查看备份状态
velero backup get
velero backup describe cluster-backup-20240101
# 查看备份日志
velero backup logs cluster-backup-20240101
4.3 Velero 恢复流程
恢复命令
# 查看可用备份
velero backup get
# 恢复整个备份
velero restore create --from-backup cluster-backup-20240101
# 恢复到新命名空间
velero restore create --from-backup production-backup \
--namespace-mappings production:production-restore
# 恢复特定资源
velero restore create --from-backup full-backup \
--include-resources deployments,services
# 查看恢复状态
velero restore get
velero restore describe <restore-name>
# 查看恢复日志
velero restore logs <restore-name>
灾难恢复流程
# disaster-recovery-runbook.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: disaster-recovery-runbook
namespace: velero
data:
dr-steps.md: |
# 灾难恢复步骤
## 1. 评估阶段
- 确认故障范围和影响
- 确定恢复优先级
- 选择恢复时间点
## 2. 准备阶段
- 准备新集群(如需要)
- 安装 Velero
- 配置存储位置
## 3. 恢复阶段
```bash
# 恢复 namespace
velero restore create --from-backup production-backup-latest
# 验证 Pod 状态
kubectl get pods -n production
# 恢复 PV
velero restore create --from-backup pv-backup-latest
```
## 4. 验证阶段
- 检查所有资源状态
- 验证应用功能
- 检查数据完整性
- 执行冒烟测试
## 5. 切换阶段
- 更新 DNS 记录
- 切换流量
- 监控新环境
五、容灾与多集群策略
5.1 多集群架构
graph TD
A[用户] -->|DNS/流量| B[Global Load Balancer]
B -->|主集群| C[Cluster A]
B -->|备集群| D[Cluster B]
C -->|数据复制| E[对象存储]
D -->|数据复制| E
E -->|备份| F[异地存储]
5.2 多集群管理工具
Kubefed 多集群配置
apiVersion: v1
kind: ConfigMap
metadata:
name: kubefed-config
namespace: kube-federation-system
data:
config: |
apiVersion: core.kubefed.io/v1beta1
kind: KubeFedConfig
metadata:
name: kubefed
namespace: kube-federation-system
spec:
scope: Cluster
controllerDuration:
availableDelay: 20s
unavailableDelay: 60s
leaderElect:
leaseDuration: 15s
renewDeadline: 10s
retryPeriod: 5s
resourceLock: configmaps
clusterHealthCheck:
period: 10s
timeout: 3s
failureThreshold: 3
successThreshold: 1
5.3 流量切换策略
Global Load Balancer 配置
# 使用 ExternalDNS 实现多集群 DNS
apiVersion: v1
kind: Service
metadata:
name: app-service
annotations:
external-dns.alpha.kubernetes.io/hostname: app.example.com
external-dns.alpha.kubernetes.io/ttl: "60"
external-dns.alpha.kubernetes.io/policy: weighted
external-dns.alpha.kubernetes.io/weight-cluster-a: "100"
external-dns.alpha.kubernetes.io/weight-cluster-b: "0"
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080
六、GitOps 实践
6.1 Argo CD 部署
apiVersion: v1
kind: Namespace
metadata:
name: argocd
---
# 使用官方安装清单
# kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
apiVersion: v1
kind: Service
metadata:
name: argocd-server
namespace: argocd
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
name: http
- port: 443
targetPort: 8080
name: https
selector:
app.kubernetes.io/name: argocd-server
6.2 Application 配置
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests
targetRevision: main
path: production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- Validate=true
- CreateNamespace=true
- PrunePropagationPolicy=foreground
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
️ 七、命令速记
etcd 相关命令
# 备份 etcd
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db
# 恢复 etcd
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db
# 查看快照状态
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot.db
# 查看 etcd 健康状态
ETCDCTL_API=3 etcdctl endpoint health
# 查看 etcd 成员
ETCDCTL_API=3 etcdctl member list
# 碎片整理
ETCDCTL_API=3 etcdctl defrag
升级相关命令
# 查看升级计划
kubeadm upgrade plan
# 升级控制面
kubeadm upgrade apply v1.28.0
# 升级节点
kubeadm upgrade node
# 标记节点不可调度
kubectl cordon <node-name>
# 驱逐节点上的 Pod
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
# 取消节点不可调度
kubectl uncordon <node-name>
Velero 相关命令
# 创建备份
velero backup create <backup-name>
# 查看备份
velero backup get
# 恢复备份
velero restore create --from-backup <backup-name>
# 查看恢复状态
velero restore get
# 删除备份
velero backup delete <backup-name>
# 查看备份位置
velero backup-location get
八、面试核心问答
Q1: 如何保证 Kubernetes 集群的高可用?
答案要点:
- 多个 Master 节点(至少 3 个)
- etcd 集群部署
- 定期备份 etcd
- 使用负载均衡器
- 配置 PodDisruptionBudget
- 多可用区部署
Q2: etcd 备份的最佳实践是什么?
答案要点:
- 定期自动备份(每 6 小时)
- 多地存储备份文件
- 定期测试恢复流程
- 监控备份任务状态
- 保留足够的备份历史
- 加密备份文件
Q3: Kubernetes 集群升级的步骤是什么?
答案要点:
- 备份 etcd
- 升级控制面节点
- 升级工作节点(逐个)
- 升级插件(CNI/CSI)
- 验证集群功能
- 准备回滚方案
Q4: 如何实现 Kubernetes 的灾难恢复?
答案要点:
- 使用 Velero 备份应用
- 备份 etcd 数据
- GitOps 管理配置
- 多集群部署
- 自动化恢复流程
- 定期演练
Q5: GitOps 的优势是什么?
答案要点:
- 版本控制所有配置
- 自动化部署
- 易于回滚
- 审计跟踪
- 声明式管理
- 减少人为错误
九、故障排查
常见备份恢复问题
1. etcd 备份失败
# 检查 etcd 状态
ETCDCTL_API=3 etcdctl endpoint health
# 检查证书
ls -la /etc/kubernetes/pki/etcd/
# 检查磁盘空间
df -h
# 查看 etcd 日志
journalctl -u etcd -f
2. Velero 备份失败
# 查看 Velero 日志
kubectl logs -n velero -l app=velero
# 检查备份位置
velero backup-location get
# 检查存储权限
velero backup-location describe default
# 查看备份详情
velero backup describe <backup-name> --details
3. 升级失败回滚
# 恢复 etcd
./etcd-restore.sh
# 降级组件
apt-get install -y kubeadm=1.27.0-00 kubelet=1.27.0-00
# 验证版本
kubectl version
kubeadm version
十、最佳实践
备份策略建议
etcd 备份
- 每 6 小时自动备份
- 保留 7 天备份
- 异地存储备份
- 定期测试恢复
应用备份
- 使用 Velero 自动备份
- 包含 PV 快照
- 保留 30 天备份
- 分级备份策略
配置管理
- GitOps 管理所有配置
- 版本控制
- 自动化部署
- Code Review 流程
升级策略建议
准备阶段
- 备份所有数据
- 准备回滚方案
- 通知相关团队
- 选择低峰期
执行阶段
- 分批升级
- 验证每个步骤
- 监控系统状态
- 保持沟通
验证阶段
- 冒烟测试
- 性能测试
- 功能验证
- 日志检查
十一、总结
通过本模块学习,你已经掌握了:
- etcd 备份与恢复策略
- 集群升级的安全流程
- Velero 应用备份方案
- 容灾与多集群策略
- GitOps 实践(Argo CD)
- 生产环境可靠性保障
- 备份恢复故障排查
下一步建议:继续学习 09-成本与容量,深入了解 Kubernetes 资源优化和成本管理。