为什么
K8S 是软件,软件就会有中间状态和运行数据,K8S 的控制面数据持久化在 etcd 中,etcd 是以键值对 Key/Value 格式存储,并对外提供读写服务,为了防止数据丢失或意外故障,需要定期备份。
同时 K8S 是容器化平台,容器屏蔽了基础设施的复杂性,涵盖了计算、网络、存储、监控日志等多种接口,因此容器运行中的所有数据也需要备份,如 pv 声明的存储数据,网络配置、权限配置、镜像数据等
备份的目的是防止数据永久丢失,同时快速恢复到正常可用,是容灾恢复(DR)的重要手段,ETCD 集群和 K8S 集群一般是高可用部署,单点故障并不会影响集群稳定性,但是用户误操作、升级、集群迁移等操作,仍然需要备份和恢复工具。
是什么
k8s 集群的备份一般是指 etcd 的备份,但因为 etcd 备份是某一时刻的完整数据,无法自定义选择备份哪些内容,且数据除了 etcd 本身,其他程序不可读,因此有很多的局限。另外 pod 使用的存储如 PV 等数据也需要备份,这并不在 etcd 的范畴。
因此出现了很多开源和商业产品来提供 k8s 的备份和恢复解决方案,如:
- velero: Backup and migrate Kubernetes resources and persistent volumes
- stash: Backup your Kubernetes Stateful Applications
- portworx: Portworx solves these challenges and more with cloud native storage and data management built from the ground up for Kubernetes.
基本是为了解决 k8s 的存储迁移问题,而 k8s 在 1.12 版本 也推出了CSI Snapshot,存储的备份操作有了更多可能性,后面会详细说明。
不是什么:
- 本文不讨论多集群灾备方案,如跨地域、跨可用区或者跨云的多集群热备、冷备、调度
- 如果 pod 中使用了外部数据库、缓存等产品,备份操作应该在对应的产品操作,如数据库本身的 db 备份,尤其是云上产品。
备份与快照
备份(backup)与快照(snapshot)的作用是很相似的,但有些区别。以云磁盘为例,备份是云硬盘数据在某一时刻的副本,而快照并非是实际的磁盘数据拷贝,不是数据副本。因此快照占用的存储空间较小,且执行速度快。但是如果磁盘物理故障,通过快照回滚是无法恢复出正确的数据的,而备份则可以。
备份的概念更宽泛一点,如果我只想备份某几个文件夹,快照的概念就不太准确了,例如 etcd 备份,在 v2 中命令 etcdctl backup,v3 版本中是 etcdctl snapshot,但其实作用是一样的,即备份某一时刻的 etcd 数据。这里不是玩文字游戏,只是对比后面的 velero 备份,etcd 的快照是某一时刻的数据,没办法备份某一个 namespace 或者某一组 pod。备份的是全部,恢复时也是全部。
物理备份与逻辑备份
备份也可以分为两类,物理备份与逻辑备份
- 物理备份: 如 mysql 备份、etcd 备份,不区分数据的内在逻辑关系,把数据存储作为一个整体来备份,恢复时也是作为整体恢复,不可能只恢复一部分数据,类似快照的概念。
-
逻辑备份:按照数据的内在逻辑关系,选择性提取部分数据或全部数据,恢复时可以选择恢复一部分数据。
物理备份的优点是速度快,无论是备份还是回恢复,但缺点是元数据不可读,只能全部恢复。而逻辑备份正好相反,因此两者可以结合使用,既能快,又能有细粒度控制的能力.
在 k8s 集群中的操作就是:
- 物理备份:etcd 备份,保存某一个时刻的快照,快捷方便。
- 逻辑备份:基于 velero 或者自研功能,允许用户自己选择备份的内容、自动或定时备份,也可以恢复特定内容。同时备份的就是 yaml,用户可读可修改。
etcd 备份
以 etcd v3 版本为例:
备份:
# 执行备份
date;
CACERT="/opt/kubernetes/ssl/ca.pem"
CERT="/opt/kubernetes/ssl/server.pem"
EKY="/opt/kubernetes/ssl/server-key.pem"
ENDPOINTS="127.0.0.1:2379"
ETCDCTL_API=3 etcdctl \
--cacert="${CACERT}" --cert="${CERT}" --key="${EKY}" \
--endpoints=${ENDPOINTS} \
snapshot save /backup/etcd-snapshot-`date +%Y%m%d`.db
# 备份保留30天
find /backup/ -name *.db -mtime +30 -exec rm -f {} \;
恢复:
1.停止所有 Master 上 kube-apiserver 服务
systemctl stop kube-apiserver
2.停止集群中所有 ETCD 服务
systemctl stop etcd
3.移除所有 ETCD 存储目录下数据
mv /etcd/data /etcd/data.bak
4.从备份文件中恢复数据
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot-xx.db
5.启动 etcd
systemctl start etcd
6.启动 apiserver
systemctl start kube-apiserver
7.检查服务是否正常
逻辑备份
逻辑备份就是让用户选择自己的备份内容、备份周期和恢复方式,换句话说,把备份做成一种产品功能,存放用户的 yaml 备份。因为我们是云产品,所以提供了自定义的备份能力,用户可以在页面上选择 namespace 或资源,备份所有资源的 yaml,后端将 yaml+json 两份文件存放在对象存储,并支持定时备份、指定资源做恢复。
备份的逻辑非常简单,简化为 kubectl 操作就是:
kubectl get deploy nginx -o yaml > nginx.yaml
只是将 kubectl 操作换成了代码实现,扫描 ns 下的十几种资源类型,并转为文件上传到对象存储。但如果做成产品功能,会多出一些设计和限制在里面,如:
- 备份限制:用户有自己的配额,如一个用户最大能有100 个备份文件,允许下载
- 手动备份:用户可以勾选需要的资源,点击备份,备份是异步操作,点击后会有备份进度展示
- 自动备份:支持 cron 表达式,按指定时间进行备份
- 恢复备份:恢复时需要去除yaml 中的某些字段,然后 apply 到用户集群
备份的思路参考了 velero 的实现,只是 velero 需要在集群内安装 pod 来配合备份,而备份 yaml 只要有 kubeconfig 能连接集群即可。
velero 备份
velero 是开源方案,项目地址:https://velero.io/
velero的作用:
- 灾备能力:提供备份恢复k8s集群的能力
- 迁移能力:提供拷贝集群资源到其他集群的能力
和 etcd 备份的区别:
- etcd 的备份必须拥有 etcd 运维权限,有些用户无法操作 etcd,如多租户场景。
- etcd 更适合单集群内数据备份,不太适合集群迁移
- etcd 是当前状态备份,velero 可以做到只备份集群内的一部分资源
velero 会在你的 k8s 集群上运行一个 server pod,然后配合 velero 客户端进行操作,安装过程可以参考文档,操作是很简单的:
1.创建一个 nginx 资源
---
apiVersion: v1
kind: Namespace
metadata:
name: nginx-example
labels:
app: nginx
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
namespace: nginx-example
spec:
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: hub.baidubce.com/cce/nginx-alpine-go:latest
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: my-nginx
namespace: nginx-example
spec:
ports:
- port: 80
targetPort: 80
selector:
app: nginx
type: LoadBalancer
kubectl apply -f base.yaml
2.生成一个备份,备份名称为 nginx-backup
velero backup create nginx-backup --include-namespaces nginx-example
3.删除nginx example 资源:
kubectl delete namespaces nginx-example
4.从nginx-backup备份中恢复资源:
velero restore create --from-backup nginx-backup
velero还支持更多的备份方式,可以参考官方文档,
工作原理:
velero 默认将备份的文件上传到对象存储,对象存储和和csi 插件都云厂商支持,因此一般搭配 velero-plugin 使用,如:
- aws: https://github.com/vmware-tanzu/velero-plugin-for-aws
- 阿里云: https://github.com/AliyunContainerService/velero-plugin
- 百度云: https://cloud.baidu.com/doc/CCE/s/njyfx596a
存储的备份
只有需要持久化的、有状态的应用才需要备份,而 k8s 中的存储挂载有很多种,如:
- emptyDir
- configmap
- secret
- hostpath
- nfs
- 各种云厂商的磁盘
- 对象存储
存储资源的备份一直是 k8s 备份最麻烦的部分,因为涉及到的挂载类型太多
云厂商磁盘:
- 如果你通过 flexvolume 或者 csi 插件挂载了文件存储、对象存储或者块存储,可以在对应的云产品页面进行磁盘的备份操作
- 如果厂商自己定义了 crd 之类的操作,允许你自定义备份策略,你可以通过提交 yaml 来配置磁盘备份
- k8s 1.12 开始支持了csi snapshot ,如果厂商实现了 snapshot 功能,你可以直接在 k8s 中声明VolumeSnapshot来创建备份。
非云厂商:
- 如果你是emptyDir或者 nfs 的方式,可以在 velero 中使用 集成restic来实现备份,需要 k8s 支持mountPropagation(1.10 以上的版本),可以参考这个[文档] https://velero.io/docs/v1.4/restic/(https://velero.io/docs/v1.4/restic/)
- restic不支持hostpath 方式的挂载,但可以支持 local pv
csi snapshot
k8s支持三种类型的卷插件:in-tree、Flex和CSI。而 snapshot 功能只有使用CSI才支持
CSI(Container Storage Interface)是社区定义的一套用于容器场景的存储接口标准。k8s作为CO(容器编排系统)支持该标准。CSI方案是k8s中功能最完整,迭代最活跃的out-of-tree存储框架,也作为新的存储接入k8s的建议模式。现在大量的in-tree插件也在向CSI插件迁移。
k8s 1.12 开始推出了 csi snapshot 功能,定义了几种 CRD 资源来实现快照功能,到 k8s 1.17,该功能进入 beta 阶段。
使用方式:
存储卷快照和pvc、pv创建的过程很类似:
- PVC-—>StorageClass—->PV
- VolumeSnapshot—->VolumeSnapshotClass—–>VolumeSnapshotContent
在kubernetes中用VolumeSnapshotContent 和VolumeSnapshot这样的API资源去为用户和管理员创建卷快照
- VolumeSnapshotContent是从集群中指定的volume中获取的快照, 像PV资源一样
- VolumeSnapshot是用户想从某个指定volume获取快照的一个请求, 像集群中的PVC一样
当用户想对某个volume进行快照的时候, 可以先创建VolumeSnapshotClass对象,之后创建一个卷快照申请,即VolumeSnapshot,当有了这个申请之后,先前创建的VolumeSnapshotClass就会根据申明来进行卷快照,生成快照内容,即VolumeSnapshotContent。
这个功能是由CSI drivers提供,有些CSI drivers是支持快照功能的,当安装了支持卷快照的CSI drivers之后,CSI drivers会自动安装 VolumeSnapshotClass、VolumeSnapshot 和VolumeSnapshotContent 这些api 资源,这些 api 资源是 CRD,并不是 core api中的一部分, 作为部署过程的一部分,kubernetes为 snapshot controller 提供了一个名叫 external-snapshotter 的sidecar helper container, 它会watches VolumeSnapshot 这个对象,并触发对 CSI 端点的 CreateVolume 和DeleteVolume 操作。
创建VolumeSnapshotClass对象
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshotClass
metadata:
name: disk-snapshotclass
snapshotter: diskplugin.csi.alibabacloud.com #指定VolumeSnapshot时使用的Volume Plugin
创建VolumeSnapshot对象:
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshot
metadata:
name: disk-snapshot
spec:
snapshotClassName: disk-snapshotclass
source:
name: disk-pvc #Snapshot的数据源, 类型是个pvc
kind: PersistentVolumeClaim
从snapshot中恢复数据到新生的pv对象中
apiVersion: v1
kind: PersisttentVolumeClaim
metadata:
name: restore-pvc
spec:
dataSource:
name: disk-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
-ReadWriteOnce
resource:
requests:
storage:20Gi
storageClassName: csi-disk
velero 中对于csi snapshot的支持:
velero 在 1.4 版本也对csi snapshot做了支持,不过功能并不完善,要求 k8s 版本必须为 1.17 及以上,参考文档: https://velero.io/blog/csi-integration/
velero client config set features=EnableCSI
参考
- https://cloud.tencent.com/developer/article/1549339
- https://www.youtube.com/watch?v=CbA40krYZf0
- https://cloud.baidu.com/doc/CCE/s/njyfx596a
- https://www.kubernetes.org.cn/6266.html
- http://dockone.io/article/8697
- https://portworx.com/use-case/kubernetes-storage/
- https://velero.io/blog/csi-integration/
- https://github.com/vmware-tanzu/velero-plugin-for-aws
- https://www.youtube.com/watch?v=JyzgS-KKuoo
- https://www.objectif-libre.com/en/blog/2020/01/10/kubernetes-backup-stateful-apps/
- https://www.infoq.cn/article/sbwSX8ypxgID2-SB723K
- https://stash.run/
- https://kubernetes-csi.github.io/docs/snapshot-restore-feature.html
- https://haojianxun.github.io/2019/06/24/kubernetes%E6%8C%81%E4%B9%85%E5%8C%96%E5%AD%98%E5%82%A8%E5%8D%B7%E5%AD%98%E5%82%A8%E5%8D%B7%E5%BF%AB%E7%85%A7Snapshot/
- https://www.youtube.com/watch?v=CbA40krYZf0&t=628s
说点什么
欢迎讨论