介绍一个不太小的工具——Stash
AppCode Stash
是一个构建在 Restic
基础之上的工具,用于备份 Kubernetes 上运行的有状态应用,它使用一个有趣的 Sidecar,能够方便的通过共享卷的方式来对 RWO 模式的存储卷进行备份。提供了批量备份、备份模板、可扩展的应用(主要是数据库)备份等功能。备份目标包括 Kubernetes 卷、S3 等常见设施。主要功能包括:
- 备份和恢复工作负载数据:包括 Deploy、DaemonSet、StatefulSet 等等。
- 备份和恢复独立存储卷。
- 备份和恢复数据库:PostgreSQL、MySQL、MongoDB、ElasticSearch。
- 卷快照:支持 CSI 卷快照功能的集群。
- 计划备份。
- 自动备份:使用注解和模板进行备份。
- 多种备份存储目标:支持 S3、Azure、GCP 以及存储卷等多种设施。
- 可监控:支持 Prometheus 监控。
- 提供 kubectl 插件。
- 可扩展开发。
- 支持 hook 和 Webhook。
安装
使用 Helm 3
安装:
$ helm repo add appscode https://charts.appscode.com/stable/ "appscode" has been added to your repositories $ helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "appscode" chart repository ... Update Complete. ⎈ Happy Helming!⎈ $ helm search repo appscode/stash --version v0.9.0-rc.4 NAME CHART VERSION APP VERSION DESCRIPTION appscode/stash v0.9.0-rc.4 v0.9.0-rc.4 Stash by AppsCode - Backup your Kubernetes Volumes $ helm install stash-operator appscode/stash \ --version v0.9.0-rc.4 \ --namespace kube-system
完成之后,可以使用如下命令进行校验:
$ kubectl get pods --all-namespaces -l app=stash --watch NAMESPACE NAME READY STATUS RESTARTS AGE kube-system stash-operator-859d6bdb56-m9br5 2/2 Running 2 5s $ kubectl get crd -l app=stash NAME AGE recoveries.stash.appscode.com 5s repositories.stash.appscode.com 5s restics.stash.appscode.com 5s
安装完毕之后,就可以尝试第一次备份操作了。
创建备份后端
这里简单使用一个 PVC 来做为备份存储的后端。
Restic 的备份过程需要指定一个密码,这里使用一个 Secret 来保存密码:
$ echo -n 'changeit' > RESTIC_PASSWORD $ kubectl create secret generic backup-password --from-file=./RESTIC_PASSWORD secret/local-secret created
接下来创建一个 PVC,作为备份文件的存储目标:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: backend-pvc spec: resources: requests: storage: 8Gi volumeMode: Filesystem accessModes: - ReadWriteOnce
在 Stash 中新建一个 Repository,用刚才的 PVC 作为存储:
apiVersion: stash.appscode.com/v1alpha1 kind: Repository metadata: name: backend-repository spec: backend: local: mountPath: /storage/data persistentVolumeClaim: claimName: backend-pvc storageSecretName: backup-password
此处的 local
段,指明了在本地加载一个卷作为备份文件的存储目标。 官方文档
中介绍了各种存储后端的用法。
storageSecretName
除了刚才提到的备份密码之外,还用于存储后端的认证凭据,例如使用 S3 后端就需要这样的 Secret:
$ echo -n 'changeit' > RESTIC_PASSWORD $ echo -n '' > AZURE_ACCOUNT_NAME $ echo -n '' > AZURE_ACCOUNT_KEY $ kubectl create secret generic -n demo azure-secret \ --from-file=./RESTIC_PASSWORD \ --from-file=./AZURE_ACCOUNT_NAME \ --from-file=./AZURE_ACCOUNT_KEY secret/azure-secret created
创建工作负载
接下来随便运行一个应用,挂载 PVC 来模拟业务应用来进行备份。
apiVersion: apps/v1 kind: Deployment metadata: name: sleep spec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep version: v1 spec: containers: - name: sleep image: dustise/sleep imagePullPolicy: IfNotPresent resources: limits: cpu: 100m memory: 100M requests: cpu: 100m memory: 100M volumeMounts: - name: storage mountPath: /data volumes: - name: storage persistentVolumeClaim: claimName: workload-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: workload-pvc spec: resources: requests: storage: 1Gi volumeMode: Filesystem accessModes: - ReadWriteOnce
Pod 正常运行后,生成一个文件:
$ kubectl get pods NAME READY STATUS RESTARTS AGE sleep-76b447c854-7xmgf 1/1 Running 0 9m17s $ kubectl exec -it sleep-76b447c854-7xmgf -c sleep -- fallocate -l 5M /data/file-5m.txt $ kubectl exec -it sleep-76b447c854-7xmgf -c sleep ls /data file-5m.txt lost+found
备份
BackupConfiguration
是一个 CRD,用于连接工作负载和备份存储目标。
apiVersion: stash.appscode.com/v1beta1 kind: BackupConfiguration metadata: name: backupconfig-sleep spec: repository: name: backend-repository # 每五分钟一次备份 schedule: "*/5 * * * *" target: ref: apiVersion: apps/v1 kind: Deployment name: sleep # 加载工作负载中的卷 volumeMounts: - name: storage mountPath: /data paths: - /data retentionPolicy: name: 'keep-last-5' keepLast: 5 prune: true
创建之后,会发现业务 Pod 被注入了 Sidecar, 正在重启
。
$ kubectl get pods NAME READY STATUS RESTARTS AGE sleep-569b786766-mwmrb 0/2 ContainerCreating 0 3s sleep-76b447c854-7bvtz 1/1 Running 0 10m
并且系统中出现了新的 CronJob 和 BackupSession 对象:
$ kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE stash-backup-backupconfig-sleep */5 * * * * False 0 4m31s 36m $ kubectl get backupsession NAME INVOKER-TYPE INVOKER-NAME PHASE AGE backupconfig-sleep-1580535011 BackupConfiguration backupconfig-sleep Succeeded 39s
上面看到,这个 BackupSession 已经成功了一次,就可以看看 Repository 有没有什么变化了:
$ kubectl get repository NAME INTEGRITY SIZE SNAPSHOT-COUNT LAST-SUCCESSFUL-BACKUP AGE backend-repository true 5 4m58s 61m
Describe 一下这个对象,会看到其中包含的快照数量,以及文件尺寸。
恢复
备份之后,我们新建一个 Deployment,作为恢复的目标:
apiVersion: apps/v1 kind: Deployment metadata: name: sleep-restore spec: replicas: 1 selector: matchLabels: app: sleep-restore template: metadata: labels: app: sleep-restore version: v1 spec: containers: - name: sleep-restore image: dustise/sleep imagePullPolicy: IfNotPresent resources: limits: cpu: 100m memory: 100M requests: cpu: 100m memory: 100M volumeMounts: - name: storage mountPath: /data volumes: - name: storage persistentVolumeClaim: claimName: restore-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: restore-pvc spec: resources: requests: storage: 1Gi volumeMode: Filesystem accessModes: - ReadWriteOnce
然后创建一个 RestoreSession 对象:
apiVersion: stash.appscode.com/v1beta1 kind: RestoreSession metadata: name: deployment-restore spec: repository: name: backend-repository rules: - paths: - /data target: ref: apiVersion: apps/v1 kind: Deployment name: sleep-restore volumeMounts: - name: storage mountPath: /data
使用 kubectl 提交对象,启动还原过程。
通过 kubectl get po
的观察,可以看到新建的 Pod 也重启了,这次加入的不是 Sidecar,而是一个 init-container。容器重建之后,可以进入 Pod 查看,例如:
$ kubectl exec -it sleep-restore-76ff947f9b-s52px ls /data file-5m.txt lost+found
其它
除了 Deployment 之外,Stash 还支持 Statefulset、Daemonset 的备份。另外能通过 AppBind 和 Task 等对象完成针对特定数据库的备份和恢复;通过 BackupBatch 来实现一个应用多种数据的备份;最后更可以使用 BackupPrint 对象根据 Annotation 进行自动备份。
缺点也是有的:
- 目前只是 RC 版本。
- 后面提到的几种功能复杂性都比本文演示的 Deployment 备份要复杂得多。
- 文档非常好,但是不够完善,并且略有瑕疵。
- 注入过程会引发业务中断。
用在生产环境还是颇为冒险的,好在备份恢复从来就不是个容易的事情,这东西至少有很好的参考价值。