Kubernetesクラスタ全体のバックアップを取るVeleroについて調べる

# はじめに

Kubernetesにはいろいろなバックアップ方法があります。もともと、構成についてはクラスタが消えてもyamlファイルから再現できる場合が多いと思います。データの場合はクラウド上にあれば、クラウドのサービスを使うことでバックアップを取ることができます。Veleroはデータも含めてクラスタ全体のバックアップを取ることができます。この記事では、Veleroでどんな機能があるか調べました。

https://github.com/vmware-tanzu/velero

# Veleroの機能の概要

今回はVelero v1.9について記述します。
以下、機能の概要です。

- PVのデータを含めたKubernetesクラスタ全体のバックアップ＆レストアを行うことができる。
- 定期的にバックアップを行うことができる。
突然の災害に備え、日毎、月毎などで定期的にバックアップを取ることができる。
- バックアップ、レストア時に任意のコマンドを挟むことができる。
バックアップ、レストアそれぞれについて、前後でコンテナを指定し、コマンドを実行することができる。
バックアップ前にPODへのアクセスを停止する処理を挟むなどができる。
- 作成したバックアップを使用して別クラスターへレストアすることができる。
- 組み込みResticを使うことで幅広いボリュームタイプをサポートすることができる。
組み込みResticを有効にすることで、emptyDirやNFSなどのボリュームタイプのバックアップを取ることができる。

https://github.com/restic/restic

# サポートされているクラウド、プラグイン

クラウド毎に、Kubernetesのサービス、バックアップを置くストレージサービスは異なります。そのため、対応しているプラグインが必要になります。サポートされているクラウドは大きく分けて、AWS、GCP、Azureとそれらのストレージの互換性を持つクラウドになります。
以下にドキュメントにて挙げられているクラウドを記載します。

https://velero.io/docs/v1.9/supported-providers/

- AWS
- GCP
- Azure
- VMware vSphere
- CSI（Velero plugin）
- AlibabaCloud
- DigitalOcean
- Hewlett Packard
- OpenEBS
- OpenStack
- Portworx
- Storj
- IBM Cloud
- Oracle Cloud
- Minio
- DigitalOcean
- NooBaa
- Tencent Cloud
- Ceph RADOS v12.2.7
- Quobyte
- Cloudian HyperStore

# 制限事項、前提条件

ドキュメントにて挙げられている制限事項、前提条件についてまとめます。

- Kubernetesバージョンは1.16以上が必要。
- `kubectl`のインストールが必要。
- `hostPath`を使ったPVをサポートしていない。`local`は使うことができる。
- ストレージ内では共通の暗号化キーを使用する。
- PVCでは増分バックアップだが、それ以外の`emptyDir`ではPOD再作成時などに完全バックアップを取る。
- Resticを使う場合、PODにマウントされたPVのみバックアップを取ることができる。マウントされていないPVのバックアップを取るには、一時的なマウントなどの対策が必要となる。
- バックアップが作成されたクラスタよりもKubernetesバージョンの低いクラスタへレストアできない。
- クラスタによってVeleroの使うCPU、メモリのカスタマイズが必要になる場合がある。
デフォルトでは以下のページに記載されています。
https://velero.io/docs/v1.9/customize-installation/
デフォルトでは、リソース数が1000、合計サイズが100GBまでの想定とのこと。

※参考

https://velero.io/docs/v1.9/basic-install/#prerequisites
https://velero.io/docs/v1.9/restic/#limitations
https://velero.io/docs/v1.9/migration-case/

# v1.9→v1.10.0-rc.1の変更点

Kubernetes自体のバージョンアップ頻度が多く、Veleroもよく更新されます。この記事を書いた11/23時点ではv1.10はプレリリースでした。しかし、更新頻度を考えるとすぐに正式リリースが出る可能性があります。そこで、プレリリースであるv1.10.0-rc.1の変更点について記載します。

- Kubernetes v1.25にてテストされている。
Velero v1.9ではKubernetes v1.24までテストされているが、Velero v1.10ではKubernetes v1.25までテストされている。
- 複数のストレージの資格情報を持つことができる
クラウドが異なる複数のストレージを持つ場合でも、同時にバックアップを取ることができる。
- Kopiaが組み込まれた。それに伴いドキュメントやコマンドが大きく変わっている。

https://github.com/kopia/kopia

※参考

https://github.com/vmware-tanzu/velero/releases
https://github.com/vmware-tanzu/velero#velero-compatabilty-matrix

# minikubeとS3でバックアップ＆レストアをしてみる

最後に簡単にバックアップ、レストアを実際にやってみます。EC2のAmazon Linux2を使います。
まず、minikube環境を構築します。

・Dockerのインストール

```bash
DOCKER="docker-20.10.17-1.amzn2.0.1"
sudo yum install -y ${DOCKER}
sudo systemctl start docker
sudo usermod -aG docker ec2-user
```

・minikubeのインストール
再ログイン後、以下のコマンドを実行します。

```bash
K8S_VERSION="v1.25.3"
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
minikube start \
--kubernetes-version=${K8S_VERSION} \
--driver=docker
echo 'alias k="minikube kubectl --"' >> ~/.bash_profile
```

・Helmのインストール
今回は、Helmを使ってVeleroをインストールします。そのため、Helmをインストールします。

```bash
HELM_VERSION='v3.10.1'
curl "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" -o helm.tar.gz
tar -zxvf helm.tar.gz
sudo mv linux-amd64/helm /usr/bin
```

次にVelero Serverをインストールします。

```bash
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm install velero vmware-tanzu/velero \
--namespace velero \
--create-namespace \
--set-file credentials.secretContents.cloud=$HOME/.aws/credentials \ #S3の資格情報
-f velero-values.yaml
```

```yaml:velero-values.yaml
configuration:
  provider: aws
  backupStorageLocation:
    name: default-test-s3
    bucket: <bucket name>
    default: true
    config:
      region: ap-northeast-1
  volumeSnapshotLocation:
    name: default-test-s3
    config:
      region: ap-northeast-1
  defaultVolumesToRestic: true #annotationを付けずにバックアップするため

image:
  tag: v1.9.3

initContainers:
- name: velero-plugin-for-aws
  image: velero/velero-plugin-for-aws:v1.5.2
  imagePullPolicy: IfNotPresent
  volumeMounts:
  - mountPath: /target
    name: plugins

deployRestic: true #Resticの有効化

resources: #VeleroのDeploymentのリソース
  requests:
    cpu: 500m
    memory: 128Mi
  limits:
    cpu: 1000m
    memory: 512Mi

restic: #ResticのDaemonSetのリソース。テスト用のEC2のためデフォルトより小さくした。
  resources:
    requests:
      cpu: 100m
      memory: 300Mi
    limits:
      cpu: 500m
      memory: 500Mi
```

```text:$HOME/.aws/credentials
[default]
aws_access_key_id=<access key>
aws_secret_access_key=<secret key>
```

Velero Clientもインストールします。

```bash
VELERO_VERSION="v1.9.3"
wget https://github.com/vmware-tanzu/velero/releases/download/${VELERO_VERSION}/velero-${VELERO_VERSION}-linux-amd64.tar.gz
tar -xvf velero-${VELERO_VERSION}-linux-amd64.tar.gz
sudo mv velero-${VELERO_VERSION}-linux-amd64/velero /usr/local/bin/
```

バックアップを取る場所が登録されているか確認します。

```bash
$ velero backup-location get
NAME              PROVIDER   BUCKET/PREFIX    PHASE       LAST VALIDATED                  ACCESS MODE   DEFAULT
default-test-s3   aws        <bucket name>    Available   2022-11-23 14:37:21 +0000 UTC   ReadWrite     true
```

バックアップ対象となるPOD、PVを作成し、テスト用ファイルを作成します。
余談ですが、minikubeのaddon「storage-provisioner」はhostPathを使うためバックアップできません。

```bash
$ sudo docker exec minikube mkdir /mydata
$ k apply -f test-pod.yaml
persistentvolume/mypv created
persistentvolumeclaim/myclaim created
pod/mynginx created
$ k get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS    REASON   AGE
mypv   1Gi        RWO            Delete           Bound    default/myclaim   local-storage            12s
$ k exec mynginx -- touch /mydata/test.txt
```

```yaml:test-pod.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv
  labels:
    app: mypv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mydata
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - minikube
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
  storageClassName: local-storage
  selector:
    matchLabels:
      app: mypv
---
apiVersion: v1
kind: Pod
metadata:
  name: mynginx
  labels:
    app: nginx
spec:
  containers:
  - image: nginx
    name: mynginx
    volumeMounts:
    - mountPath: /mydata
      name: data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: myclaim
```

それではバックアップを取ってみます。

```bash
$ velero backup create nginx-backup --selector app=nginx
Backup request "nginx-backup" submitted successfully.
Run `velero backup describe nginx-backup` or `velero backup logs nginx-backup` for more details.
$ velero backup get #バックアップが取れているかの確認
NAME           STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
nginx-backup   Completed   0        0          2022-11-23 14:44:27 +0000 UTC   29d       default-test-s3    app=nginx
```

実際にS3にあるかAWSコンソールから確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1474054/953de599-de65-364d-a2e5-ae4874d580a0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1474054/942078d0-4047-705e-dccc-956ccb6d4ff4.png)

バックアップファイルとResticの設定ファイルが格納されていました。
PODを削除し、レストアできるか確認します。

```bash
$ k delete -f test-pod.yaml
persistentvolume "mypv" deleted
persistentvolumeclaim "myclaim" deleted
pod "mynginx" deleted
$ sudo docker exec minikube rm /mydata/test.txt #レストアで復元できるか確認するためローカルのファイルは削除しました。
$ velero restore create --from-backup nginx-backup
Restore request "nginx-backup-20221123145107" submitted successfully.
Run `velero restore describe nginx-backup-20221123145107` or `velero restore logs nginx-backup-20221123145107` for more details.
$ velero restore get #ずっと待ってもSTATUSがInProgressのままでした。PODがPVがないために起動していませんでした。
NAME                          BACKUP         STATUS       STARTED                         COMPLETED   ERRORS   WARNINGS   CREATED                         SELECTOR
nginx-backup-20221123145107   nginx-backup   InProgress   2022-11-23 14:51:07 +0000 UTC   <nil>       0        0          2022-11-23 14:51:07 +0000 UTC   <none>
$ k apply -f test-pod.yaml #PVとPVCを作成してPODが起動できるようにしました。
persistentvolume/mypv created
persistentvolumeclaim/myclaim unchanged
pod/mynginx configured
$ velero restore get #レストアが完了しているかを確認
NAME                          BACKUP         STATUS      STARTED                         COMPLETED                       ERRORS   WARNINGS   CREATED                         SELECTOR
nginx-backup-20221123145107   nginx-backup   Completed   2022-11-23 14:51:07 +0000 UTC   2022-11-23 14:52:02 +0000 UTC   0        0          2022-11-23 14:51:07 +0000 UTC   <none>
$ k exec mynginx -- ls /mydata/test.txt #ファイルが復元されているか確認
Defaulted container "mynginx" out of: mynginx, restic-wait (init)
/mydata/test.txt
```

※参考

https://tellesnobrega.github.io/velero-demo/
https://qiita.com/ysakashita/items/3a0b2ad9ac37e2ce315a

# おわりに

今回は、Kubernetesでバックアップを行う方法を調べました。日々業務で触れることに対して、振り返りの時間が足りないと感じます。
これからも勉強していきます。