#云原生征文# 使用Velero备份Kubernetes集群 原创
@toc
基于velero备份还原kubernetes集群
1、Kubernetes
1.1 简介
Kubernetes(简称k8s)是一个全新的基于容器技术的分布式架构领先方案。目的是实现资源管理的自动化,以及跨多个数据中心的资源利用率的最大化;是Go语言开发,是Docker的上层架构,就好像Java与J2EE的关系一样。K8s是一个开放的开发平台,不局限于任何语言。
1.2 主要功能
1、能方便地管理跨机器运行容器化的应用
2、提供应用部署、维护、扩展机制
3、集群管理、安全防护、准入机制、多应用支撑、服务注册、服务发现、智能负载均衡、故障发现、自我修复、服务滚动升级、在线扩容、资源配额管理
4、使用Docker对应用程序包装、实例化、运行
5、以集群的方式运行、管理跨机器的容器
6、解决Docker跨机器容器之间的通讯问题
1.3 应用体系生态
1.4 架构图解
1.5 Kubernetes基本对象
Container
Pod
Node
Namespace
Service
Label
Annotations
基本对象这里不做过多说明,需要的可以去官方文档查看。
http://docs.kubernetes.org.cn/
2、velero备份还原
2.1 Velero介绍
Velero是一个针对kubernetes集群资源和持久卷的一个备份和还原工具。 可以运行在公有云或者私有云中应用。
它主要有以下三个功能:
- 备份kubernetes的集群,并在丢失时恢复。
- 迁移集群的资源到另一个集群。
- 复制你生产的集群到开发和测试的集群。
Velero可以运行两种方式运行:
- 服务器:运行在你集群上
- 命令行工具:运行在本地
Velero使用对象存储去存储备份,它还集成支持后端存储系统的快照功能。
2.2 Velero 支持的后端存储
Velero 支持两种关于后端存储的 CRD,分别是 BackupStorageLocation 和 VolumeSnapshotLocation。主要用来定义 Kubernetes 集群资源的数据存放位置,也就是集群对象数据,不是 PVC 的数据。主要支持的后端存储是 S3 兼容的存储,比如:Mino 和阿里云 OSS 等。
VolumeSnapshotLocation 主要用来给 PV 做快照,需要云提供商提供插件。阿里云已经提供了插件,这个需要使用 CSI 等存储机制。你也可以使用专门的备份工具 Restic,把 PV 数据备份到阿里云 OSS 中去(安装时需要自定义选项)。
这里选用:BackupStorageLocation。
2.3 备份还原流程
备份持久化数据:调用应用数据,包括数据库数据,中间件数据(需提供获取数据接口),数据保存在云端,用年月日的方式每天创建一个文件,例如20211118-k-data,k代表k8s,v代表velero数据,其中v又涵盖数据库数据、中间件数据、redis等数据,创建文件存储使用脚本(定时任务),针对备份和针对恢复写不同的接口实现以及获得备份数据和恢复数据的列表等。
Vlero还原:request请求中获得所有的列表,然后循环读取匹配,最后返回一个plugin对象,每个节点的pod数据判断其处理的状态,成功或失败都记录,如果失败重试3次,直到成功为止。Request判断是恢复的话,获取节点信息,对节点信息rollback。
2.4 Velero部署说明
2.4.1、kubectl的安装
2.4.2、CLI的安装
2.4.3、安装和配置服务器端组件
Velero使用存储提供程序插件与各种存储系统集成,以支持备份和快照操作。安装和配置Velero服务器组件以及适当插件的步骤是特定于您所选择的存储提供商的。Velero 支持针对卷的快照和对象存储使用不同的提供商。比如,可以使用AWS S3来做对象存储,Portworx针对块卷的快照。
2.4.4、安装时自定义的参数
根据需要进行配置插件、命名空间、验证机制等参数。
2.5 实践—相关命令行模拟备份还原
启动一个配置的yaml程序
kubectl apply -f base.yaml
创建备份
velero backup create nginx-backup --include-namespaces nginx-example
创建带有pv的备份
velero backup create nginx-backup --include-namespaces nginx-example --snapshot-volumes
备份时排除指定的条目
kubectl label -n <ITEM_NAMESPACE> <RESOURCE>/<NAME> velero.io/exclude-from-backup=true
模拟删除
kubectl delete namespaces nginx-example
还原
velero restore create --from-backup nginx-backup
velero restore create --from-backup nginx-backup --restore-volumes=true
构建日常备份
velero schedule create <SCHEDULE NAME> --schedule “0 7 * * *”
查看备份信息
velero backup describe YOUR_BACKUP_NAME
还原成功后查看还原信息
velero restore describe YOUR_RESTORE_NAME
kubectl -n velero get podvolumerestores -l velero.io/restore-name=YOUR_RESTORE_NAME -o yaml
2.6 实践—使用go实现velero备份和应用重启功能
2.6.1、集群、集群deploy、集群ingress、pv、pvc等资源封装
2.6.2、备份接口后端核心代码实现
func (h *Handler) AppsBackup(c *gin.Context) {
id := exgin.GinsParamStr(c, "id")
appres, err := h.appsRepository.GetAppMeta("id = ?", id)
if err != nil {
zlog.Error("应用不存在: %v", err)
errors.Dangerous("应用不存在")
return
}
cluster, err := h.clusterRepository.GetByID(appres.Region)
if err != nil || cluster == nil {
errors.Bomb("没有可用的集群")
return
}
clusterclient, err := client.Manager(cluster.ID)
if err != nil {
zlog.Error("%v 获取kube client 失败: %v", cluster.ID, err)
errors.Bomb("%v 获取kube client 失败: %v", cluster.ID, err)
return
}
backupVer := ztime.GetTodayMin()
backupName := fmt.Sprintf("backup-%v-%v", appres.Name, backupVer)
const DefaultBackupTTL time.Duration = 30 * 24 * time.Hour
vc := &velero.BackupOptions{
Name: backupName,
TTL: DefaultBackupTTL,
IncludeNamespaces: flag.NewStringArray("*"),
Labels: flag.NewMap(),
Selector: flag.LabelSelector{
LabelSelector: &metav1.LabelSelector{MatchLabels: map[string]string{
"app.xx.work/managed-by": "cce",
"k8s.xx.work/name": appres.Name,
"k8s.xx.work/appid": appres.ID,
}},
},
SnapshotVolumes: flag.NewOptionalBool(ptr.BoolPtr(true)),
IncludeClusterResources: flag.NewOptionalBool(ptr.BoolPtr(true)),
}
config := clusterclient.Config
veleroClient, err := veleroclientset.NewForConfig(config)
if err != nil {
zlog.Error("创建备份 velero client err: %v", err)
errors.Dangerous("创建备份失败")
return
}
vc.Client = veleroClient
if err := vc.Create(); err != nil {
zlog.Error("创建备份失败: %v", err)
errors.Dangerous("创建备份失败")
return
}
backupID := zos.GenUUID()
h.appsRepository.CreateBackUp(&models.AppBackUP{
ID: backupID,
AppID: appres.ID,
Status: false,
Version: backupVer,
Namespace: appres.Namespace,
Name: backupName,
})
exgin.GinsData(c, map[string]interface{}{
"region": appres.Region,
"appid": appres.ID,
"backupid": backupID,
}, nil)
}
2.6.2、重启应用功能实现
func Restart(c *gin.Context) {
name := exgin.GinsQueryStr(c, "name", "")
ns := exgin.GinsQueryStr(c, "ns", "default")
k, err := kube.New()
if err != nil {
errors.Dangerous(err)
return
}
if len(name) == 0 {
errors.Dangerous("name is null")
return
}
list, err := k.AppsV1().Deployments(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
errors.Dangerous(err)
return
}
old := list.Spec.Template.ObjectMeta.Annotations
new := map[string]string{
"go-restart": ztime.NowUnixString(),
}
list.Spec.Template.ObjectMeta.Annotations = exmap.MergeLabels(old, new)
_, err = k.AppsV1().Deployments(ns).Update(context.TODO(), list, metav1.UpdateOptions{})
if err != nil {
errors.Dangerous(err)
return
}
exgin.GinsData(c, nil, nil)
}
2.6.3、还原
go操作velero的还原这里就不过多阐述了,参考velero命令行还原代码,转换成对应的go语言程序代码就可以了。如果对yaml文件很熟悉,也可以编写yaml来实现这些操作(这里安利一个yaml转换为go代码的工具 https://kyaml2go.prasadg.dev/ )。
【本文正在参加云原生有奖征文活动】,活动链接:https://ost.51cto.com/posts/12598