Kasten k10 实战系列 07 - Kanister 应用感知框架的使用
1. 前言
由于 Kubernetes 本身的特性,基于 Kubernetes 开发和运行的应用对于企业的商业目标非常重要。随着 Kubernetes 中有状态应用程序的部署在云原生基础架构中的越发成熟,对有状态的云原生应用如何进行备份就成为了一个让人担心的问题。实际上在生产系统运行有状态应用并不是一件容易的事情,这需要我们仔细的计划并部署,管理者需要清晰地知道数据备份到哪个位置,备份的时间计划以及备份时间窗口,以确保与应用关联的数据也被正确备份了,从而达成应用的一致性,Kanister 就是解决这此问题的有利武器。
文章目录
Kasten k10 实战系列 07 - Kanister 应用感知框架的使用
- 前言
- Kasten Kanister 介绍
- Kanister 的核心概念
- 3.1 Kanister Operator 与 CRDs
- 3.2 Blueprint 的实现方式-- Admission Webhook
- 启用 Kanister 之前的准备工作
- 4.1 安装 kanctl 工具包
- 4.2 存储桶的准备
- 4.3 安装 MySQL
- 利用 Kanister 达成应用感知的备份
- 5.1 在 K10 中启用应用感知的备份
- 5.2 利用开源的 Kanister 框架进行应用感知的备份
- 总结
- 参考链接
Kasten 实战系列导航
- Kasten K10 实战系列 01 - 在腾讯云上部署 K10 概览
- Kasten K10 实战系列 02 - Kasten K10 搭建云镜像库
- Kasten k10 实战系列 03 - Kasten K10 存储集成
- Kasten k10 实战系列 04 - 利用 Kubestr 进行云原生存储能力评测
- Kasten k10 实战系列 05 - Kasten K10 安装及最佳实践
- Kasten k10 实战系列 06 - Kasten K10 备份与恢复
- Kasten k10 实战系列 07 - Kasten K10 Kanister 应用感知框架的使用
- Kasten k10 实战系列 08 - Kasten K10 应用容灾与迁移
- Kasten k10 实战系列 09 - Kasten K10 整体环境灾备
- Kasten k10 实战系列 10 - Kasten K10 日常运维总结
2. Kasten Kanister 介绍
Kanister 是 Kasten K10 数据管理平台使用的可扩展开源框架,可用于 Kubernetes 上的应用程序级数据管理。利用 Kanister 的特性,数据库领域专家在可以轻松地共享和扩展的 Blueprint 中捕获特定于应用程序的数据管理任务。 在本文中我们将介绍有关 Kanister 备份与恢复应用程序的测试及其扩展资源与信息,以供大家参考。
目前,通过 Kanister 我们可以对如下数据库进行应用感知的备份,可以说非常全面了:
- RDS PostgreSQL Backup
- Logical Elasticsearch Backup
- Logical MongoDB Backup
- Logical MySQL Backup
- Logical PostgreSQL Backup
- Logical MySQL Backup for OpenShift
- Logical MongoDB Backup on OpenShift clusters
- Logical PostgreSQL Backup on OpenShift Clusters
3. Kanister 的核心概念
3.1 Kanister Operator 与 CRDs
Kanister Operator 部署完成后,系统中会看到三个 CRD,就是 Kanister 运行的 3 个核心组件。下面给出了每个 CR 的简要说明。
- actionset 动作集 , 指示要由备份或还原执行的任务(操作)的资源,理解成 backup policy 或备份、还原等数据操作任务就好了。
- buleprint 蓝图 , 定义备份和恢复等过程的模板资源, 其中定义的主要的数据操作,备份、还原、删除,还有就是使用何种应用原生的方法获取数据集。
- profile 配置文件, 定义作为备份目的地的对象存储的位置信息的资源, 之后会定义的 Profiles 中 包括 endpoint, bucket, access_key, secret_key 等。
Kanister 部署后的三个 CRD:
$ kubectl get crd |grep kanister
actionsets.cr.kanister.io 2021-06-25T08:14:59Z
blueprints.cr.kanister.io 2021-06-25T08:14:59Z
profiles.cr.kanister.io 2021-06-25T08:14:59Z
Kanister 的工作流程如下所示。
3.2 Blueprint 的实现方式-- Admission Webhook
就像我们在之前的章节中表述的那样,K10 在进行数据备份操作时,会通过存储的方式(原生或是CSI)进行卷快照操作,但也有需要自定义的情况。例如,保护应用程序与数据库需要从逻辑层进行备份,而这时需要使用特定于该数据库的工具进行数据操作,例如 mysql 数据库上常用的 mysqldump。
如果要获得应用程序一致的备份, 则需要在启动卷快照之前停止数据库服务,最方便的做法就是利用 Admission Webhook 机制,将 Sidecar Proxy 自动注入用户 Pod , 并调用应用程序蓝图中定义的函数 ,如 mysqldump,静默数据库,然后调用卷快照,保证数据的一致性。这样的操作的好处是,用户可以快速得到一份应用一致的数据副本用于备份,同时不影响生产系统的性能。
下图中,标成蓝色的部分说明了,blueprint 调用 mysql dump 网我们定义的对象存储中写入数据的过程。
详细的情况可以查看 Github Kanister
https://github.com/kanisterio/kanister
Admission Webhook 的理论(option)
在 K8S中 Admission Webhook 是一种用于接收准入请求并对其进行处理的 HTTP 回调机制。Admission Webhook 有两种类型:validating 和 mutating 。
Validating webhook 可用于执行超出 OpenAPI 架构验证功能的验证,例如确保字段在常见后是不可变的,或者对向 API Server 发出请求的用户进行更高级别的权限检查。通过 Validating admission webhook,我们可以拒绝自定义准入策略的请求。
Mutating webhook 常用于默认设置,在创建时往在资源中添加未设置字段的默认值,工作原理如下图。
4. 启用 Kanister 之前的准备工作
- Kanctl CLI 安装
- 对象存储 - COS 存储桶
- 应用程序 - mysql with statefulset
- Kubernetes 要求:
- Kubernetes 1.6+ with Beta APIs enabled
- 底层基础设施中的PV, PVC 存储提供支持
- Kanister controller 0.61.0 版本 安装在 K8S 集群 Kanister 命名空间中
4.1 安装 kanctl 工具包
Kanctl 是操作 kanister 进行备份恢复的工具集,如果你没有 k10 ,就靠它了。
安装 kanctl 工具包
https://docs.kanister.io/tooling.html#install-the-tools$ curl https://raw.githubusercontent.com/kanisterio/kanister/master/scripts/get.sh | bash
## 4.2 存储桶的准备
存储桶是我们备份的目标,请建立存储桶,并将相关参数记录, 一会儿建立 profile 时要用。
![20210701191637](https://mars-blog-1257130361.cos.ap-chengdu.myqcloud.com/20210701191637.png)
## 4.3 安装 MySQL
用 bitnami 部署 MySQL 应用, 应用名为 mysql-release。
加入 bitnami docker 镜像库
$ helm repo add bitnami https://charts.bitnami.com/bitnami
更新 helm repo 设置
$ helm repo update
安装 MySQL database
$ kubectl create namespace mysql-test
$ helm install mysql-release bitnami/mysql --namespace mysql-test \
--set auth.rootPassword='Start123' \
--set primary.persistence.size=10Gi # <- 默认 8Gi 无法部署到 TKE CBS,改成10Gi
> [bitnami mysql 参数](https://artifacthub.io/packages/helm/bitnami/mysql)
> https://artifacthub.io/packages/helm/bitnami/mysql
用以下命令验证 Password 是否指定正确,如果在安装中没有指定 password, 可通过以下命令获取 root password
可通过以下命令获取 root password
$ kubectl get secret [YOUR_RELEASE_NAME] --namespace [YOUR_NAMESPACE] -o jsonpath="{.data.mysql-root-password}" | base64 --decode
部署完成,了解 MySql 部署的详细情况
$ kubectl get statefulset,pod,pvc,svc -n mysql-test
NAME READY AGE
statefulset.apps/mysql-release 1/1 7h9m
NAME READY STATUS RESTARTS AGE
pod/mysql-release-0 1/1 Running 0 7h9m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/data-mysql-release-0 Bound pvc-20019012-4622-4925-b445-0566088c7254 20Gi RWO cbs-csi 7h9m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/mysql-release ClusterIP 172.16.255.192 <none> 3306/TCP 7h9m
# 5. 利用 Kanister 达成应用感知的备份
## 5.1 在 K10 中启用应用感知的备份
很显然 Kansten K10 是个重视体验的商用软件,它已经将 Kanister 功能集成, 默认地 Kanister controller 已经部署到 Kasten K10 namespace 当中,所有的 ActionSet 被 K10 接管,只需要 apply 相应的 Blueprint 即可。
### 5.1.1 建立 secret 与 profile
- **建立 secret**
$ kubectl create secret generic k10-cos-secret \
--namespace kasten-io \
--type secrets.kanister.io/aws \
--from-literal=aws_access_key_id=AKID4B6mCN79Ava3IJef4GCzZuzoRovmj2OW \
--from-literal=aws_secret_access_key=2uYx74pLbhgT1KUR9bopb8PXT9alkUzF
secret/k10-cos-secret created
$ kubectl get secret -n kasten-io
NAME TYPE DATA AGE
default-token-72fwn kubernetes.io/service-account-token 3 6d15h
k10-cluster-passphrase Opaque 1 6d15h
k10-cos-secret secrets.kanister.io/aws 2 53m
- **建立 profile**
```yaml
apiVersion: config.kio.kasten.io/v1alpha1
kind: Profile
metadata:
name: kanister-profile
namespace: kasten-io
spec:
type: Kanister
kanister:
credential:
secretType: AwsAccessKey
secret:
apiVersion: v1
kind: Secret
name: k10-cos-secret
namespace: kasten-io
location:
type: ObjectStore
objectStore:
name: kanister-1257130361
objectStoreType: S3
endpoint: https://cos.ap-chengdu.myqcloud.com
region: ap-chengdu
# 建立 profile
$ kubectl apply -f kanister-profile.yaml
profile.config.kio.kasten.io/kanister-profile created
# 确保初始化成功
$ kubectl get profiles.config.kio.kasten.io --namespace kasten-io
NAME STATUS
cos1 Success
kanister-profile Success
5.1.2 建立 MySQL 应用
$ kubectl create namespace mysql
namespace/mysql created
$ helm repo add
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo list
NAME URL
kasten https://charts.kasten.io/
bitnami https://charts.bitnami.com/bitnami
kanister http://charts.kanister.io
$ helm install mysql-release bitnami/mysql --namespace mysql \
--set auth.rootPassword='Start123' \
--set primary.persistence.size=10Gi # <- 默认 8Gi 无法部署到 TKE CBS,改成10Gi
$ kubectl get pvc,po,svc -n mysql
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/data-mysql-release-0 Bound pvc-edf41c52-79a0-4b4d-b3fb-47e881a84a8f 10Gi RWO cbs-csi 4m19s
NAME READY STATUS RESTARTS AGE
pod/mysql-release-0 1/1 Running 0 4m19s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/mysql-release ClusterIP 172.16.255.33 <none> 3306/TCP 4m19s
service/mysql-release-headless ClusterIP None <none> 3306/TCP 4m19s
$ kubectl get statefulset -n mysql
NAME READY AGE
mysql-release 1/1 3m6s
下面的命令将在 K10 命名空间中安装 MySQL Blueprint,并在 MySQL 部署中添加注释,以便让 K10 在对这个MySQL实例执行操作时使用Blueprint。
$ kubectl --namespace kasten-io apply -f \
https://raw.githubusercontent.com/kanisterio/kanister/0.58.0/examples/stable/mysql/blueprint-v2/mysql-blueprint.yaml
blueprint.cr.kanister.io/mysql-blueprint created
$ kubectl get blueprint --namespace kasten-io
NAME AGE
k10-namespace-generic-volume-2.0.6 122m
mysql-blueprint 2s
$ kubectl --namespace mysql annotate statefulset/mysql-release \
kanister.kasten.io/blueprint=mysql-blueprint
statefulset.apps/mysql-release annotated
$ kubectl get statefulset mysql-release -n mysql -o yaml
apiVersion: v1
items:
- apiVersion: apps/v1
kind: StatefulSet
metadata:
annotations:
kanister.kasten.io/blueprint: mysql-blueprint
...
5.1.3 在 K10中 建立 MySQL 应用的备份
设置 sidecar inject 参数
$ helm get values k10 --output yaml --namespace=kasten-io > k10_val.yaml
$ helm upgrade k10 kasten/k10 --namespace=kasten-io -f k10_val.yaml \ ✔ 1112
--set injectKanisterSidecar.enabled=true
在 K10中 建立 MySQL 应用的备份
5.2 利用开源的 Kanister 框架进行应用感知的备份
Kanister 开源框架让一切组件动作都变得更加清晰,当然这也是需要一定的技术基础的。Kanister 开源框架以免费的方式让更多的客户与合作伙伴受益,开源的目的是让更多数据类型应用的开发者使用蓝图,使其数据操作变得更顺畅。
5.2.1 Kanister Operator 安装与设置
首先,创建并移动到 Kanister 命名空间
$ kubectl create ns kanister
$ kubens kanister
然后使用 Helm 设置 Kanister Operator
$ helm repo add kanister http://charts.kanister.io
$ helm install myrelease --namespace kanister kanister/kanister-operator --set image.tag=0.61.0
确认 kanister Operator 已启动
$ kubectl get deploy,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/myrelease-kanister-operator 1/1 1 1 64m
NAME READY STATUS RESTARTS AGE
pod/myrelease-kanister-operator-6bbcd59494-cq5h7 1/1 Running 0
这样就完成了 Kanister Operator 设置, Kanister 还部署了以下三个 CRD:
$ kubectl get crd |grep kanister
actionsets.cr.kanister.io 2021-06-25T08:14:59Z
blueprints.cr.kanister.io 2021-06-25T08:14:59Z
profiles.cr.kanister.io 2021-06-25T08:14:59Z
下面给出了每个 CR 的简要说明。
- actionset , 动作集,指示要由备份或还原执行的任务(操作)的资源。
- buleprint , 蓝图, 定义备份和恢复等过程的模板资源
- profile , 存储配置, 定义作为备份目的地的对象存储的位置信息的资源
Kanister 使用以上三个 CR 来执行备份/恢复。
5.2.2 创建用于备份的对象存储 Profile
$ kanctl create profile s3compliant --access-key A****@#@#@#@#@#***W \
--secret-key 2****@#@#@#@#@#***F \
--bucket kanister-1257130361 --region ap-chengdu \
--endpoint https://cos.ap-chengdu.myqcloud.com \
--namespace mysql-test
secret 's3-secret-yixwyd' created
profile 's3-profile-fbvpv' created
# 查看 profiles 要牢记这个 profile 的名字
kubectl get profiles.cr.kanister.io -n mysql-test
NAME AGE
s3-profile-6xtr6 16h
s3-profile-fbvpv 5s
5.2.3 建立 Blueprint 蓝图
# 下载应用蓝图
$ wget https://raw.githubusercontent.com/kanisterio/kanister/0.58.0/examples/stable/mysql/blueprint-v2/mysql-blueprint.yaml
# 建立 Blueprint 蓝图
$ kubectl create -f mysql-blueprint.yaml -n kanister
# 查看 blueprint
$ kubectl get blueprint -n kanister
NAME AGE
mysql-blueprint 18h
5.2.4 建立 MySQL 数据集
# 登录到 MySQL Docker
$ kubectl exec -ti $(kubectl get pods -n mysql-test --selector=app.kubernetes.io/instance=mysql-release -o=jsonpath='{.items[0].metadata.name}') -n mysql-test -- bash
# 登录 MySQL
$ mysql --user=root --password=Start123
# 建立 "test" 数据库, 并使用这个库
mysql> CREATE DATABASE test;
Query OK, 1 row affected (0.00 sec)
mysql> USE test;
Database changed
# 创建 "pets" 表,
mysql> CREATE TABLE pets (name VARCHAR(20), owner VARCHAR(20), species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);
Query OK, 0 rows affected (0.02 sec)
# 插入一行数据
mysql> INSERT INTO pets VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
Query OK, 1 row affected (0.01 sec)
# 查看 "pets" 表中的数据
mysql> SELECT * FROM pets;
+----------+-------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+----------+-------+---------+------+------------+-------+
| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
+----------+-------+---------+------+------------+-------+
1 row in set (0.00 sec)
5.2.5 创建 ActionSets 保护 MySQL 应用
现在我们可以使用这个应用程序的 ActionSet 对 MySQL 数据进行备份,在与 controller 相同的 namespace 中创建一个ActionSet
# 找到 刚刚建立的 profile
kubectl get profiles.cr.kanister.io -n mysql-test
NAME AGE
s3-profile-fbvpv 2m
kanctl create actionset --action backup --namespace kanister --blueprint mysql-blueprint --statefulset mysql-test/mysql-release --profile mysql-test/s3-profile-fbvpv --secrets mysql=mysql-test/mysql-release
actionset backup-mpvqf created
# 查看 actionset 完成情况
$ kubectl --namespace kanister get actionsets.cr.kanister.io
NAME AGE
backup-mpvqf 1m
$ kubectl describe actionset -n kanister backup
~~~
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started Action 19m Kanister Controller Executing action backup
Normal Started Phase 19m Kanister Controller Executing phase dumpToObjectStore
Normal Ended Phase 19m Kanister Controller Completed phase dumpToObjectStore
Normal Update Complete 19m Kanister Controller Updated ActionSet 'backup-mpvqf' Status->complete</code></pre>
<p>查看 S3 存储桶上的备份信息</p>
<pre><code>$ kubectl describe actionset backup-mpvqf -n kanister |grep s3path
s3path: /mysql-backups/mysql-test/mysql-release/2021-07-01T07-24-37/dump.sql.gz</code></pre>
<h3>5.2.6 模拟灾难 删除 MySQL 数据</h3>
<pre><code># 登录 Docker, MySQL 库
$ kubectl exec -ti $(kubectl get pods -n mysql-test --selector=app.kubernetes.io/instance=mysql-release -o=jsonpath='{.items[0].metadata.name}') -n mysql-test -- bash
$ mysql --user=root --password=Start123
# Drop the test database
$ mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
mysql> DROP DATABASE test;
Query OK, 1 row affected (0.03 sec)
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)</code></pre>
<h3>5.2.7 还原 MySQL 数据</h3>
<p>要恢复丢失的数据, 我匀需要使用之前创建的备份集。利用 kanctl 命令工具,帮助创建用于Restore 的 actionset</p>
<pre><code>$ kanctl --namespace kanister create actionset --action restore --from "backup-mpvqf"
restore-backup-cfnms-lcw5t created
$ kubectl describe actionset -n kanister restore
~~~
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started Action 6s Kanister Controller Executing action restore
Normal Started Phase 6s Kanister Controller Executing phase restoreFromBlobStore
Normal Ended Phase 2s Kanister Controller Completed phase restoreFromBlobStore
Normal Update Complete 2s Kanister Controller Updated ActionSet 'restore-backup-cfnms-lcw5t' Status->complete
一旦 ActionSet 状态为 “complete”,您可以看到数据已经成功恢复到 MySQL
5.2.8 查看 mysql 数据
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
mysql> USE test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| pets |
+----------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM pets;
+----------+-------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+----------+-------+---------+------+------------+-------+
| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
+----------+-------+---------+------+------------+-------+
1 row in set (0.00 sec)
5.2.9 ActionSet 的维护与续操作
可以使用以下命令清理备份操作创建的Artifacts:
$ kanctl --namespace kanister create actionset --action delete --from backup-mpvqf --namespacetargets kanister
actionset delete-backup-mpvqf-rm47s created
# 查看 ActionSet 情况
$ kubectl --namespace kanister describe actionset delete-backup-glptq-cq6bw
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started Action 46s Kanister Controller Executing action delete
Normal Started Phase 46s Kanister Controller Executing phase deleteFromBlobStore
Normal Ended Phase 44s Kanister Controller Completed phase deleteFromBlobStore
Normal Update Complete 44s Kanister Controller Updated ActionSet 'delete-backup-mpvqf-rm47s' Status->complete
删除 CRs
# 删除 Blueprint 和 CR Profile
$ kubectl delete blueprints.cr.kanister.io mysql-blueprint -n kanister
$ kubectl get profiles.cr.kanister.io -n mysql-test
NAME AGE
s3-profile-6xtr6 16h
s3-profile-fbvpv 16h
s3-profile-jcm89 14h
# 这是只是删除定义,在 S3 桶上的数据还在
$ kubectl delete profiles.cr.kanister.io s3-profile-jcm89 -n mysql-test ✔ 942 05:47:22
profile.cr.kanister.io "s3-profile-jcm89" deleted
5.2.10 Troubleshooting
如果您在使用上述命令时遇到任何问题,您可以使用以下命令查看控制器的日志, 比如我们查看一下以上删除ActionSet的日志
$ kubectl --namespace kanister logs -l app=kanister-operator |grep delete-backup-mpvqf-rm47s
~~~
time="2021-07-01T13:09:29.432733894Z" level=info msg="Executing action delete" ActionSet=delete-backup-mpvqf-rm47s File=pkg/controller/controller.go Function="github.com/kanisterio/kanister/pkg/controller.(*Controller).runAction" Line=379 cluster_name=aee8ee9a-7e11-4d6d-a338-8b959d3acf23 hostname=myrelease-kanister-operator-6bbcd59494-cq5h7
~~~
# 我们也可以检查活动的事件
$ kubectl describe actionset delete-backup-mpvqf-rm47s -n kanister
7. 总结
这一次,我们验证了Kanister对Kubernetes Native备份/恢复的操作。 Kanister 是一种工具,它通过为每个应用程序准备一个名为 Blueprint 的模板,以某种方式为每个应用程序备份/恢复。如果您的应用程序中已有蓝图,则可以轻松使用它。然而,仅仅因为蓝图可用而过度自信是危险的。我们建议您在使用 Blueprint 之前始终检查它的内容,以了解正在执行的处理类型。
参考链接
https://github.com/kanisterio/kanister
Backup and Restore of K8s using K10 and Kanister(Mutating Web Hooks) with Minio
https://itnext.io/backup-and-restore-of-k8s-using-k10-and-kanister-mutating-web-hooks-with-minio-a1511a79638e
Kubernetes NativeなバックアップツールKanisterの検証
https://qiita.com/ysakashita/items/79e0d45257b59772fd77#%E6%84%9F%E6%83%B3
Writing a very basic kubernetes mutating admission webhook
https://medium.com/ovni/writing-a-very-basic-kubernetes-mutating-admission-webhook-398dbbcb63ec
https://kanister.io
Workflow orchestration:- http://github.com/kanisterio