作者:李全江(jokey),腾讯云工程师,热衷于云原生畛域。目前次要负责腾讯云 TKE 的售中、售后的技术支持,依据客户需要输入正当技术计划与最佳实际。
概述
Velero 是一个十分弱小的开源工具,能够平安地备份和还原,执行劫难复原以及迁徙 Kubernetes 群集资源和长久卷,能够在 TKE 平台上应用 Velero 备份、还原和迁徙集群资源,对于如何应用请参阅 应用对象存储 COS 作为 Velero 存储实现集群资源备份和还原 和 在 TKE 中应用 Velero 迁徙复制集群资源,本文将介绍如何应用 Velero 将自建或其余云平台 Kubernetes 集群无缝迁徙到 TKE 平台。
迁徙原理
架构原理与应用 Velero 迁徙复制集群资源 过程的原理相似,迁徙集群和被迁徙集群都装置 Velero 实例,且指定同一个腾讯云 COS 后端存储,被迁徙集群按需执行备份,指标集群按需还原集群资源实现资源迁徙。不同的是,自建或其余云平台的集群资源迁徙到 TKE 时,须要思考和解决因跨平台导致集群环境差别问题,侥幸的是,Velero 提供了很多实用的备份和还原策略帮忙咱们解决这些问题,前面的迁徙示例会介绍如何更好的利用和应用它们。
环境筹备
- 已有自建或其余云平台 Kubernetes 集群(以下称作集群 A),且集群版本为 1.10 以上。
- 已创立迁徙指标的 TKE 集群(以下称作集群 B),创立 TKE 集群请参阅 创立集群。
- 集群 A 和 集群 B 都须要装置 Velero 实例(1.5 版本以上),并且共用同一个腾讯云 COS 存储桶作为 Velero 后端存储,装置步骤请参阅 配置存储和装置 Velero。
- 确保镜像资源在迁徙后能够失常拉取。
- 确保两个集群的 K8S 版本的 API 兼容,最好是雷同版本。
迁徙领导
在迁徙工作进行前,首先应该理清迁徙思路,制订具体的迁徙打算,迁徙过程大略须要思考上面几点:
- 筛选剖析须要迁徙哪些集群资源,不须要迁徙哪些集群资源
依据理论状况筛选分类出须要迁徙资源清单和不须要迁徙的资源清单。
- 依据业务场景思考是否须要自定义一些 Hook 操作
须要思考在备份集群资源时,是否须要在备份期间执行 备份 Hooks,比方须要将正在运行的利用的内存数据落盘场景。
相似的,在还原(迁徙)集群资源时,是否须要在还原期间执行 还原 Hooks,比方须要在还原前做一些初始化工作。
- 按需编写备份和还原的命令或资源清单
依据筛选归类的资源清单编写备份和还原策略,举荐在简单场景下应用创立资源清单的形式来执行备份和还原,YAML 资源清单比拟直观且不便保护,参数指定的形式能够在简略迁徙场景或测试时应用。
- 解决跨云平台资源的差异性
因为是跨云平台,动态创建 PVC 的存储类等关系可能不同,须要提前布局动静 PVC/PV 存储类关系是否须要从新映射,需在在还原操作前,创立相干映射的
ConfigMap
配置。如果须要解决更加个性化的差别,能够手动批改备份后的资源清单解决。 - 操作实现后核查迁徙资源
查看校验迁徙的集群资源是否合乎预期且数据残缺可用。
操作步骤
接下来将演示将某云平台集群 A 中的资源迁徙到 TKE 集群 B 中的操作步骤,其中波及到 Velero 备份和还原实用基础知识,如不理解请先移步文章开端【Velero 备份 / 还原实用常识】查看。
创立集群 A 示例资源
在某云平台集群 A 中部署 Velero 示例中含有 PVC 的 Nginx 工作负载,为了不便起见间接应用动静存储类来创立 PVC 和 PV,首先查看以后集群反对的动静存储类信息:
获取以后集群反对的存储类信息,其中 xxx-StorageClass 为存储类代名,xxx-Provider 为提供商代名,下同。
[root@iZj6c3vzs170hmeiu98h5aZ ~]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
xxx-StorageClass xxx-Provider Delete Immediate true 3d3h
…
应用集群中存储类名为 “xxx-StorageClass” 的存储类来动态创建,批改 with-pv.yaml 的 PVC 资源清单如下图:
…
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-logs
namespace: nginx-example
labels:
app: nginx
spec:
# Optional: 批改 PVC 的存储类的值为某云平台
storageClassName: xxx-StorageClass
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi # 因为该云平台限度存储最小为 20Gi,本示例须要同步批改此值为 20Gi
…
批改实现后利用示例中的 YAML 创立如下的集群资源(nginx-example 命名空间):
[root@iZj6c3vzs170hmeiu98h5aZ nginx-app]# kubectl apply -f with-pv.yaml
namespace/nginx-example created
persistentvolumeclaim/nginx-logs created
deployment.apps/nginx-deployment created
service/my-nginx created
创立进去的 PVC “nginx-logs” 已挂载给 nginx 容器的 /var/log/nginx
目录作为服务的日志存储,本示例在浏览器测试拜访 Nginx 服务,给挂载的 PVC 生产一些日志数据(以便后续还原后做数据比对)。
查看测试产生的 Nginx 日志大小,以后为 84 K
[root@iZj6c8ttj5dmmrs75yb7ybZ ~]# kubectl exec -it nginx-deployment-5ccc99bffb-6nm5w bash -n nginx-example
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] — [COMMAND]
Defaulting container name to nginx.
Use ‘kubectl describe pod/nginx-deployment-5ccc99bffb-6nm5w -n nginx-example’ to see all of the containers in this pod
root@nginx-deployment-5ccc99bffb-6nm5w:/# du -sh /var/log/nginx/
84K /var/log/nginx/
查看 accss.log 和 error.log 前两条日志
root@nginx-deployment-5ccc99bffb-6nm5w:/# head -n 2 /var/log/nginx/access.log
192.168.0.73 – – [29/Dec/2020:03:02:31 +0000] “GET /?spm=5176.2020520152.0.0.22d016ddHXZumX HTTP/1.1” 200 612 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36” “-“
192.168.0.73 – – [29/Dec/2020:03:02:32 +0000] “GET /favicon.ico HTTP/1.1” 404 555 “http://47.242.233.22/?spm=5176.2020520152.0.0.22d016ddHXZumX” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36” “-“
root@nginx-deployment-5ccc99bffb-6nm5w:/# head -n 2 /var/log/nginx/error.log
2020/12/29 03:02:32 [error] 6#6: *597 open() “/usr/share/nginx/html/favicon.ico” failed (2: No such file or directory), client: 192.168.0.73, server: localhost, request: “GET /favicon.ico HTTP/1.1”, host: “47.242.233.22”, referrer: “http://47.242.233.22/?spm=5176.2020520152.0.0.22d016ddHXZumX”
2020/12/29 03:07:21 [error] 6#6: *1172 open() “/usr/share/nginx/html/0bef” failed (2: No such file or directory), client: 192.168.0.73, server: localhost, request: “GET /0bef HTTP/1.0”
确认须要迁徙的资源清单
应用上面命令输入以后集群中所有的资源清单列表:
kubectl api-resources –verbs=list -o name | xargs -n 1 kubectl get –show-kind –ignore-not-found –all-namespaces
也能够依据资源是否辨别命名空间须要放大输入的资源范畴:
- 查看不辨别命名空间的资源清单列表:
kubectl api-resources –namespaced=false –verbs=list -o name | xargs -n 1 kubectl get –show-kind –ignore-not-found
- 查看辨别命名空间的资源清单列表:
kubectl api-resources –namespaced=true –verbs=list -o name | xargs -n 1 kubectl get –show-kind –ignore-not-found –all-namespaces
能够依据理论状况筛选出须要被迁徙的资源清单,本示例将间接从该云平台迁徙 “nginx-example” 命名空间下 Nginx 工作负载相干的资源到 TKE 平台,波及资源如下所示:
[root@iZj6c3vzs170hmeiu98h5aZ ~]# kubectl get all -n nginx-example
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-5ccc99bffb-tn2sh 2/2 Running 0 2d19h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-nginx LoadBalancer 172.21.1.185 x.x.x.x 80:31455/TCP 2d19h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 1/1 1 1 2d19h
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-5ccc99bffb 1 1 1 2d19h
[root@iZj6c3vzs170hmeiu98h5aZ ~]# kubectl get pvc -n nginx-example
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-logs Bound d-j6ccrq4k1moziu1l6l5r 20Gi RWO xxx-StorageClass 2d19h
[root@iZj6c3vzs170hmeiu98h5aZ ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
d-j6ccrq4k1moziu1l6l5r 20Gi RWO Delete Bound nginx-example/nginx-logs xxx-StorageClass 2d19h
确认 Hook 策略
本示例在 with-pv.yaml 中曾经配置了备份 Nginx 工作负载前将文件系统设置为只读,在备份后复原读写的 Hook 策略,如下 YAML 所示:
…
annotations:
# 备份 Hook 策略的注解示意:在开始备份之前将 nginx 日志目录设置为只读模式,备份实现后复原读写模式
pre.hook.backup.velero.io/container: fsfreeze
pre.hook.backup.velero.io/command: ‘[“/sbin/fsfreeze”, “–freeze”, “/var/log/nginx”]’
post.hook.backup.velero.io/container: fsfreeze
post.hook.backup.velero.io/command: ‘[“/sbin/fsfreeze”, “–unfreeze”, “/var/log/nginx”]’
spec:
volumes:
- name: nginx-logs
persistentVolumeClaim:
claimName: nginx-logs
containers:
- image: nginx:1.17.6
name: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: “/var/log/nginx”
name: nginx-logs
readOnly: false
- image: ubuntu:bionic
name: fsfreeze
securityContext:
privileged: true
volumeMounts:
- mountPath: “/var/log/nginx”
name: nginx-logs
…
开始迁徙操作
接下来依据理论状况编写备份和还原策略,开始对该云平台的 Nginx 工作负载相干资源进行迁徙。
在集群 A 执行备份
本示例创立如下 YAML 来备份想要迁徙的资源:
apiVersion: velero.io/v1
kind: Backup
metadata:
name: migrate-backup
# 必须得是 velero 装置的命名空间
namespace: velero
spec:
# 仅蕴含 nginx-example 命名空间的资源
includedNamespaces:
- nginx-example
# 蕴含不辨别命名空间的资源
includeClusterResources: true
# 备份数据存储地位指定
storageLocation: default
# 卷快照存储地位指定
volumeSnapshotLocations:
- default
# 应用 restic 备份卷
defaultVolumesToRestic: true
执行备份过程如下所示,当备份状态为 “Completed” 且 errors 数为 0 时示意备份过程残缺无误:
[root@iZj6c8ttj5dmmrs75yb7ybZ ~]# kubectl apply -f backup.yaml
backup.velero.io/migrate-backup created
[root@iZj6c8ttj5dmmrs75yb7ybZ ~]# velero backup get
NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR
migrate-backup InProgress 0 0 2020-12-29 19:24:12 +0800 CST 29d default <none>
[rootftiZi6c8tti5dmmrs75yb7vbZ ~1# velero backup get
NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR
migrate-backup Completed 0 0 2020-12-29 19:24:28 +0800 CST 29d default <none>
备份实现后,长期将备份存储地位更新为只读模式(非必须,这能够避免在还原过程中 Velero 在备份存储地位中创立或删除备份对象):
kubectl patch backupstoragelocation default –namespace velero
–type merge
–patch ‘{“spec”:{“accessMode”:”ReadOnly”}}’
解决跨云平台资源的差异性
- 因为应用的动静存储类有差别,这里须要如下所示的 ConfigMap 为长久卷 “nginx-logs” 创立动静存储类名映射:
apiVersion: v1
kind: ConfigMap
metadata:
name: change-storage-class-config
namespace: velero
labels:
velero.io/plugin-config: “”
velero.io/change-storage-class: RestoreItemAction
data:
# 存储类名映射到腾讯云动静存储类 cbs
xxx-StorageClass: cbs
利用上述的 ConfigMap
配置:
[root@VM-20-5-tlinux ~]# kubectl apply -f cm-storage-class.yaml
configmap/change-storage-class-config created
- Velero 备份的资源清单 以
json
格局寄存在对象存储中,如果有更加个性化的迁徙需要,能够间接下载备份文件并自定义批改,本示例将为 Nginx 的 Deployment 资源自定义增加一个 “jokey-test:jokey-test” 注解,批改过程如下:
jokey@JOKEYLI-MB0 Downloads % mkdir migrate-backup
解压备份文件
jokey@JOKEYLI-MB0 Downloads % tar -zxvf migrate-backup.tar.gz -C migrate-backup
编辑批改想要自定义的资源, 本示例为 nginx 的 Deployment 资源增加 “jokey-test”:”jokey-test” 的注解项
jokey@JOKEYLI-MB0 migrate-backup % cat resources/deployments.apps/namespaces/nginx-example/nginx-deployment.json
{“apiVersion”:”apps/v1″,”kind”:”Deployment”,”metadata”:{“annotations”:{“jokey-test”:”jokey-test”,…
从新打包批改后的备份文件
jokey@JOKEYLI-MB0 migrate-backup % tar -zcvf migrate-backup.tar.gz *
实现自定义批改并从新打包后上传替换原有备份文件:
在集群 B 执行还原
本示例利用如下所示的资源清单执行还原操作(迁徙):
apiVersion: velero.io/v1
kind: Restore
metadata:
name: migrate-restore
namespace: velero
spec:
backupName: migrate-backup
includedNamespaces:
- nginx-example
# 按需填写须要复原的资源类型,nginx-example 命名空间下没有想要排除的资源,所以这里间接写 ‘*’
includedResources:
- ‘*’
includeClusterResources: null
# 还原时不蕴含的资源,这里额定排除 StorageClasses 资源类型。
excludedResources:
- storageclasses.storage.k8s.io
# 应用 labelSelector 选择器抉择具备特定 label 的资源,因为此示例中无须再应用 label 选择器筛选,这里先正文。
# labelSelector:
# matchLabels:
# app: nginx
# 设置命名空间关系映射策略
namespaceMapping:
nginx-example: default
restorePVs: true
执行还原过程如下所示,当还原状态显示为 “Completed” 且 “errors” 数为 0 时示意还原过程残缺无误:
[root@VM-20-5-tlinux ~]# kubectl apply -f restore.yaml
restore.velero.io/migrate-restore created
[root@VM-20-5-tlinux ~]# velero restore get
NAME BACKUP STATUS STARTED COMPLETED ERRORS WARNINGS CREATED SELECTOR
migrate-restore migrate-backup Completed 2021-01-12 20:39:14 +0800 CST 2021-01-12 20:39:17 +0800 CST 0 0 2021-01-12 20:39:14 +0800 CST <none>
迁徙资源核查
-
首先查看被迁徙的资源的运行状态是否失常。
因为在还原时指定了 “nginx-example” 命名空间映射到 “default” 命名空间,所以还原的资源将运行在 “default” 命名空间下
[root@VM-20-5-tlinux ~]# kubectl get all -n default
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-5ccc99bffb-6nm5w 2/2 Running 0 49s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kube-user LoadBalancer 172.16.253.216 10.0.0.28 443:30060/TCP 8d
service/kubernetes ClusterIP 172.16.252.1 <none> 443/TCP 8d
service/my-nginx LoadBalancer 172.16.254.16 x.x.x.x 80:30840/TCP 49s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 1/1 1 1 49s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-5ccc99bffb 1 1 1 49s -
从下面能够看出被迁徙的资源的运行状态都是失常的,接下来核查设置的还原策略是否胜利。
-
核查动静存储类名映射是否正确:
能够看到 PVC/PV 的存储类曾经是 “cbs” 了,阐明存储类映射胜利。
[root@VM-20-5-tlinux ~]# kubectl get pvc -n default
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-logs Bound pvc-bcc17ccd-ec3e-4d27-bec6-b0c8f1c2fa9c 20Gi RWO cbs 55s
[root@VM-20-5-tlinux ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-bcc17ccd-ec3e-4d27-bec6-b0c8f1c2fa9c 20Gi RWO Delete Bound default/nginx-logs cbs 57s -
查看还原前为 “deployment.apps/nginx-deployment” 自定义增加的 “jokey-test” 注解是否胜利:
获取注解 ”jokey-test” 胜利, 阐明自定义批改资源胜利。
[root@VM-20-5-tlinux ~]# kubectl get deployment.apps/nginx-deployment -o custom-columns=annotations:.metadata.annotations.jokey-test
annotations
jokey-test - 从上述查看资源运行状态能够看出命名空间映射配置也是胜利的。
-
-
查看工作负载挂载的 PVC 数据是否胜利迁徙:
查看挂载的 PVC 数据目录中的数据大小,显示为 88K 比迁徙前多,起因是腾讯云 CLB 被动发动健康检查产生了一些日志。
[root@VM-20-5-tlinux ~]# kubectl exec -it nginx-deployment-5ccc99bffb-6nm5w -n default — bash
Defaulting container name to nginx.
Use ‘kubectl describe pod/nginx-deployment-5ccc99bffb-6nm5w -n default’ to see all of the containers in this pod.
root@nginx-deployment-5ccc99bffb-6nm5w:/# du -sh /var/log/nginx
88K /var/log/nginx查看前两条日志信息,和迁徙前统一,大抵阐明 PVC 数据没失落
root@nginx-deployment-5ccc99bffb-6nm5w:/# head -n 2 /var/log/nginx/access.log
192.168.0.73 – – [29/Dec/2020:03:02:31 +0000] “GET /?spm=5176.2020520152.0.0.22d016ddHXZumX HTTP/1.1” 200 612 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36” “-“
192.168.0.73 – – [29/Dec/2020:03:02:32 +0000] “GET /favicon.ico HTTP/1.1” 404 555 “http://47.242.233.22/?spm=5176.2020520152.0.0.22d016ddHXZumX” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36” “-“
root@nginx-deployment-5ccc99bffb-6nm5w:/# head -n 2 /var/log/nginx/error.log
2020/12/29 03:02:32 [error] 6#6: *597 open() “/usr/share/nginx/html/favicon.ico” failed (2: No such file or directory), client: 192.168.0.73, server: localhost, request: “GET /favicon.ico HTTP/1.1”, host: “47.242.233.22”, referrer: “http://47.242.233.22/?spm=5176.2020520152.0.0.22d016ddHXZumX”
2020/12/29 03:07:21 [error] 6#6: *1172 open() “/usr/share/nginx/html/0bef” failed (2: No such file or directory), client: 192.168.0.73, server: localhost, request: “GET /0bef HTTP/1.0”
综上所述,此示例胜利迁徙某云平台集群 A 的 Nginx(nginx-example 命名空间)工作负载相干资源和数据到 TKE 集群 B(default 命名空间)中。
总结
本示例解说和演示了常见的集群资源迁徙到 TKE 的思路和办法步骤,若在理论迁徙过程中遇到未笼罩到的场景时,欢送征询和探讨迁徙解决方案。
Velero 备份 / 还原实用常识
velero 提供了许多十分实用的备份和还原策略,以下作简要梳理:
-
当不应用任何筛选选项时,Velero 会将所有对象包含在备份或还原操作中,在 备份和还原 时能够指定参数按需过滤资源:
蕴含关系的过滤参数:
--include-resources
:指定要蕴含的资源对象列表。--include-namespaces
:指定要蕴含的命名空间列表。--include-cluster-resources
:指定是否要蕴含集群的资源。--selector
:指定蕴含与标签选择器匹配的资源。
不蕴含关系的过滤参数:
--exclude-namespaces
:指定要排除的命名空间列表--exclude-resources
:指定要排除的资源对象列表。velero.io/exclude-from-backup=true
:此配置项为资源对象配置 label 属性,增加了此 label 配置项的资源对象将会排除在外。
详情请参阅 资源过滤。
- 在 备份期间 执行一些 Hook 操作,比方须要在在备份前将内存数据落盘,详情请参阅 备份 Hooks。
- 在 还原期间 执行一些 Hook 操作,比方在还原前判断组件依赖是否可用,详情请参阅 还原 Hooks。
-
在 还原时 配置 PVC/PV 卷相干映射关系配置:
- 配置 PV / PVC 存储类映射。
- 配置 PVC 绑定节点映射。
详情请参阅 还原参考。
-
Restic 备份卷配置
从 1.5 版本开始,Velero 默认应用 Restic 备份所有 pod 卷,而不用独自正文每个 pod,所以 举荐应用 Velero 1.5 以上版本。
_在 1.5 版本以前,Velero 应用 restic 在备份卷时,Restic 有两种形式发现须要备份的 Pod 卷_:
- 应用的 Pod 卷备份抉择蕴含注解(默认):
kubectl -n <YOUR_POD_NAMESPACE> annotate <pod/YOUR_POD_NAME> backup.velero.io/backup-volumes=<YOUR_VOLUME_NAME_1,YOUR_VOLUME_NAME_2,…>
- 应用的 Pod 卷备份抉择不蕴含注解:
kubectl -n <YOUR_POD_NAMESPACE> annotate <pod/YOUR_POD_NAME> backup.velero.io/backup-volumes-excludes=<YOUR_VOLUME_NAME_1,YOUR_VOLUME_NAME_2,…>
备份实现后能够查看备份卷信息:
kubectl -n velero get podvolumebackups -l velero.io/backup-name=<YOUR_BACKUP_NAME> -o yaml
还原实现后能够查看还原卷信息:
kubectl -n velero get podvolumerestores -l velero.io/restore-name=<YOUR_RESTORE_NAME> -o yaml
- 应用的 Pod 卷备份抉择蕴含注解(默认):
- 除了应用 Velero 命令执行备份操作,也能够通过 创立备份资源来触发(举荐),配置示例请参阅 备份示例,API 具体字段定义可参考 备份 API 定义。
- 除了执行 Velero 命令执行还原操作,也能够通过 创立还原资源来触发(举荐),配置示例参参阅 还原示例,API 具体字段定义可参考 还原 API 定义。
- 如有 annonations、label 等其余个性化资源配置差别,能够在还原前手动编辑备份的 josn 资源清单文件。