# Kubernetes教程(五十二)---Velero快速入门：开源备份恢复工具实战



![velero-quickstart.png](https://img.lixueduan.com/kubernetes/cover/velero-quickstart.jpeg)

在之前的文章《[Kubernetes PVC Clone & Snapshot 实战：基于 Csi-Driver-Nfs 的完整示例](https://www.lixueduan.com/posts/kubernetes/51-pvc-clonesnapshot/)》中，我们探讨了如何使用 Kubernetes 内置的 PVC 克隆和快照功能进行数据保护。然而，当我们需要对整个 Kubernetes 集群进行全面的备份恢复时，就需要更专业的工具。

Velero（前身 Heptio Ark）正是这样一个专业的 Kubernetes 备份恢复工具，已成为 CNCF 毕业项目。它不仅能够备份持久卷数据，还能备份整个集群的应用配置、服务和资源状态，提供企业级的灾难恢复和集群迁移能力。

**你将学到：**
- Velero 架构原理和核心特性
- 单集群备份恢复完整操作流程
- 跨集群应用迁移实战演示
- 生产环境最佳实践和故障排查

<!--more-->

## 1. Velero 简介

### 1.1 什么是 Velero

在前一篇文章中我们介绍了 PVC 级别的数据保护方案，但当我们需要对整个 Kubernetes 应用栈进行备份恢复时，就需要更全面的解决方案。

Velero（前身 Heptio Ark）正是一个用于备份与恢复 Kubernetes 集群资源和持久卷（PV/PVC）的专业开源工具，提供安全可靠的数据保护解决方案。

> **Velero 在 Kubernetes 生态中已被广泛视为开源领域事实标准 / 最主流备份恢复工具（CNCF 毕业项目，社区采用率最高）。**

### 1.2 核心特性

* **集群资源备份恢复**：支持 Deployment、Service、ConfigMap、Secret 等 Kubernetes 资源的备份与恢复
* **持久卷数据保护**：通过云快照或文件系统备份工具（Kopia）保护 PVC 数据
* **定时备份调度**：支持自动化定时备份策略
* **跨集群迁移**：实现集群间应用和数据的安全迁移
* **多存储后端**：支持 S3、GCS、Azure Blob 等多种对象存储

### 1.3 适用场景

* **灾难恢复**：应对集群故障、误删除等意外情况
* **集群升级迁移**：安全地将应用迁移到新版本集群
* **开发测试**：为开发测试环境提供快速数据恢复能力
* **合规要求**：满足数据保护和审计合规需求

* **开源地址**：<https://github.com/vmware-tanzu/velero>
* **官方文档**：[https://velero.io/docs/v1.17/](https://velero.io/docs/v1.17/)

## 2. 架构和工作原理

### 2.1 组件构成

Velero 采用客户端-服务器架构：

* **服务端**：运行在 Kubernetes 集群中的控制器组件
* **客户端**：本地命令行工具，需要配置 kubectl 和集群 kubeconfig


### 2.2 备份流程

Velero 采用 Operator 模式，通过创建 CRD 对象触发备份操作：

![velero-workflow.png](https://img.lixueduan.com/kubernetes/velero/velero-workflow.png)


1. **创建备份任务**：Velero 客户端调用 Kubernetes API 创建 Backup CRD
2. **监听任务**：Backup Controller 通过 watch 机制获取备份任务
3. **收集数据**：Controller 通过 kube-apiserver 获取需要备份的资源数据
4. **存储备份**：将数据上传到指定的对象存储后端

### 2.3 存储后端配置

Velero 通过两种 CRD 管理存储后端：

#### BackupStorageLocation
定义 Kubernetes 集群资源的存储位置，主要用于存储 YAML 清单文件等元数据。支持 S3 兼容存储（如 MinIO、AWS S3、阿里云 OSS 等）。

#### VolumeSnapshotLocation
定义持久卷快照的存储位置，需要云提供商插件支持。对于不支持快照的环境，可以使用文件系统备份工具 Restic/Kopia。

> **Restic** 是一款用 Go 语言开发的数据加密备份工具，支持多种存储后端：Local、SFTP、AWS S3、MinIO、Azure Blob Storage、Google Cloud Storage 等。  
> **Kopia** 是 Velero 从 v1.10 版本开始引入的新一代 文件级备份工具，用于替代传统的 Restic，相比 Restic 具有更好的性能和可靠性。

## 3. 安装部署

### 3.1 准备工作

#### 存储插件选择
Velero 支持多种存储插件，可通过 [官方文档](https://velero.io/docs/v1.17/supported-providers/) 查看完整列表。本教程使用 MinIO 作为 S3 兼容的对象存储。

#### MinIO 部署
可以参考 MinIO 官方文档部署服务，或使用 Velero 提供的快速部署脚本：

```bash
kubectl apply -f https://raw.githubusercontent.com/vmware-tanzu/velero/main/examples/minio/00-minio-deployment.yaml
```

### 3.2 安装 CLI 工具

到 [GitHub release](https://github.com/vmware-tanzu/velero/releases/latest) 页面下载最新压缩包：

```bash
wget https://github.com/vmware-tanzu/velero/releases/download/v1.17.2/velero-v1.17.2-linux-amd64.tar.gz

tar -zxvf velero-v1.17.2-linux-amd64.tar.gz

mv velero-v1.17.2-linux-amd64/velero /usr/local/bin/

# 查看版本
velero version
```

### 3.3 安装服务端组件

#### 创建认证文件
先创建 S3 配置文件，提供 MinIO 的访问凭证：

```bash
cat > credentials-s3 <<EOF
[default]
aws_access_key_id = your-access-key-id
aws_secret_access_key = your-secret-access-key
EOF
```

#### 部署 Velero 服务端
开始部署 Velero 服务端组件：

```bash
REGISTRY=docker.io
S3URL=http://your-minio-endpoint:port
BUCKET=velero

velero install    \
     --namespace velero  \
     --provider aws   \
     --image $REGISTRY/velero/velero:v1.17.2  \
     --plugins $REGISTRY/velero/velero-plugin-for-aws:v1.13.2  \
     --secret-file ./credentials-s3  \
     --bucket $BUCKET \
     --use-node-agent \
     --use-volume-snapshots=false \
     --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=$S3URL
```

**参数说明**：

* `--namespace`：指定部署的 namespace 名称，默认为 velero
* `--provider`：定义插件提供方，aws 表示 AWS S3 兼容
* `--image`：定义运行 velero 的镜像
* `--plugins`：指定使用 aws s3 兼容的插件镜像
* `--secret-file`：指定对象存储认证文件
* `--bucket`：指定对象存储 Bucket 桶名称
* `--use-node-agent`：创建 Velero Node Agent 守护进程，用于通过 Kopia 备份 PVC 数据
* `--use-volume-snapshots`：是否启用快照功能

> **注意**：从 Velero 1.7 开始，Kopia 成为默认的文件系统备份工具，取代了之前的 Restic。Kopia 提供了更好的性能和可靠性。
* `--backup-location-config`：指定对象存储地址信息
  * `region`：MinIO 本身没有区域概念，但 AWS S3 插件需要 region 参数，因此使用 `minio` 作为占位符
  * `s3ForcePathStyle`：路径风格访问，强制使用路径风格的 URL（`http://endpoint/bucket/key`），这是 MinIO 的推荐访问方式
  * `s3Url`：MinIO 服务地址

#### 验证安装状态
```bash
# 检查 Pod 状态
kubectl -n velero get pod

# 查看 BackupStorageLocation
kubectl -n velero get BackupStorageLocation

# 示例输出：
# NAME      PHASE       LAST VALIDATED   AGE     DEFAULT
# default   Available   43s              5m      true
```

### 3.4 卸载 Velero

如果需要从集群中完全卸载 Velero：

```bash
# 使用 velero 命令卸载
velero uninstall

# 或者手动删除相关资源
kubectl delete namespace/velero clusterrolebinding/velero
kubectl delete crds -l component=velero
```

## 4. 基础操作

### 4.1 备份命令详解

备份命令：`velero create backup NAME [flags]`

### 4.2 定时备份配置

除了手动备份外，Velero 还支持定时备份，可以通过 Schedule CRD 实现自动化备份：

```bash
# 创建每天凌晨2点的定时备份
velero create schedule daily-backup \
    --schedule="0 2 * * *" \
    --include-namespaces nginx-example \
    --default-volumes-to-fs-backup \
    --ttl 72h

# 查看定时备份列表
velero get schedules

# 查看定时备份的执行历史
velero get backups --selector velero.io/schedule-name=daily-backup
```

**定时表达式说明**：
- `0 2 * * *`：每天凌晨2点执行
- `0 */6 * * *`：每6小时执行一次
- `0 0 * * 0`：每周日午夜执行

**常用选项**：

* `--exclude-namespaces stringArray`：从备份中排除的命名空间
* `--exclude-resources stringArray`：从备份中排除的资源类型
* `--include-cluster-resources optionalBool[=true]`：是否包含集群级资源
* `--include-namespaces stringArray`：要包含的命名空间（默认 '*'）
* `--include-resources stringArray`：要备份的资源类型
* `--labels mapStringString`：为备份添加标签
* `-o, --output string`：输出格式（table/json/yaml）
* `-l, --selector labelSelector`：按标签筛选资源
* `--snapshot-volumes optionalBool[=true]`：是否为 PV 创建快照
* `--storage-location string`：指定备份位置
* `--ttl duration`：备份数据的过期时间
* `--volume-snapshot-locations strings`：指定快照位置


## 5. 实战演示：单集群备份恢复

### 5.1 创建测试应用

创建一个 Nginx 应用并挂载 PVC，用于验证备份恢复功能：

```yaml
cat > nginx-demo.yaml <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-example
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-html-pvc
  namespace: nginx-example
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs  # 请修改为你的集群中可用的StorageClass
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: nginx-example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.cn-shanghai.aliyuncs.com/99cloud-sh/nginx:1.20
        ports:
        - containerPort: 80
        volumeMounts:
        - name: html-volume
          mountPath: /usr/share/nginx/html  # Nginx默认的网页根目录
      volumes:
      - name: html-volume
        persistentVolumeClaim:
          claimName: nginx-html-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: nginx-example
spec:
  type: NodePort  # 为了方便从集群外部访问，使用NodePort类型
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
EOF
```

```bash
kubectl apply -f nginx-demo.yaml
```

### 5.2 写入测试数据

```bash
# 获取 Nginx Pod 名称
NGINX_POD=$(kubectl get pods -n nginx-example -l app=nginx -o jsonpath='{.items[0].metadata.name}')
echo $NGINX_POD

# 创建测试文件并复制到 Pod
echo '<h1>Hello from Velero Backup Demo!</h1><p>This file was created on '"$(date)"'.</p>' > test-index.html
kubectl cp test-index.html nginx-example/$NGINX_POD:/usr/share/nginx/html/index.html

# 验证数据写入
kubectl get svc nginx-service -n nginx-example
curl http://<cluster-ip>:80
```

### 5.3 执行备份

```bash
velero backup create nginx-backup-pvc --include-namespaces nginx-example --default-volumes-to-fs-backup
```

**参数说明**：
* `--include-namespaces`：指定要备份的命名空间
* `--default-volumes-to-fs-backup`：使用文件系统备份工具备份 PVC 数据

### 5.4 监控备份状态

```bash
# 查看备份列表
velero backup get

# 示例输出：
# NAME               STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
# nginx-backup-pvc   Completed   0        0          2026-01-27 08:36:54 +0000 UTC   29d       default            <none>

# 查看详细备份信息
velero backup describe nginx-backup-pvc

# 查看备份日志
velero backup logs nginx-backup-pvc
```

### 5.5 验证备份结果

备份完成后，可以在 MinIO 存储中查看备份内容：

**Kubernetes 资源配置备份**：
![velero-save-in-minio-yaml.png](https://img.lixueduan.com/kubernetes/velero/velero-save-in-minio-yaml.png)

**PVC 数据文件备份**：
![velero-save-in-minio-pvc.png](https://img.lixueduan.com/kubernetes/velero/velero-save-in-minio-pvc.png)




### 5.5 模拟灾难恢复

```bash
# 删除应用模拟灾难
kubectl delete namespace nginx-example

# 执行恢复
velero restore create --from-backup nginx-backup-pvc

# 监控恢复进度
velero restore get

# 示例输出：
# NAME                              BACKUP             STATUS      STARTED                         COMPLETED                       ERRORS   WARNINGS   CREATED                         SELECTOR
# nginx-backup-pvc-20260127084915   nginx-backup-pvc   Completed   2026-01-27 08:49:15 +0000 UTC   2026-01-27 08:49:23 +0000 UTC   0        1          2026-01-27 08:49:15 +0000 UTC   <none>

# 验证恢复结果
kubectl -n nginx-example get pod,svc,pvc
curl <nginx-service-cluster-ip>
```



## 6. 高级功能：跨集群迁移

**只要我们将每个 velero 实例指向相同的对象存储，velero 就能将资源从一个群集迁移到另一个群集。**

![velero-demo-cross-cluster.png](https://img.lixueduan.com/kubernetes/velero/velero-demo-cross-cluster.png)



### 6.1 环境要求

* **集群版本一致**：建议两个 Kubernetes 集群版本保持一致
* **存储类匹配**：确保目标集群有相同名称的 StorageClass
* **共享存储后端**：两个集群的 Velero 需连接同一对象存储



以下是集群信息：

| 角色      | 集群IP           | 集群版本    | 部署软件            |
| ------- | -------------- | ------- | --------------- |
| K8S 集群A | 172.16.131.134 | v1.34.2 | velero、demo-app |
| K8S 集群B | 172.16.131.171 | v1.34.2 | velero、minio    |



### 6.2 源集群操作

在集群 A 部署上应用。



#### 部署测试应用

创建一个 nginx app，并挂载 pvc 用于验证备份恢复功能。

```bash
cat > nginx-demo.yaml <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-example
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-html-pvc
  namespace: nginx-example
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs  # 请修改为你的集群中可用的StorageClass
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: nginx-example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.cn-shanghai.aliyuncs.com/99cloud-sh/nginx:1.20
        ports:
        - containerPort: 80
        volumeMounts:
        - name: html-volume
          mountPath: /usr/share/nginx/html  # Nginx默认的网页根目录
      volumes:
      - name: html-volume
        persistentVolumeClaim:
          claimName: nginx-html-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: nginx-example
spec:
  type: NodePort  # 为了方便从集群外部访问，使用NodePort类型
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
EOF
```



```bash
kubectl apply -f nginx-demo.yaml
```



#### 写入测试

```Bash
NGINX_POD=$(kubectl get pods -n nginx-example -l app=nginx -o jsonpath='{.items[0].metadata.name}')
echo $NGINX_POD
```

将一个简单的 html 复制到 nginx 数据目录中

```Bash
# 首先在本机创建一个测试文件
echo '<h1>Hello from Velero Backup Demo!</h1><p>This file was created on '"$(date)"'.</p>' > test-index.html
# 将文件拷贝到Pod内的PVC目录
kubectl cp test-index.html nginx-example/$NGINX_POD:/usr/share/nginx/html/index.html
```

访问 nginx 进行验证

```Bash
kubectl get svc nginx-service -n nginx-example
# 使用输出的NodePort端口访问，例如节点IP为192.168.1.100，端口为32000
curl http://<cluster-ip>:80

root@lixd-dev-2:~# curl 10.111.66.141
<h1>Hello from Velero Backup Demo!</h1><p>This file was created on Tue Jan 27 07:49:17 UTC 2026.</p>
```



#### Velero 备份

```Bash
root@lixd-dev-1:~/velero# velero backup create nginx-backup-pvc --include-namespaces nginx-example --default-volumes-to-fs-backup
Backup request "nginx-backup-pvc" submitted successfully.
Run `velero backup describe nginx-backup-pvc` or `velero backup logs nginx-backup-pvc` for more details.
```

参数：

- `--include-namespaces`：指定命名空间，这里测试仅备份 nginx-example 下的内容。
- `--default-volumes-to-fs-backup`：使用**文件系统备份工具**（Kopia）来备份数据。这种方式更通用。

查看状态

```Bash
root@lixd-dev-1:~/velero# velero backup get
NAME               STATUS       ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
nginx-backup-pvc   InProgress   0        0          2026-01-28 07:41:25 +0000 UTC   29d       default            <none>
root@lixd-dev-1:~/velero# velero backup get
NAME               STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
nginx-backup-pvc   Completed   0        0          2026-01-28 07:41:25 +0000 UTC   29d       default            <none>

# 查看备份详细信息
$ velero backup describe nginx-backup
 
# 查看备份日志
$ velero backup logs nginx-backup
```

这样就备份好了。



### 6.4 集群 B 恢复

#### 恢复

在目标集群查看备份对象（如果连接到同一个 S3 存储，Velero 会自动同步）：

```bash
root@lixd-dev-2:~# velero get backup
NAME               STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
nginx-backup-pvc   Completed   0        0          2026-01-28 07:41:25 +0000 UTC   29d       default            <none>
```

恢复数据

```Bash
root@lixd-dev-2:~# velero restore create --from-backup nginx-backup-pvc
Restore request "nginx-backup-20260127075810" submitted successfully.
Run `velero restore describe nginx-backup-20260127075810` or `velero restore logs nginx-backup-20260127075810` for more details.
```

查看恢复进度

```Bash
root@lixd-dev-2:~# velero restore get
NAME                              BACKUP             STATUS       STARTED                         COMPLETED   ERRORS   WARNINGS   CREATED                         SELECTOR
nginx-backup-pvc-20260128080008   nginx-backup-pvc   InProgress   2026-01-28 08:00:08 +0000 UTC   <nil>       0        0          2026-01-28 08:00:08 +0000 UTC   <none>
root@lixd-dev-2:~# velero restore get
NAME                              BACKUP             STATUS      STARTED                         COMPLETED                       ERRORS   WARNINGS   CREATED                         SELECTOR
nginx-backup-pvc-20260128080008   nginx-backup-pvc   Completed   2026-01-28 08:00:08 +0000 UTC   2026-01-28 08:00:17 +0000 UTC   0        1          2026-01-28 08:00:08 +0000 UTC   <none>
```



#### 验证

验证 Nginx 是否完全恢复

```Bash
root@lixd-dev-2:~/velero# kubectl -n nginx-example get po
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-7cf7667b79-cmjfm   1/1     Running   0          41s
root@lixd-dev-2:~/velero# kubectl -n nginx-example get svc
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
nginx-service   NodePort   10.103.125.238   <none>        80:32285/TCP   42s
root@lixd-dev-2:~/velero# kubectl -n nginx-example get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
nginx-html-pvc   Bound    pvc-99f0060d-fd8b-4887-a5e5-cdc6858d3590   1Gi        RWO            nfs            <unset>                 45s
root@lixd-dev-2:~# curl 10.111.49.149
<h1>Hello from Velero Backup Demo!</h1><p>This file was created on Wed Jan 28 07:48:15 UTC 2026.</p>
```

一切正常。

跨集群迁移完成。



## 小结

Velero 作为一个成熟的 Kubernetes 备份恢复工具，提供了完整的灾难恢复和集群迁移解决方案。通过本文的实战演示，您可以掌握：

1. **Velero 的基本安装和配置**
2. **单集群内应用的备份恢复操作**
3. **跨集群的应用和数据迁移流程**
4. **生产环境的最佳实践建议**


---

> 作者: [意琦行](https://github.com/lixd)  
> URL: https://www.lixueduan.com/posts/kubernetes/53-velero-quickstart/  

