Velero对K8s集群的备份与恢复实践
最近在生产环境折腾 K8s,心里总有点不踏实。万一哪天手一滑,kubectl delete ns 敲错了命名空间,那场面简直不敢想。常在河边走,哪有不湿鞋,是时候给我的集群搭建一套靠谱的灾备方案了。
经过一番调研,我把目标锁定在了 Velero 这个项目上。它是目前社区里最主流的 K8s 备份恢复工具,口碑相当不错。至于备份数据存哪儿,考虑到成本和便捷性,我决定在集群内部署一个 MinIO 作为对象存储仓库。
这篇博客,就是我这次从零开始,搭建并验证 Velero + MinIO 灾备方案的全程笔记。记录了从环境准备、工具安装,到模拟“删库”灾难,再到最终完美恢复的全过程。
第一章:核心概念速览
动手之前,我习惯先花几分钟弄明白工具的基本原理,这样遇到问题才不会慌。
Velero 是什么?
一个开源的 K8s 集群资源备份、恢复和迁移工具。它能把 K8s 资源的 YAML 配置和 PV 里的真实数据,一起打包存到外部。它的工作逻辑是怎样的?
Velero Server (服务端):一个跑在 K8s 集群里的 Deployment,是干活的“机器人”。
Velero CLI (客户端):我本地电脑上的命令行工具,是用来指挥机器人的“遥控器”。
对象存储 (MinIO):我准备在集群里搭建的一个“仓库”,专门存放备份文件。
插件 (Plugins):Velero 用它来和不同的云、不同的存储技术打交道。我们这次用的 velero-plugin-for-aws 就能让它和兼容 S3 协议的 MinIO 对话。
我自己的理解:
这就像给我的 K8s 集群配了个时光机。Velero Server 是时光机本体,Velero CLI 是操作面板,MinIO 是存储时光快照的“能量块”。需要时,我就能启动时光机,回到过去某个完好无损的时间点。
第二章:搭建后方仓库 —— 部署 MinIO
首先,得有个地方存备份文件。我决定直接在 K8s 集群里部署一个 MinIO 服务,方便快捷。
2.1 准备 MinIO 的部署文件
我创建了一个 minio-deployment.yaml 文件,把 Namespace, Deployment, Service 都写在了一起。
apiVersion: v1
kind: Namespace
metadata:
name: minio
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: minio
namespace: minio
spec:
replicas: 1
selector:
matchLabels:
app: minio
template:
metadata:
labels:
app: minio
spec:
containers:
- name: minio
# 找了个稳定的 MinIO 镜像版本
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
args:
- server
- /data
- --console-address
- :9001
env:
- name: MINIO_ROOT_USER
value: "minioadmin" # Access Key
- name: MINIO_ROOT_PASSWORD
value: "minioadmin123" # Secret Key
ports:
- containerPort: 9000 # API 端口
- containerPort: 9001 # Web 控制台端口
---
apiVersion: v1
kind: Service
metadata:
name: minio-service
namespace: minio
spec:
type: ClusterIP # 用 ClusterIP 就够了,主要是给集群内部的 Velero 用
ports:
- port: 9000
targetPort: 9000
protocol: TCP
name: api
- port: 9001
targetPort: 9001
protocol: TCP
name: console
selector:
app: minio2.2 一键部署
kubectl apply -f minio-deployment.yaml执行完,MinIO 服务就在 minio 命名空间里静静地跑起来了。
第三章:配置 MinIO Bucket
3.1 安装 MinIO 客户端 (mc)
我选择在 K8s Master 节点上安装 mc 工具,方便操作。
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/3.2 临时打通本地到 MinIO 的隧道
为了能在 Master 节点上操作集群里的 MinIO,我用 port-forward 搭了个“临时桥梁”。
⚠️ 注意:这个命令会一直挂起,我得新开一个 SSH 窗口来执行后面的操作。
# 在第一个终端窗口执行
kubectl port-forward -n minio svc/minio-service 9000:90003.3 连接并创建 Bucket
在新的终端窗口里,我先配置 mc 连接,然后创建一个叫 velero 的 Bucket。
# 配置 mc 客户端连接
mc alias set myminio http://127.0.0.1:9000 minioadmin minioadmin123
# 创建一个名为 velero 的 Bucket
mc mb myminio/velero看到 Bucket created successfully 'myminio/velero'. 的提示,就说明货架准备好了。
最后,回到第一个终端窗口,按 Ctrl + C 拆掉“临时桥梁”。
第四章:部署 Velero
4.1 准备 Velero 访问 MinIO 的“钥匙”
Velero 需要知道 MinIO 的账号密码才能访问。我创建了一个名为 credentials-velero 的文件来存放这些信息。
[default]
aws_access_key_id = minioadmin
aws_secret_access_key = minioadmin1234.2 安装 Velero 命令行工具 (CLI)
这个工具是我的“遥控器”,我在 Master 节点上安装它。
VERSION=v1.13.0
wget https://github.com/vmware-tanzu/velero/releases/download/${VERSION}/velero-${VERSION}-linux-amd64.tar.gz
tar -zxvf velero-${VERSION}-linux-amd64.tar.gz
sudo mv velero-${VERSION}-linux-amd64/velero /usr/local/bin/
# 检查一下装好了没
velero version看到客户端版本信息就表示OK了。
4.3 执行安装命令
这是最关键的一步,用 velero install 命令在 K8s 集群里部署 Velero Server。
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.9.0 \
--bucket velero \
--secret-file ./credentials-velero \
--use-volume-snapshots=false \
--backup-location-config \
region=minio,s3ForcePathStyle=true,s3Url=http://minio-service.minio.svc:9000💡 这条长命令的解释:
--provider aws: 使用 AWS S3 协议的插件。
--plugins ...: 指定插件镜像。
--bucket velero: 我们在 MinIO 里创建的 Bucket 名字。
--secret-file ...: 我们刚创建的包含账号密码的“钥匙”文件。
--use-volume-snapshots=false: 重要! 这次我先不搞 PV 数据备份,只备份 YAML 配置,所以禁用快照功能来简化流程。
--backup-location-config ...: 这里是精髓,告诉 Velero 我们要连接的不是真的 AWS S3,而是集群内部的 MinIO 服务。
region=minio: 区域随便写一个,比如 minio。
s3ForcePathStyle=true: 必须设置成 true,使用路径风格的地址。
s3Url=http://minio-service.minio.svc:9000: MinIO 在集群内部的访问地址。
4.4 检查部署结果
# 检查 Velero 和 MinIO 的 Pod 是否都正常运行
kubectl get pod -n velero -o wide
kubectl get pod -n minio -o wide
# 检查 Velero 的备份位置状态
velero backup-location get🎉 至此,Velero 已经成功部署并连接到了 MinIO! 🎉
第五章:备份与“灾难”恢复
5.1 准备“牺牲品”
我部署了一个简单的Nginx应用作为测试对象,放在 nginx-example 命名空间里。
# 1. 准备 nginx-deployment.yaml 文件
# (此处省略和原文一样的YAML内容)
# 2. 部署应用
kubectl apply -f nginx-deployment.yaml
# 3. 确认应用正常运行
kubectl get pods -n nginx-example -o wide
# 并用 curl 访问 Pod IP,确认能看到页面5.2 按下“备份”按钮
我决定把 Nginx-example 这个命名空间完整地备份下来。
# 创建一个名为 nginx-backup 的备份任务
velero backup create nginx-backup --include-namespaces nginx-example
# 检查备份状态
velero backup get当 STATUS 变为 Completed 时,备份就完成了。我还可以用 velero backup describe nginx-backup 看看都备份了些啥。

5.3 模拟“灾难”发生
我深吸一口气,执行了那条传说中的“删库”命令。
# 模拟手滑,删掉整个命名空间
kubectl delete namespace nginx-example5.4 启动时光机,回到过去!
现在,是时候让 Velero 表演了。
# 从之前的备份创建一个恢复任务
velero restore create nginx-restore --from-backup nginx-backup
# 检查恢复状态
velero restore getSTATUS 很快也变成了 Completed。我迫不及待地去检查结果。

5.5 见证奇迹
kubectl get pods -n nginx-example -o wide
[root@master231 ~/zhang]#kubectl get pods -n nginx-example -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-57d44965bf-h8nhh 1/1 Running 0 2m11s 10.100.1.69 worker232 <none> <none>
nginx-deployment-57d44965bf-jzv8z 1/1 Running 0 2m11s 10.100.1.70 worker232 <none> <none>
[root@master231 ~/zhang]#curl 10.100.1.69
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>yinzhengjie apps v1</title>
<style>
div img {
width: 900px;
height: 600px;
margin: 0;
}
</style>
</head>
<body>
<h1 style="color: green">凡人修仙传 v1 </h1>
<div>
<img src="1.jpg">
<div>
</body>
</html>熟悉的 Pod 名字回来了!IP 地址变了,但它们确确实实地 Running 在节点上。我再次用 curl 访问新的 Pod IP,看到了和之前一模一样的页面。

完美恢复!
到这里,这次用 Velero 快速搭建灾备方案的实践记录就告一段落了。回过头看,整个过程确实如预想中那样流畅和迅速。当看到被“误删”的 Nginx 服务在几分钟内原封不动地回来时,我心里那块石头总算是落地了。
这次经历让我深刻体会到,像 Velero 这样的工具,极大地降低了我们实施 K8s 数据保护的门槛。虽然初次配置需要一些步骤,但一旦这套“自动化保险”搭建起来,后续带来的安全感是无价的。
这次实践只是一个开始,Velero 还有很多更高级的玩法值得去探索,比如:
定时自动备份(Schedules):设置每天凌晨自动备份,彻底解放双手。
PV 数据快照:这次为了简化,我禁用了 PV 快照。在生产环境中,为有状态应用开启数据卷快照是必不可少的。
跨集群迁移:利用 Velero 将应用从一个集群无缝迁移到另一个,这在集群升级或云厂商迁移时简直是神器。
总而言之,为你的 Kubernetes 集群配备一套如 Velero 般的灾备方案,绝对是一项高回报的投资。希望我的这份实践笔记能对你有所启发,让我们都能更安心地在 K8s 的世界里驰骋。