使用 Velero 備份還原 Kubernetes 集羣
-
備份集羣數據,並在集羣故障的情況下進行還原
-
將集羣資源遷移到其他集羣
-
將生產集羣複製到開發和測試集羣
Velero 包含一個在集羣上運行的服務器端和在本地運行的命令行客戶端。
原理
每個 Velero 的操作(比如按需備份、計劃備份、還原)都是 CRD 自定義資源,Velero 可以備份或還原集羣中的所有對象,也可以按類型、namespace 或標籤過濾對象。Velero 是 Kubernetes 用來災難恢復的理想選擇,也可以在集羣上執行系統操作(比如升級)之前對應用程序狀態進行快照的理想選擇。
按需備份
按需備份操作可以將複製的 Kubernetes 對象的壓縮文件上傳到雲對象存儲中,也可以調用雲環境提供的 API 來創建持久化卷的磁盤快照。我們可以選擇指定在備份期間執行的備份 hook,比如你可能需要在拍攝快照之前告訴數據庫將其內存中的緩衝區刷新到磁盤。
需要注意的是集羣備份並不是嚴格的原子備份,如果在備份時創建或編輯 Kubernetes 對象,則它們可能不會被包含在備份中,是可能出現這種狀況的。
定時備份
通過定時
操作,我們可以定期備份數據,第一次創建日程表時將執行第一次備份,隨後的備份將按日程表指定的間隔進行備份,這些間隔由 Cron 表達式指定。
定時備份保存的名稱爲 <SCHEDULE NAME>-<TIMESTAMP>
,其中 <TIMESTAMP>
格式爲 YYYYMMDDhhmmss
。
備份還原
通過還原操作,我們可以從以前創建的備份中還原所有對象和持久卷,此外我們還可以僅還原對象和持久卷的子集,Velero 支持多個命名空間重新映射。例如在一次還原操作中,可以在命名空間 def 下重新創建命名空間 abc 中的對象,或在 456 之下重新創建名稱空間 123 中的對象。
還原的默認名稱爲 <BACKUP NAME>-<TIMESTAMP>
,<TIMESTAMP>
格式爲 YYYYMMDDhhmmss
,還可以指定自定義名稱,恢復的對象還包括帶有鍵 velero.io/restore-name
和值的標籤 <RESTORE NAME>
。
默認情況下,備份存儲位置以讀寫模式創建,但是,在還原期間,可以將備份存儲位置配置爲只讀模式,這將禁用該存儲位置的備份創建和刪除,這對於確保在還原方案期間不會無意間創建或刪除任何備份非常有用。此外我們還可以選擇指定在還原期間或還原資源後執行的還原 hook,例如可能需要在數據庫應用程序容器啓動之前執行自定義數據庫還原操作。
備份流程
執行命令 velero backup create test-backup
的時候,會執行下面的操作:
-
Velero 客戶端調用 Kubernetes APIServer 創建 Backup 這個 CRD 對象
-
Backup 控制器 watch 到新的 Backup 對象被創建並執行驗證
-
Backup 控制器開始執行備份,通過查詢 APIServer 來獲取資源收集數據進行備份
-
Backup 控制器調用對象存儲服務,比如 S3 上傳備份文件
默認情況下 velero backup create
支持任何持久卷的磁盤快照,可以通過指定其他參數來調整快照,可以使用 --snapshot-volumes=false
選項禁用快照。
設置備份過期時間
創建備份時,可以通過添加標誌 --ttl
來指定 TTL,如果未指定,則將默認的 TTL 值爲 30 天,如果 Velero 檢測到有備份資源已過期,它將刪除以下相應備份數據:
-
備份資源
-
來自雲對象存儲的備份文件
-
所有 PersistentVolume 快照
-
所有關聯的還原
同步對象存儲
Velero 將對象存儲視爲資源的來源,它不斷檢查以確保始終存在正確的備份資源,如果存儲桶中有格式正確的備份文件,但 Kubernetes APIServer 中沒有相應的備份資源,則 Velero 會將信息從對象存儲同步到 Kubernetes,這使還原功能可以在集羣遷移方案中工作,在該方案中,新集羣中不存在原始的備份對象。同樣,如果備份對象存在於 Kubernetes 中,但不存在於對象存儲中,則由於備份壓縮包不再存在,它將從 Kubernetes 中刪除。
備份存儲位置和卷快照位置
Velero 有兩個自定義資源 BackupStorageLocation
和 VolumeSnapshotLocation
,用於配置 Velero 備份及其關聯的持久卷快照的存儲位置。
-
BackupStorageLocation
:定義爲存儲區,存儲所有 Velero 數據的存儲區中的前綴以及一組其他特定於提供程序的字段, 後面部分會詳細介紹該部分所包含的字段。 -
VolumeSnapshotLocation
:完全由提供程序提供的特定的字段(例如 AWS 區域,Azure 資源組,Portworx 快照類型等)定義。
用戶可以預先配置一個或多個可能的 BackupStorageLocations
對象,也可以預先配置一個或多個 VolumeSnapshotLocations
對象,並且可以在創建備份時選擇應該存儲備份和相關快照的位置。
此配置設計支持許多不同的用法,包括:
-
在單個 Velero 備份中創建不止一種持久卷的快照。例如,在同時具有 EBS 卷和 Portworx 卷的集羣中
-
在不同地區將數據備份到不同的存儲中
-
對於支持它的卷提供程序(例如 Portworx),可以將一些快照存儲在本地集羣中,而將其他快照存儲在雲中
安裝
在 Github Release 頁面
(https://github.com/vmware-tanzu/velero/releases) 下載指定的 velero 二進制客戶端安裝包,比如這裏我們下載最新穩定版本 v1.6.3
,
➜ ~ wget https://github.com/vmware-tanzu/velero/releases/download/v1.6.3/velero-v1.6.3-darwin-amd64.tar.gz
# 如果有限制,也可以替換成下面的 URL 加速下載
# wget https://download.fastgit.org/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
➜ ~ tree .
.
├── LICENSE
├── examples
│ ├── README.md
│ ├── minio
│ │ └── 00-minio-deployment.yaml
│ └── nginx-app
│ ├── README.md
│ ├── base.yaml
│ └── with-pv.yaml
└── velero
3 directories, 7 files
將根目錄下面的 velero
二進制文件拷貝到 PATH 路徑下面:
➜ ~ cp velero /usr/local/bin && chmod +x /usr/local/bin/velero
➜ ~ velero version
Client:
Version: v1.6.3
Git commit: 5fe3a50bfddc2becb4c0bd5e2d3d4053a23e95d2
<error getting server version: no matches for kind "ServerStatusRequest" in version "velero.io/v1">
安裝 MINIO
這裏我們可以使用 minio 來代替雲環境的對象存儲,在上面解壓的壓縮包中包含一個 examples/minio/00-minio-deployment.yaml
的資源清單文件,爲了測試方便可以將其中的 Service 更改爲 NodePort 類型,我們可以配置一個 console-address
來提供一個 console 頁面的訪問入口,完整的資源清單文件如下所示:
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"
然後直接部署在 Kubernetes 集羣中即可:
➜ ~ kubectl apply -f examples/minio/00-minio-deployment.yaml
namespace/velero created
deployment.apps/minio created
service/minio created
job.batch/minio-setup created
➜ ~ kubectl get pods -n velero
NAME READY STATUS RESTARTS AGE
minio-5b96ffddf8-x8s7p 1/1 Running 0 2m48s
minio-setup-rhc4d 0/1 Completed 1 2m48s
➜ ~ kubectl get svc -n velero
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
minio NodePort 10.103.132.34 <none> 9000:32036/TCP,9001:31925/TCP 3m56s
然後我們可以通過 http://<nodeip>:31925
訪問 minio 的 console 頁面,使用 minio
與 minio
進行登錄即可:
當然如果需要在不同 Kubernetes 和存儲池集羣備份與恢復數據,需要將 minio 服務端安裝在 Kubernetes 集羣外,保證在集羣發生災難性故障時,不會對備份數據產生影響,可以通過二進制的方式進行安裝。
在待安裝 minio 的服務器上下載二進制包
➜ ~ wget https://dl.minio.io/server/minio/release/linux-amd64/minio
➜ ~ chmod +x minio
➜ ~ sudo mv minio /usr/local/bin/
➜ ~ minio --version
準備對象存儲的磁盤,這裏我們跳過該步驟,可以使用 systemd 來方便管理 minio 服務,對於使用 systemd init 系統運行系統的人,請創建用於運行 minio 服務的用戶和組:
➜ ~ sudo groupadd --system minio
➜ ~ sudo useradd -s /sbin/nologin --system -g minio minio
爲 /data
(上述步驟準備好的磁盤掛載位置) 目錄提供 minio 用戶所有權:
➜ ~ sudo chown -R minio:minio /data/
爲 minio 創建 systemd 服務單元文件:
➜ ~ vi /etc/systemd/system/minio.service
[Unit]
Description=Minio
Documentation=https://docs.minio.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio
[Service]
WorkingDirectory=/data
User=minio
Group=minio
EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
# Let systemd restart this service always
Restart=always
# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536
# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no
[Install]
WantedBy=multi-user.target
創建 minio 環境文件 /etc/default/minio
:
# Volume to be used for Minio server.
MINIO_VOLUMES="/data"
# Use if you want to run Minio on a custom port.
MINIO_OPTS="--address :9000"
# Access Key of the server.
MINIO_ACCESS_KEY=minio
# Secret key of the server.
MINIO_SECRET_KEY=minio123
其中 MINIO_ACCESS_KEY
爲長度至少爲 3 個字符的訪問密鑰,MINIO_SECRET_KEY
爲最少 8 個字符的密鑰。重新加載 systemd 並啓動 minio 服務:
➜ ~ sudo systemctl daemon-reload
➜ ~ sudo systemctl start minio
關於 minio 的更多使用方法可以參考官方文檔 https://docs.min.io/ 瞭解更多。
安裝 velero 服務端
我們可以使用 velero 客戶端來安裝服務端,也可以使用 Helm Chart 來進行安裝,比如這裏我們用客戶端來安裝,velero 命令默認讀取 kubectl 配置的集羣上下文,所以前提是 velero 客戶端所在的節點有可訪問集羣的 kubeconfig 配置。
首先準備密鑰文件,在當前目錄建立一個空白文本文件,內容如下所示:
[default]
aws_access_key_id=<access key id>
aws_secret_access_key=<secret access key>
替換爲之前步驟中 minio 的對應 access key id 和 secret access key 如果 minio 安裝在 kubernetes 集羣內時按照如下命令安裝 velero 服務端:
➜ ~ velero install \
--provider aws \
--bucket velero \
--image velero/velero:v1.6.3 \
--plugins velero/velero-plugin-for-aws:v1.2.1 \
--namespace velero \
--secret-file ./credentials-velero \
--use-volume-snapshots=false \
--use-restic \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.velero.svc:9000
......
DaemonSet/restic: created
Velero is installed! ⛵ Use 'kubectl logs deployment/velero -n velero' to view the status.
➜ ~ kubectl get pods -n velero
NAME READY STATUS RESTARTS AGE
minio-5b96ffddf8-x8s7p 1/1 Running 0 4m1s
minio-setup-rhc4d 0/1 Completed 1 4m1s
restic-2qn94 1/1 Running 0 22s
velero-664598d6cc-dpvxn 1/1 Running 0 22s
由於我們這裏準備使用 minio 來作爲對象存儲,minio 是兼容 S3 的,所以這裏我們配置的 provider(聲明使用的 Velero 插件類型)是 aws
,--secret-file
用來提供訪問 minio 的密鑰,--use-restic
表示使用開源免費備份工具 restic 備份和還原持久卷數據,啓用該參數後會部署一個名爲 restic 的 DaemonSet 對象,--plugins
使用的 velero 插件,我們使用 AWS S3 兼容插件。
安裝完成後 velero 的服務端就部署成功了。
測試
比如現在我們部署一個 mysql 應用,資源清單文件如下所示:
# mysql-deployment.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
labels:
app: mysql
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
labels:
app: mysql
spec:
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
livenessProbe:
tcpSocket:
port: 3306
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
直接部署上面的應用:
➜ ~ kubectl create namespace kube-demo
➜ ~ kubectl create secret generic mysql-pass --from-literal=password=password321 -n kube-demo
➜ ~ kubectl apply -f mysql-deployment.yaml -n kube-demo
➜ ~ kubectl get pods -n kube-demo
NAME READY STATUS RESTARTS AGE
mysql-c57f676dd-gw5pf 1/1 Running 0 51s
比如現在我們創建一個新的數據庫 velero:
➜ ~ kubectl exec -it -n kube-demo mysql-c57f676dd-gw5pf -- /bin/bash
mysql-c57f676dd-gw5pf:/# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.6.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
mysql> create database velero;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| velero |
+--------------------+
4 rows in set (0.00 sec)
mysql>
現在我們來執行一個備份:
➜ ~ velero backup create mysql-backup --include-namespaces kube-demo --default-volumes-to-restic
Backup request "mysql-backup" submitted successfully.
Run `velero backup describe mysql-backup` or `velero backup logs mysql-backup` for more details.
其中我們指定的 --default-volumes-to-restic
參數表示使用 restic 備份持久捲到 minio,--include-namespaces
用來備份該命名空間下的所有資源,不包括集羣資源,此外還可以使用 --include-resources
指定要備份的資源類型 ,--include-cluster-resources
指定是否備份集羣資源。
該命令請求創建一個對項目(命名空間)的備份,備份請求發送之後可以用命令查看備份狀態,等到 STATUS 列變爲 Completed
表示備份完成。
➜ ~ velero backup get
NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR
mysql-backup Completed 0 0 2021-09-16 16:58:51 +0800 CST 29d default <none>
➜ ~ velero backup describe mysql-backup
Name: mysql-backup
Namespace: velero
Labels: velero.io/storage-location=default
Annotations: velero.io/source-cluster-k8s-gitversion=v1.18.4-tke.6
velero.io/source-cluster-k8s-major-version=1
velero.io/source-cluster-k8s-minor-version=18+
Phase: Completed
Errors: 0
Warnings: 0
Namespaces:
Included: kube-demo
Excluded: <none>
Resources:
Included: *
Excluded: <none>
Cluster-scoped: auto
Label selector: <none>
Storage Location: default
Velero-Native Snapshot PVs: auto
TTL: 720h0m0s
Hooks: <none>
Backup Format Version: 1.1.0
Started: 2021-09-16 16:58:51 +0800 CST
Completed: 2021-09-16 16:59:08 +0800 CST
Expiration: 2021-10-16 16:58:51 +0800 CST
Total items to be backed up: 30
Items backed up: 30
Velero-Native Snapshots: <none included>
Restic Backups (specify --details for more information):
Completed: 1
備份完成後可以去 minio 的 bucket 上查看是否有對應的備份數據:
現在我們刪除應用所在的命名空間來模擬生產環境發生災難或運維錯誤導致應用失敗的場景:
➜ ~ kubectl delete namespace kube-demo
這個時候我們肯定訪問不了我們的 MySQL 數據庫了,這時候我們可以用一條命令,使用 velero 從 minio 中來恢復應用和數據:
➜ ~ velero restore create --from-backup mysql-backup
Restore request "mysql-backup-20210916172100" submitted successfully.
Run `velero restore describe mysql-backup-20210916172100` or `velero restore logs mysql-backup-20210916172100` for more details.
同樣我們可以使用 velero restore get
來查看還原的進度,等到 STATUS 列變爲 Completed
表示還原完成:
➜ ~ velero restore get
NAME BACKUP STATUS STARTED COMPLETED ERRORS WARNINGS CREATED SELECTOR
mysql-backup-20210916172100 mysql-backup Completed 2021-09-16 17:21:00 +0800 CST 2021-09-16 17:21:22 +0800 CST 0 0 2021-09-16 17:21:00 +0800 CST <none>
➜ ~ velero restore describe mysql-backup-20210916172100
Name: mysql-backup-20210916172100
Namespace: velero
Labels: <none>
Annotations: <none>
Phase: Completed
Total items to be restored: 10
Items restored: 10
Started: 2021-09-16 17:21:00 +0800 CST
Completed: 2021-09-16 17:21:22 +0800 CST
Backup: mysql-backup
Namespaces:
Included: all namespaces found in the backup
Excluded: <none>
Resources:
Included: *
Excluded: nodes, events, events.events.k8s.io, backups.velero.io, restores.velero.io, resticrepositories.velero.io
Cluster-scoped: auto
Namespace mappings: <none>
Label selector: <none>
Restore PVs: auto
Restic Restores (specify --details for more information):
Completed: 1
Preserve Service NodePorts: auto
還原完成後我們再去查看之前我們的 kube-demo 命名空間下面的應用數據是否正確:
➜ ~ kubectl get ns kube-demo
NAME STATUS AGE
kube-demo Active 3m29s
➜ ~ kubectl get pods -n kube-demo
NAME READY STATUS RESTARTS AGE
mysql-c57f676dd-gw5pf 1/1 Running 0 6m28s
➜ ~ kubectl exec -it -n kube-demo mysql-c57f676dd-gw5pf -- /bin/bash
root@mysql-c57f676dd-gw5pf:/# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 42
Server version: 5.6.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+---------------------+
| Database |
+---------------------+
| information_schema |
| #mysql50#lost+found |
| mysql |
| performance_schema |
| velero |
+---------------------+
5 rows in set (0.00 sec)
mysql>
可以看到我們的創建的 velero
數據庫依然存在,證明已經完全恢復了。
只要我們將每個 velero 實例指向相同的對象存儲,velero 就能將資源從一個羣集遷移到另一個羣集。此外還支持定時備份,觸發備份 Hooks 等操作,更多資料請查閱官方文檔:https://velero.io/docs/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/VC6kVfcBCUQfG6RwM6F1QA