最近在生产环境折腾 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: minio

2.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:9000

3.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 = minioadmin123

4.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-example

5.4 启动时光机,回到过去!

现在,是时候让 Velero 表演了。

# 从之前的备份创建一个恢复任务
velero restore create nginx-restore --from-backup nginx-backup

# 检查恢复状态
velero restore get

STATUS 很快也变成了 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 的世界里驰骋。