概述
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 卷相關對映關係配置:
詳情請參閱 還原參考。
-
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
-
-
除了使用 Velero 命令執行備份操作,也可以通過建立備份資源來觸發(推薦),配置示例請參閱 備份示例 ,API 詳細欄位定義可參考 備份 API 定義。
-
除了執行 Velero 命令執行還原操作,也可以通過建立還原資源來觸發(推薦),配置示例參參閱 還原示例,API 詳細欄位定義可參考 還原 API 定義。
-
如有 annonations 、label 等其他個性化資源配置差異,可以在還原前手動編輯備份的 josn 資源清單檔案。