Velero 备份还原 Kubernetes 集群
每个 Velero 的操作(比如按需备份、计划备份、还原)都是 CRD 自定义资源,Velero 可以备份或还原集群中的所有对象,也可以按类型、namespace 或标签过滤对象。
Velero(https://velero.io)(可以提供备份和还原 Kubernetes 集群资源和持久卷的能力,你可以在公有云或本地搭建的私有云环境安装 Velero,可以为你提供以下能力:
- 备份集群数据,并在集群故障的情况下进行还原
- 将集群资源迁移到其他集群
- 将生产集群复制到开发和测试集群
Velero 包含一个在集群上运行的服务器端和在本地运行的命令行客户端。
1 Velero 介绍
每个 Velero 的操作(比如按需备份、计划备份、还原)都是 CRD 自定义资源,Velero 可以备份或还原集群中的所有对象,也可以按类型、namespace 或标签过滤对象。Velero 是 Kubernetes 用来灾难恢复的理想选择,也可以在集群上执行系统操作(比如升级)之前对应用程序状态进行快照的理想选择。
1.1 按需备份
按需备份操作可以将复制的 Kubernetes 对象的压缩文件上传到云对象存储中,也可以调用云环境提供的 API 来创建持久化卷的磁盘快照。我们可以选择指定在备份期间执行的备份 hook,比如你可能需要在拍摄快照之前告诉数据库将其内存中的缓冲区刷新到磁盘。
需要注意的是集群备份并不是严格的原子备份,如果在备份时创建或编辑 Kubernetes 对象,则它们可能不会被包含在备份中,是可能出现这种状况的。
1.2 定时备份
通过定时操作,我们可以定期备份数据,第一次创建日程表时将执行第一次备份,随后的备份将按日程表指定的间隔进行备份,这些间隔由 Cron 表达式指定。
定时备份保存的名称为 <SCHEDULE NAME>-<TIMESTAMP>
,其中 <TIMESTAMP>
格式为 YYYYMMDDhhmmss
。
1.3 备份还原
通过还原操作,我们可以从以前创建的备份中还原所有对象和持久卷,此外我们还可以仅还原对象和持久卷的子集,Velero 支持多个命名空间重新映射。例如在一次还原操作中,可以在命名空间 def 下重新创建命名空间 abc 中的对象,或在 456 之下重新创建名称空间 123 中的对象。
还原的默认名称为<BACKUP NAME>-<TIMESTAMP>
,<TIMESTAMP>
格式为 YYYYMMDDhhmmss
,还可以指定自定义名称,恢复的对象还包括带有键 velero.io/restore-name
和值的标签 <RESTORE NAME>
。
默认情况下,备份存储位置以读写模式创建,但是,在还原期间,可以将备份存储位置配置为只读模式,这将禁用该存储位置的备份创建和删除,这对于确保在还原方案期间不会无意间创建或删除任何备份非常有用。此外我们还可以选择指定在还原期间或还原资源后执行的还原 hook,例如可能需要在数据库应用程序容器启动之前执行自定义数据库还原操作。
1.4 备份流程
执行命令 velero backup create test-backup 的时候,会执行下面的操作:
- Velero 客户端调用 Kubernetes APIServer 创建 Backup 这个 CRD 对象
- Backup 控制器 watch 到新的 Backup 对象被创建并执行验证
- Backup 控制器开始执行备份,通过查询 APIServer 来获取资源收集数据进行备份
- Backup 控制器调用对象存储服务,比如 S3 上传备份文件
默认情况下 velero backup create
支持任何持久卷的磁盘快照,可以通过指定其他参数来调整快照,可以使用 --snapshot-volumes=false
选项禁用快照。
下面是 Velero 备份的工作原理图:
下面是 Velero 如何恢复工作:
1.5 设置备份过期时间
创建备份时,可以通过添加标志 –ttl 来指定 TTL,如果未指定,则将默认的 TTL 值为30天,如果 Velero 检测到有备份资源已过期,它将删除以下相应备份数据:
- 备份资源
- 来自云对象存储的备份文件
- 所有 PersistentVolume 快照
- 所有关联的还原
1.6 同步对象存储
Velero 将对象存储视为资源的来源,它不断检查以确保始终存在正确的备份资源,如果存储桶中有格式正确的备份文件,但 Kubernetes APIServer 中没有相应的备份资源,则 Velero 会将信息从对象存储同步到 Kubernetes,这使还原功能可以在集群迁移方案中工作,在该方案中,新集群中不存在原始的备份对象。同样,如果备份对象存在于 Kubernetes 中,但不存在于对象存储中,则由于备份压缩包不再存在,它将从 Kubernetes 中删除。
1.7 Velero的特性
Velero
目前包含以下特性:
- 支持
Kubernetes
集群数据备份和恢复 - 支持复制当前
Kubernetes
集群的资源到其它Kubernetes
集群 - 支持复制生产环境到开发以及测试环境
1.8 Velero组件
Velero
组件一共分两部分,分别是服务端和客户端。
- 服务端:运行在你
Kubernetes
的集群中 - 客户端:是一些运行在本地的命令行的工具,需要已配置好
kubectl
及集群kubeconfig
的机器上
1.9 支持备份存储
- AWS S3 以及兼容 S3 的存储,比如:Minio
- Azure BloB 存储
- Google Cloud 存储
- Aliyun OSS 存储(github.com/AliyunConta…)
Velero 有两个自定义资源 BackupStorageLocation
和 VolumeSnapshotLocation
,用于配置 Velero 备份及其关联的持久卷快照的存储位置。
BackupStorageLocation
:定义为存储区,存储所有 Velero 数据的存储区中的前缀以及一组其他特定于提供程序的字段,后面部分会详细介绍该部分所包含的字段。VolumeSnapshotLocation
:完全由提供程序提供的特定的字段(例如AWS区域,Azure资源组,Portworx快照类型等)定义。
用户可以预先配置一个或多个可能的 BackupStorageLocations
对象,也可以预先配置一个或多个 VolumeSnapshotLocations
对象,并且可以在创建备份时选择应该存储备份和相关快照的位置。
此配置设计支持许多不同的用法,包括:
- 在单个 Velero 备份中创建不止一种持久卷的快照。例如,在同时具有 EBS 卷和 Portworx 卷的集群中
- 在不同地区将数据备份到不同的存储中
- 对于支持它的卷提供程序(例如Portworx),可以将一些快照存储在本地集群中,而将其他快照存储在云中
2 Velero 概述
2.1 适用场景
灾备场景
:提供备份恢复k8s集群的能力迁移场景
:提供拷贝集群资源到其他集群的能力(复制同步开发,测试,生产环境的集群配置,简化环境配置)
2.2 与etcd的区别
与 Etcd 备份相比,直接备份 Etcd
是将集群的全部资源备份起来。而 Velero
就是可以对 Kubernetes
集群内对象级别进行备份。除了对 Kubernetes
集群进行整体备份外,Velero
还可以通过对 Type
、Namespace
、Label
等对象进行分类备份或者恢复。
3 实践velero备份minio
在我们的示例中,我们将在 Kubernetes 集群中使用 MinIO 作为备份图中所示的“云提供者”。MinIO 是一个使用 S3兼容 API 的对象存储,因此可以用来存储备份的资源。
Velero 使用 Restic 备份 Kubernetes 卷。Restic 是一个快速、安全的文件系统备份程序,其文档可以在这里找到。它的工作方式是扫描卷目录中的文件,然后将这些文件分割成 blobs,然后发送到 MinIO。下面是它如何与 Velero 集成。
必要条件:
- 带有 DNS 的 Kubernetes 集群版本1.19至1.23
- Velero cli 安装了 https://Velero.io/docs/main/basic-install/(velero 也可以通过 helm 进行安装)
3.1 安装 velero 1.9.0
GitHub:https://github.com/vmware-tanzu/velero/releases
1 下载 1.90
root@master:~# wget https://github.com/vmware-tanzu/velero/releases/download/v1.9.0/velero-v1.9.0-linux-amd64.tar.gz
2 解压
root@master:~# tar xf velero-v1.9.0-linux-amd64.tar.gz
root@master:~/velero-v1.9.0-linux-amd64# tree
.
├── examples
│ ├── minio
│ │ └── 00-minio-deployment.yaml # minio yaml
│ ├── nginx-app # 示例 yaml
│ │ ├── base.yaml
│ │ ├── README.md
│ │ └── with-pv.yaml
│ └── README.md
├── LICENSE
└── velero # 二进制程序
# 拷贝到 sbin 目录下
root@master:~# cp velero-v1.9.0-linux-amd64/velero /usr/local/sbin/
3 验证命令
root@master:~# velero version
Client:
Version: v1.9.0
Git commit: 6021f148c4d7721285e815a3e1af761262bff029
<error getting server version: no matches for kind "ServerStatusRequest" in version "velero.io/v1">
3.2 安装minio
这里我们可以使用 minio 来代替云环境的对象存储,在上面解压的压缩包中包含一个 examples/minio/00-minio-deployment.yaml 的资源清单文件,为了测试方便可以将其中的 Service 更改为 NodePort 类型,我们可以配置一个 console-address 来提供一个 console 页面的访问入口,完整的资源清单文件如下所示:
3.2.1 K8S 安装方式
1 修改 yaml 编辑 svc 字段
root@master:~/velero-v1.9.0-linux-amd64/examples/minio# vim 00-minio-deployment.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: velero
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: velero
name: minio
labels:
component: minio
spec:
strategy:
type: Recreate
selector:
matchLabels:
component: minio
template:
metadata:
labels:
component: minio
spec:
volumes:
- name: storage
emptyDir: {}
- name: config
emptyDir: {}
containers:
- name: minio
image: minio/minio:latest
imagePullPolicy: IfNotPresent
args:
- server
- /storage
- --config-dir=/config
- --console-address=:9001
env:
- name: MINIO_ACCESS_KEY
value: "minio"
- name: MINIO_SECRET_KEY
value: "minio123"
ports:
- containerPort: 9000
- containerPort: 9001
volumeMounts:
- name: storage
mountPath: "/storage"
- name: config
mountPath: "/config"
---
apiVersion: v1
kind: Service
metadata:
namespace: velero
name: minio
labels:
component: minio
spec:
# ClusterIP is recommended for production environments.
# Change to NodePort if needed per documentation,
# but only if you run Minio in a test/trial environment, for example with Minikube.
type: NodePort
ports:
- name: api
port: 9000
targetPort: 9000
protocol: TCP
- name: console
port: 9001
targetPort: 9001
selector:
component: minio
---
apiVersion: batch/v1
kind: Job
metadata:
namespace: velero
name: minio-setup
labels:
component: minio
spec:
template:
metadata:
name: minio-setup
spec:
restartPolicy: OnFailure
volumes:
- name: config
emptyDir: {}
containers:
- name: mc
image: minio/mc:latest
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- "mc --config-dir=/config config host add velero http://minio:9000 minio minio123 && mc --config-dir=/config mb -p velero/velero"
volumeMounts:
- name: config
mountPath: "/config"
由上面资源清淡我们可以看到,在安装minio的时候
MINIO_ACCESS_KEY:minio
MINIO_SECRET_KEY:minio123
service的地址为:http://minio:9000,类型为ClusterIP,我们可以映射为NodePort查看
最后执行了一个job来创建一个名称为:velero/velero的bucket,在创建的时候适应了。
2 部署
root@master:~/velero-v1.9.0-linux-amd64/examples/minio# kubectl apply -f 00-minio-deployment.yaml
namespace/velero created
deployment.apps/minio created
service/minio created
job.batch/minio-setup created
# 查看 velero NS 下所有资源
root@master:~/velero-v1.9.0-linux-amd64/examples/minio# kubectl get all -n velero
NAME READY STATUS RESTARTS AGE
pod/minio-6db8cd4c55-kcwvl 1/1 Running 0 111s
pod/minio-setup-5pl8n 0/1 Completed 2 7m46s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/minio NodePort 10.96.73.145 <none> 9000:31900/TCP,9001:21365/TCP 7m46s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/minio 1/1 1 1 7m46s
NAME DESIRED CURRENT READY AGE
replicaset.apps/minio-58fb7cfdc8 0 0 0 7m46s
replicaset.apps/minio-6db8cd4c55 1 1 1 111s
NAME COMPLETIONS DURATION AGE
job.batch/minio-setup 1/1 18s 7m46s
3 访问 console 地址
http://10.0.0.140:21365 访问 minio 的 console 页面使用 minio 与 minio123 进行登录即可:
![image-20220817220746844](Velero 备份还原 Kubernetes 集群.assets/image-20220817220746844.png)
3.2.2 二进制安装方式
当然如果需要在不同 Kubernetes 和存储池集群备份与恢复数据,需要将 minio 服务端安装在 Kubernetes 集群外,保证在集群发生灾难性故障时,不会对备份数据产生影响,可以通过二进制的方式进行安装。
1 在待安装 minio 的服务器上下载二进制包
➜ ~ wget https://dl.minio.io/server/minio/release/linux-amd64/minio
➜ ~ chmod +x minio
➜ ~ sudo mv minio /usr/local/bin/
➜ ~ minio --version
minio version RELEASE.2022-08-13T21-54-44Z (commit-id=49862ba3470335decccecb27649167025e18c406)
Runtime: go1.18.5 linux/amd64
License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>
Copyright: 2015-2022 MinIO, Inc.
2 准备对象存储的磁盘,这里我们跳过该步骤,可以使用 systemd 来方便管理 minio 服务,对于使用 systemd init 系统运行系统的人,请创建用于运行 minio 服务的用户和组:
➜ ~ sudo groupadd --system minio
➜ ~ sudo useradd -s /sbin/nologin --system -g minio minio
3 为 /data(上述步骤准备好的磁盘挂载位置)目录提供 minio 用户所有权:
➜ ~ sudo chown -R minio:minio /data/
➜ ~ sudo chmod 775 /data
4 为 minio 创建 systemd 服务单元文件:
➜ ~ vi /etc/systemd/system/minio.service
[Unit]
Description=Minio
Documentation=https://docs.minio.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio
[Service]
WorkingDirectory=/data
User=minio
Group=minio
EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
# Let systemd restart this service always
Restart=always
# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536
# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no
[Install]
WantedBy=multi-user.target
5 创建 minio 环境文件 /etc/default/minio:
➜ ~ vim /etc/default/minio
# Volume to be used for Minio server.
MINIO_VOLUMES="/data"
# Use if you want to run Minio on a custom port.
MINIO_OPTS="--address :9000"
# Access Key of the server.
MINIO_ACCESS_KEY=minio
# Secret key of the server.
MINIO_SECRET_KEY=minio123
6 其中 MINIO_ACCESS_KEY 为长度至少为3个字符的访问密钥,MINIO_SECRET_KEY 为最少8个字符的密钥。重新加载 systemd 并启动 minio 服务:
➜ ~ sudo systemctl daemon-reload
➜ ~ sudo systemctl start minio
关于 minio 的更多使用方法可以参考官方文档 https://docs.min.io/ 了解更多。
3.3 安装 velero 服务端
我们可以使用 velero 客户端来安装服务端,也可以使用 Helm Chart 来进行安装,比如这里我们用客户端来安装,velero 命令默认读取 kubectl 配置的集群上下文,所以前提是 velero 客户端所在的节点有可访问集群的 kubeconfig 配置。
1 首先准备密钥文件,在当前目录建立一个空白文本文件,内容如下所示:=
# 回到 K8S 节点操作
root@master:~# cat > credentials-velero <<EOF
> [default]
> aws_access_key_id = minio
> aws_secret_access_key = minio123
> EOF
velero-plugin-for-aws 插件:支持在 AWS 上运行 Velero
https://github.com/vmware-tanzu/velero-plugin-for-aws
2 替换为之前步骤中 minio 的对应 access key id 和 secret access key如果 minio 安装在 kubernetes 集群内时按照如下命令安装 velero 服务端:
velero install \
--provider aws \
--image velero/velero:v1.9.0 \
--plugins velero/velero-plugin-for-aws:v1.5.0 \
--bucket velero \
--secret-file ./credentials-velero \
--use-volume-snapshots=false \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://10.0.0.140:31900
# ......省略......最后安装完成会出现下面这句提示
Velero is installed! ⛵ Use 'kubectl logs deployment/velero -n velero' to view the status.
- –provider 声明“aws”提供的插件类型
- –plugins 使用 AWS S3 兼容 API 插件“velero-plugin-for-aws”
Plugin Version | Velero Version |
---|---|
v1.5.x | v1.9.x |
v1.4.x | v1.8.x |
v1.3.x | v1.7.x |
v1.2.x | v1.6.x |
v1.1.x | v1.5.x |
v1.1.x | v1.4.x |
v1.0.x | v1.3.x |
v1.0.x | v1.2.0 |
- –secret-file 访问对象存储的凭证
- –use-volume-snapshots Velero 没有适用于云的卷快照插件,因此禁用了创建卷快照
- –use-restic 使用开源免费备份工具备份和恢复持久卷数据。但是,不支持“hostPath”卷, 该集成补充了 Velero 的备份功能,建议打开
- –default-volumes-to-restic 允许使用 Restic 备份所有 Pod 卷,前提是需要打开 –use-restic 参数
- –backup-location-config 备份与存储桶访问相关的配置
- region 指定地域,minio没有地域之分,所以随便写了个minio
- s3ForcePathStyle 使用 S3 文件路径格式
- s3Url 指定s3的地址
3 查看 api 版本
root@master:~# kubectl api-versions | grep velero
velero.io/v1
4 查看 pod
root@master:~# kubectl get pod -n velero
NAME READY STATUS RESTARTS AGE
minio-6db8cd4c55-kcwvl 1/1 Running 0 16h
minio-setup-5pl8n 0/1 Completed 2 16h
velero-679bbddd96-nlt9v 1/1 Running 0 13m\
至此velero就已经全部部署完成。
3.4 测试
velero非常的人性化,在安装包中已经为我们准备好了测试demo,我们可以利用测试demo来进行测试验证。
3.4.1 创建 demo
1 创建
root@master:~# kubectl apply -f velero-v1.9.0-linux-amd64/examples/nginx-app/base.yaml
2 创建成功
root@master:~# kubectl get all -n nginx-example
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-5c844b66c8-98sgx 1/1 Running 0 3m3s
pod/nginx-deployment-5c844b66c8-cbcf4 1/1 Running 0 3m3s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-nginx LoadBalancer 10.102.111.211 <pending> 80:20134/TCP 3m4s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 2/2 2 2 3m4s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-5c844b66c8 2 2 2 3m4s
3.4.2 执行备份
# 指定对 nginx-example NS 做备份
root@master:~# velero backup create nginx-backup --include-namespaces nginx-example
# velero backup create nginx-backup 创建备份为 nginx-backup
# --include-namespaces nginx-example 指定包含 nginx-example NS
4 velero 命令
$ velero create backup NAME [flags]
# 剔除 namespace
--exclude-namespaces stringArray namespaces to exclude from the backup
# 剔除资源类型
--exclude-resources stringArray resources to exclude from the backup, formatted as resource.group, such as storageclasses.storage.k8s.io
# 包含集群资源类型
--include-cluster-resources optionalBool[=true] include cluster-scoped resources in the backup
# 包含 namespace
--include-namespaces stringArray namespaces to include in the backup (use '*' for all namespaces) (default *)
# 包含 namespace 资源类型
--include-resources stringArray resources to include in the backup, formatted as resource.group, such as storageclasses.storage.k8s.io (use '*' for all resources)
# 给这个备份加上标签
--labels mapStringString labels to apply to the backup
-o, --output string Output display format. For create commands, display the object but do not send it to the server. Valid formats are 'table', 'json', and 'yaml'. 'table' is not valid for the install command.
# 对指定标签的资源进行备份
-l, --selector labelSelector only back up resources matching this label selector (default <none>)
# 对 PV 创建快照
--snapshot-volumes optionalBool[=true] take snapshots of PersistentVolumes as part of the backup
# 指定备份的位置
--storage-location string location in which to store the backup
# 备份数据多久删掉
--ttl duration how long before the backup can be garbage collected (default 720h0m0s)
# 指定快照的位置,也就是哪一个公有云驱动
--volume-snapshot-locations strings list of locations (at most one per provider) where volume snapshots should be stored