詳解kubernetes備份恢復利器 Velero | 深入瞭解Carina系列第三期

BoCloud博雲發表於2022-06-24

Carina 是由博雲主導併發起的雲原生本地儲存專案(GitHub 地址為:https://github.com/carina-io/...),目前已經進入 CNCF 全景圖。

Carina 可以為雲原生環境中的有狀態應用提供高效能免運維本地儲存解決方案,具有儲存卷生命週期管理、LVM/RAW盤供應、智慧排程、RAID管理、自動分層等能力,旨在為雲原生有狀態服務提供極低延遲、免運維、懂資料庫的資料儲存系統。Carina 作為博雲容器雲平臺的元件之一,已經在多個金融機構的生產環境中穩定執行多年。

傳統的資料備份方案主要有兩種, 一種是利用儲存資料的服務端實現基於快照的備份,另一種是在每臺目標伺服器上部署專有備份 agent 並指定備份資料目錄,定期把資料複製到外部儲存上。這兩種方式的備份機制相對固化,在雲原生時代無法適應容器化後的彈性、池化等部署場景。

以雲原生儲存外掛 Carina 為例,資料庫等資料敏感場景中每個資料庫叢集包括多個計算例項,例項可能在叢集內任意漂移並實現自動故障恢復。傳統資料備份方式在資料庫叢集快速擴縮容、跨節點漂移等場景下無法自動跟隨計算例項遷移從而導致資料備份失效,因此一款貼合 k8s 容器場景的備份工具就十分重要。

Kubernetes備份恢復利器:velero

Velero 是一款雲原生時代的災難恢復和遷移工具,採用 Go 語言編寫,並在 github 上進行了開源,開源地址為:https://github.com/vmware-tan...。Velero 源於西班牙語,意思為帆船,非常符合 Kubernetes 社群的命名風格。

利用 velero 使用者可以安全的備份、恢復和遷移 Kubernetes 叢集資源和持久卷。它的基本原理就是將叢集的資料,例如叢集資源和持久化資料卷備份到物件儲存中,在恢復的時候將資料從物件儲存中拉取下來。除了災備之外它還能做資源移轉,支援把容器應用從一個叢集遷移到另一個叢集,這也是 velero 一個非常成功的使用場景。

Velero 主要包括兩個核心元件,分別為服務端和客戶端。服務端執行在具體的 Kubernetes 叢集中,客戶端是執行在本地的命令列工具,只要配置好 kubectl 及 kubeconfig 即可使用,非常簡單。

Velero 基於其實現的 kubernetes 資源備份能力,可以輕鬆實現 Kubernetes 叢集的資料備份和恢復、複製 kubernetes 叢集資源到其他 kubernetes 叢集或者快速複製生產環境到測試環境等功能。

在資源備份方面,velero 支援將資料備份到眾多的雲端儲存中,例如AWS S3或S3相容的儲存系統、Azure Blob、Google Cloud儲存、Aliyun OSS等。與備份整個 kubernetes 的資料儲存引擎 etcd 相比,velero 的控制更加細化,可以對 Kubernetes 叢集內物件級別進行備份,還可以通過對 Type、Namespace、Label 等物件進行分類備份或者恢復。

Velero工作流程

以核心的資料備份為例,當執行velero backup create my-backup時:

  • Velero 客戶端首先呼叫 Kubernetes API 伺服器以建立 Backup 物件;
  • BackupController 將收到通知有新的 Backup 物件被建立並執行驗證;
  • BackupController 開始備份過程,它通過查詢 API 伺服器以獲取資源來收集資料以進行備份;
  • BackupController 將呼叫物件儲存服務,例如,AWS S3 -上傳備份檔案。預設情況下,velero backup create支援任何持久卷的磁碟快照,可以通過指定其他標誌來調整快照,執行velero backup create --help可以檢視可用的標誌,也可以使用--snapshot-volumes=false選項禁用快照。

關於備份儲存位置和卷快照,Velero 有兩個自定義資源 BackupStorageLocation 和 VolumeSnapshotLocation,用於配置 Velero 備份及其關聯的持久卷快照的儲存位置。

  • BackupStorageLocation 主要支援的後端儲存是 S3 相容的儲存,儲存所有Velero資料的儲存區中的字首以及一組其他特定於提供程式的欄位。比如:Minio 和阿里雲 OSS 等 ;
  • VolumeSnapshotLocation(pv 資料),主要用來給 PV 做快照,需要雲提供商提供外掛,完全由提供程式提供的特定的欄位(例如AWS區域,Azure資源組,Portworx快照型別等)定義。以對資料一致性最為敏感的資料庫和中介軟體為例,開源儲存外掛 Carina 也即將提供資料庫感知的 velero 卷快照功能,可以實現中介軟體資料的快速備份及恢復。

Velero安裝和使用

安裝velero客戶端

$ wget https://mirror.ghproxy.com/https://github.com/vmware-tanzu/velero/releases/download/v1.6.3/velero-v1.6.3-darwin-amd64.tar.gz 
$ tar -zxvf velero-v1.6.3-darwin-amd64.tar.gz && cd velero-v1.6.3-darwin-amd64 
$ mv velero /usr/local/bin && chmod +x /usr/local/bin/velero 
$ velero version

安裝minio作為資料備份後端

Minio安裝Yaml檔案如下:

apiVersion: v1 
kind: Namespace 
metadata: 
  name: velero 
--- 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  namespace: velero 
  name: minio 
  labels: 
    component: minio 
spec: 
  strategy: 
    type: Recreate 
  selector: 
    matchLabels: 
      component: minio 
  template: 
    metadata: 
      labels: 
        component: minio 
    spec: 
      volumes: 
      - name: storage 
        emptyDir: {} 
      - name: config 
        emptyDir: {} 
      containers: 
      - name: minio 
        image: minio/minio:latest 
        imagePullPolicy: IfNotPresent 
        args: 
        - server 
        - /storage 
        - --config-dir=/config 
        - --console-address=:9001 
        env: 
        - name: MINIO_ACCESS_KEY 
          value: "minio" 
        - name: MINIO_SECRET_KEY 
          value: "minio123" 
        ports: 
        - containerPort: 9000 
        - containerPort: 9001 
        volumeMounts: 
        - name: storage 
          mountPath: "/storage" 
        - name: config 
          mountPath: "/config" 
--- 
apiVersion: v1 
kind: Service 
metadata: 
  namespace: velero 
  name: minio 
  labels: 
    component: minio 
spec: 
  type: NodePort 
  ports: 
    - name: api 
      port: 9000 
      targetPort: 9000 
    - name: console 
      port: 9001 
      targetPort: 9001 
  selector: 
    component: minio 
--- 
apiVersion: batch/v1 
kind: Job 
metadata: 
  namespace: velero 
  name: minio-setup 
  labels: 
    component: minio 
spec: 
  template: 
    metadata: 
      name: minio-setup 
    spec: 
      restartPolicy: OnFailure 
      volumes: 
      - name: config 
        emptyDir: {} 
      containers: 
      - name: mc 
        image: minio/mc:latest 
        imagePullPolicy: IfNotPresent 
        command: 
        - /bin/sh 
        - -c 
        - "mc --config-dir=/config config host add velero http://minio:9000 minio minio123 && mc --config-dir=/config mb -p velero/velero" 
        volumeMounts: 
        - name: config 
          mountPath: "/config" 

安裝Mini,並檢查資源建立情況。

$ kubectl apply -f ./00-minio-deployment.yaml 
$ kubectl get pods -n velero 
NAME                     READY   STATUS              RESTARTS   AGE
minio-58dc5cf789-z2777   0/1     ContainerCreating   0          14s
minio-setup-dz4jb        0/1     ContainerCreating   0          6s
$ kubectl get svc  -n velero 
NAME    TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)                         AGE
minio   NodePort   10.96.13.35   <none>        9000:30693/TCP,9001:32351/TCP   17s

待服務都已經啟動完畢,可以登入 minio 檢視 velero/velero 的 bucket 是否建立成功。

安裝 velero 服務端 ,使用s3 作為儲存

  • 建立 minio 憑證

    $ cat > credentials-velero <<EOF
    [default]
    aws_access_key_id = minio
    aws_secret_access_key = minio123
    EOF
    # 安裝velero
    $ cp velero /usr/bin/
    # 啟用快速補全
    $ velero completion bash
  • 使用官方提供的 restic 元件備份 pv

    $ velero install    \
     --image velero/velero:v1.6.3  \
       --plugins velero/velero-plugin-for-aws:v1.0.0  \
       --provider aws   \
       --bucket velero   \
       --namespace velero  \
       --secret-file ./credentials-velero   \
       --velero-pod-cpu-request 200m   \
       --velero-pod-mem-request 200Mi   \
       --velero-pod-cpu-limit 1000m  \
       --velero-pod-mem-limit 1000Mi   \
       --use-volume-snapshots=false   \
       --use-restic   \
       --restic-pod-cpu-request 200m   \
       --restic-pod-mem-request 200Mi   \
       --restic-pod-cpu-limit 1000m  \
       --restic-pod-mem-limit 1000Mi  \
       --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.velero.svc:9000

其中,幾個重要的引數及其說明如下:

--provider:宣告使用的 Velero 外掛型別。
--plugins:使用 S3 API 相容外掛 “velero-plugin-for-aws ”。
--bucket:在騰訊雲 COS 建立的儲存桶名。
--secret-file:訪問 COS 的訪問憑證檔案,見上面建立的 “credentials-velero”憑證檔案。
--use-restic:使用開源免費備份工具 restic 備份和還原持久卷資料。
--default-volumes-to-restic:使用 restic 來備份所有Pod卷,前提是需要開啟 --use-restic 引數。
--backup-location-config:備份儲存桶訪問相關配置。
--region:相容 S3 API 的 COS 儲存桶地區,例如建立地區是廣州的話,region 引數值為“ap-guangzhou”。
--s3ForcePathStyle:使用 S3 檔案路徑格式。
--s3Url:COS 相容的 S3 API 訪問地址
--use-volume-snapshots=false 來關閉儲存卷資料快照備份。

安裝命令執行完成後,等待 Velero 和 restic 工作負載就緒後,檢視配置的儲存位置是否可用。

$ velero backup-location get 

apiVersion: velero.io/v1    
kind: BackupStorageLocation    
metadata:    
  name: default    
  namespace: velero    
spec:    
# 只有 aws gcp azure    
  provider: aws    
  objectStorage:    
    bucket: myBucket    
    prefix: backup    
  config:    
    region: us-west-2        
    profile: "default"    
    s3ForcePathStyle: "false"    
    s3Url: http://minio:9000

至此 velero 就已經全部部署完成。

velero功能介紹

建立備份

velero 支援備份所有物件,也可以按型別,名稱空間和/或標籤過濾物件

$ velero create backup $NAME [flags]
$ velero backup create pvc-backup-1  --snapshot-volumes --include-namespaces nginx-example --default-volumes-to-restic --volume-snapshot-locations default

其中:

--include-namespaces:備份該名稱空間下的所有資源,不包括叢集資源

--include-resources:要備份的資源型別

--include-cluster-resources:是否備份叢集資源
此選項可以具有三個可能的值:

true:包括所有叢集範圍的資源;
false:不包括叢集範圍內的資源;
nil (“自動”或不提供)

--selector:通過標籤選擇匹配的資源備份

--exclude-namespaces:備份時該名稱空間下的資源不進行備份

--exclude-resources:備份時該型別的資源不進行備份

--velero.io/exclude-from-backup=true:當標籤選擇器匹配到該資源時,若該資源帶有此標籤,也不進行備份

同時,也可以通過使用 –ordered-resources 引數,按特定順序備份特定種類的資源,需要指定資源名稱和該資源的物件名稱列表,資源物件名稱以逗號分隔,其名稱格式為“名稱空間/資源名稱”,對於叢集範圍資源,只需使用資源名稱。對映中的鍵值對以分號分隔,資源型別是複數形式。

$ velero backup create backupName --include-cluster-resources=true --ordered-resources 'pods=ns1/pod1,ns1/pod2;persistentvolumes=pv4,pv8' --include-namespaces=ns1

$ velero backup create backupName --ordered-resources 'statefulsets=ns1/sts1,ns1/sts0' --include-namespaces=n

定時備份:

$ velero schedule create <SCHEDULE NAME> --schedule "0 7 * * *"

$ velero create schedule NAME --schedule="@every 6h"

$ velero create schedule NAME --schedule="@every 24h" --include-namespaces web

$ velero create schedule NAME --schedule="@every 168h" --ttl 2160h0m0s

備份高階用法舉例

  • 在單個Velero備份中建立不止一種持久卷的快照

    $ velero snapshot-location create ebs-us-east-1 \
      --provider aws \
      --config region=us-east-1
    
    $ velero snapshot-location create portworx-cloud \
      --provider portworx \
      --config type=cloud
    
    $ velero backup create full-cluster-backup \
      --volume-snapshot-locations ebs-us-east-1,portworx-cloud    
  • 在不同的地區將備份儲存到不同的物件儲存桶中

    $ velero backup-location create default \
      --provider aws \
      --bucket velero-backups \
      --config region=us-east-1
    
    $ velero backup-location create s3-alt-region \
      --provider aws \
      --bucket velero-backups-alt \
      --config region=us-west-1
    
    $ velero backup create full-cluster-alternate-location-backup \
      --storage-location s3-alt-region
  • 對於公有云提供的儲存卷,將一部分快照儲存在本地,一部分儲存在公有云

    $ velero snapshot-location create portworx-local \
      --provider portworx \
      --config type=local
    
    $ velero snapshot-location create portworx-cloud \
      --provider portworx \
      --config type=cloud
    
    $ velero backup create cloud-snapshot-backup \
      --volume-snapshot-locations portworx-cloud    
  • 使用儲存位置

    $ velero backup-location create default \
      --provider aws \
      --bucket velero-backups \
      --config region=us-west-1
    
    $ velero snapshot-location create ebs-us-west-1 \
      --provider aws \
      --config region=us-west-1
    
    $ velero backup create full-cluster-backup

檢視備份任務。

當備份任務狀態是 “Completed” ,且錯誤數為 0 ,說明備份任務完成且沒發生任何錯誤,可以通過以下命令查詢:

 $ velero backup get 

通過先臨時將備份儲存位置更新為只讀模式,可以防止在還原過程中在備份儲存位置中建立或刪除備份物件。

$ kubectl patch backupstoragelocation default --namespace velero \
    --type merge \
    --patch '{"spec":{"accessMode":"ReadOnly"}}'
    
velero backup-location get
NAME      PROVIDER   BUCKET/PREFIX   PHASE     LAST VALIDATED   ACCESS MODE   DEFAULT
default   aws        velero          Unknown   Unknown          ReadWrite     true

恢復備份資料

$ velero restore create --from-backup <backup-name>
$ velero  restore create --from-backup pvc-backup-1 --restore-volumes

檢視恢復任務。

$ velero restore get 

還原完成後,不要忘記把備份儲存位置恢復為讀寫模式,以便下次備份任務使用:

$ kubectl patch backupstoragelocation default --namespace velero \
   --type merge \
   --patch '{"spec":{"accessMode":"ReadWrite"}}'

備份 hooks 介紹

Velero 支援在備份任務執行之前和執行後在容器中執行一些預先設定好的命令,這種方式對資料一致性等非常有效。velero 支援兩種方法指定鉤子,一種是 pod 本身的註釋宣告,另一種是在定義 Backup 任務時的 Spec 中宣告。

  • Pre hooks

    pre.hook.backup.velero.io/container:將要執行命令的容器,預設為pod中的第一個容器,可選的。
    
    pre.hook.backup.velero.io/command:要執行的命令,如果需要多個引數,請將該命令指定為JSON陣列。例如:["/usr/bin/uname", "-a"]
    
    pre.hook.backup.velero.io/on-error:如果命令返回非零退出程式碼如何處理。預設為“Fail”,有效值為“Fail”和“Continue”,可選的。
    
    pre.hook.backup.velero.io/timeout:等待命令執行的時間,如果命令超過超時,則認為該掛鉤失敗的。預設為30秒,可選的。
    
  • Post hooks

    post.hook.backup.velero.io/container:將要執行命令的容器,預設為pod中的第一個容器,可選的。
    
    post.hook.backup.velero.io/command:要執行的命令,如果需要多個引數,請將該命令指定為JSON陣列。例如:["/usr/bin/uname", "-a"]
    
    post.hook.backup.velero.io/on-error:如果命令返回非零退出程式碼如何處理。預設為“Fail”,有效值為“Fail”和“Continue”,可選的。
    
    post.hook.backup.velero.io/timeout:等待命令執行的時間,如果命令超過超時,則認為該掛鉤失敗的。預設為30秒,可選的

    還原 hooks 介紹

    Velero 支援還原 hooks,可以在還原任務執行前或還原過程之後執行的自定義操作。有以下兩種定義形式:

  • InitContainer Restore Hooks:這些將在待還原的 Pod 的應用程式容器啟動之前將 init 容器新增到還原的 pod 中,以執行任何必要的設定。
init.hook.restore.velero.io/container-image:要新增的init容器的容器映象

init.hook.restore.velero.io/container-name:要新增的init容器的名稱

init.hook.restore.velero.io/command:將要在初始化容器中執行的任務或命令

如進行備份之前,請使用以下命令將註釋新增到Pod:

kubectl annotate pod -n <POD_NAMESPACE> <POD_NAME> \
    init.hook.restore.velero.io/container-name=restore-hook \
    init.hook.restore.velero.io/container-image=alpine:latest \
    init.hook.restore.velero.io/command='["/bin/ash", "-c", "date"]'
  • Exec Restore Hooks:可用於在已還原的Kubernetes pod的容器中執行自定義命令或指令碼。

    post.hook.restore.velero.io/container:;執行hook的容器名稱,預設為第一個容器,可選
    
    post.hook.restore.velero.io/command:將在容器中執行的命令,必填
    
    post.hook.restore.velero.io/on-error:如何處理執行失敗,有效值為Fail和Continue,預設為Continue,使用Continue模式,僅記錄執行失敗;使用Fail模式時,將不會在自行其他的hook,還原的狀態將為PartiallyFailed,可選
    
    post.hook.restore.velero.io/exec-timeout:開始執行後要等待多長時間,預設為30秒,可選
    
    post.hook.restore.velero.io/wait-timeout:等待容器準備就緒的時間,該時間應足夠長,以使容器能夠啟動,並

    如進行備份之前,請使用以下命令將註釋新增到Pod

    kubectl annotate pod -n <POD_NAMESPACE> <POD_NAME> \
      post.hook.restore.velero.io/container=postgres \
      post.hook.restore.velero.io/command='["/bin/bash", "-c", "psql < /backup/backup.sql"]' \
      post.hook.restore.velero.io/wait-timeout=5m \
      post.hook.restore.velero.io/exec-timeout=45s \
      post.hook.restore.velero.io/on-error=Continue

Velero部分關鍵問題解析

Velero可以將資源還原到與其備份來源不同的名稱空間中嗎?

是的,可以使用--namespace-mappings引數來指定:

velero restore create RESTORE_NAME \
  --from-backup BACKUP_NAME \
  --namespace-mappings old-ns-1:new-ns-1,old-ns-2:new-ns-2

執行還原操作後,已有的 NodePort 型別的 service 如何處理?

Velero 有一個引數,可讓使用者決定保留原來的 nodePorts。

velero restore create子命令具有 --preserve-nodeports標誌保護服務nodePorts。此標誌用於從備份中保留原始的nodePorts,可用作--preserve-nodeports或--preserve-nodeports=true
如果給定此標誌,則Velero在還原Service時不會刪除nodePorts,而是嘗試使用備份時寫入的nodePorts。

velero怎麼實現不影響業務前提下得一致性備份策略,並將備份資料上傳到物件儲存中?

如果是基於velero實現資料庫的一致性,需要用velero的hook,在備份前對資料庫進行quiesce操作,備份完unquiesce。對於備份本身,可以使用restic來copy資料(但不用快照),或者使用快照的方式。

相關文章