Veleroをインストールした時のメモ (Minio版)

# はじめに

VeleroはKubernetes環境のバックアップを取得するために利用しています。
MinioはAWS S3互換のObject Storageです。

Veleroをインストールする手順は、Harborの記事に書いていたのですが、バージョンアップするタイミングで独立した記事にまとめました。

namespace全体をバックアップできるので、アプリケーションをnamespaceで分離している場合にはとても便利です。

# 参考資料

* [https://qiita.com/YasuhiroABE/items/8d247a3abbcf484e1c65 - Velero+MinioによるHarborの引越し作業](https://qiita.com/YasuhiroABE/items/8d247a3abbcf484e1c65)
* [https://goharbor.io/docs/main/administration/backup-restore/ - Harbor 公式ガイド](https://goharbor.io/docs/main/administration/backup-restore/)
* [https://github.com/vmware-tanzu/velero-plugin-for-aws - Github Velero AWSプラグイン](https://github.com/vmware-tanzu/velero-plugin-for-aws)

# 環境

新規にインストールしたのは次のような環境です。
 
* Kubernetes v1.25.6 (Kubespray v2.21.0) → v1.27.5 (Kubespray v2.23.0) → v1.29.5 (Kubespray v2.25.0)
* Rook/Ceph v1.9.13 (Ceph v16.2.6) → v1.14.5 (Ceph v18.2.2)
* Velero v1.10.3 → 1.11.1 → 1.12.0-rc.1 → v1.12.2 → v1.14.0
* velero-plugin-for-aws v1.6.2 → v1.7.1 → v1.8.0-rc.1 → v1.8.2 → v1.10.0
* Minio (RELEASE.2023-07-07T07-13-57Z) → (Helm 5.2.0, RELEASE.2024-03-03T17-50-39Z)
* mc (RELEASE.2023-07-07T05-25-51Z) → (RELEASE.2024-05-24T09-08-49Z)

ここではオンプレミスで導入したKubernetesとRook/CephによるPVを基盤として利用しています。

AmazonのEKS+S3やGoogleのGKE+Cloud Volumesを利用する場合にはsnapshotを積極的に使うことになると思うので、ここでのVeleroの導入手順は参考にしないでください。

# 準備作業

* veleroコマンドを/usr/local/sbin/veleroに実行権限を付けて配置 (permisison: 0755)
* credentials-velero ファイルを配置

## credentials-velero ファイルのフォーマット

Minioで作成したbucketにアクセス権を持つID,Passwordを次のような形式でファイルをあらかじめ作成しておきます。

```conf:
[default]
aws_access_key_id = ed573f5ea128ca21
aws_secret_access_key = c7c443a8fa8404abfcaab6fe09922c8f
```

# インストール手順

次のようなMakefileを作成しています。

v1.14.0をインストールする際に利用したMakefileの内容で置き換えました。kopiaを使うように変更しています。

```Makefile:Makefile

.PHONY: all
all:
        @echo reference - https://github.com/vmware-tanzu/velero-plugin-for-aws

.PHONY: install
install:
        sudo velero install \
            --provider aws \
            --plugins velero/velero-plugin-for-aws:v1.10.0 \
            --bucket my-backup-bucket \
            --secret-file ./credentials-velero \
            --use-volume-snapshots=false \
            --uploader-type kopia \
            --use-node-agent \
            --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://my-minio-svc.minio.svc.cluster.local:9000

.PHONY: delete
delete:
        @echo sudo velero uninstall
```

インストール自体は、makeコマンドを利用して実施しています。

```bash:インストール手順
$ make install
```

動作確認には、veleroのPodのログを確認します。

v1.14.0のドキュメントでは``backup-location``を別に作成する手順になっていますが、``--backup-location-config ...``で指示を与えると自動的に作成してくれます。

```bash:
$ sudo velero backup-location get
NAME      PROVIDER   BUCKET/PREFIX   PHASE       LAST VALIDATED                  ACCESS MODE   DEFAULT
default   aws        velero-bucket   Available   2024-06-21 01:49:45 +0000 UTC   ReadWrite     true
```

# Veleroによるバックアップの取得

テスト用のnamespaceを作成し、いくつかPod, PVCを配置して、バックアップが動作するか検証します。

## Namespack, pod と pvc の作成

まずnamespace **velero-test** を作成します。

```bash:namespaceの作成
$ sudo kubectl create ns velero-test
```

次にテスト用のPod, PVCを作成するYAMLファイルを準備します。

```yaml:01.pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-block-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
  storageClassName: rook-ceph-block
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-file-pvc
spec:
  accessModes: [ "ReadWriteMany" ]
  storageClassName: rook-cephfs
  resources:
    requests:
      storage: 1Gi
```

これらのPVCを利用するnginxをdeployします。

```yaml:02.deploy.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-block-storage
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-block-storage
  template:
    metadata:
      labels:
        app: nginx-block-storage
      annotations:
        backup.velero.io/backup-volumes: nginx-data-storage
    spec:
      containers:
      - name: nginx-block-storage
        image: nginx:latest
        imagePullPolicy: "Always"
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-data-storage
          mountPath: /usr/share/nginx/html
      volumes:
      - name: nginx-data-storage
        persistentVolumeClaim:
          claimName: nginx-block-pvc
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-file-storage
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-file-storage
  template:
    metadata:
      labels:
       app: nginx-file-storage
      annotations:
        backup.velero.io/backup-volumes: nginx-data-storage
    spec:
      containers:
      - name: nginx-file-storage
        image: nginx:latest
        imagePullPolicy: "Always"
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-data-storage
          mountPath: /usr/share/nginx/html
      volumes:
      - name: nginx-data-storage
        persistentVolumeClaim:
          claimName: nginx-file-pvc
```

アクセスするためのServiceオブジェクトを作成します。

```yaml:03.svc.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-block-storage
spec:
  type: LoadBalancer
  ports:
     -  port: 80
        protocol: TCP
        targetPort: 80
  selector:
    app: nginx-block-storage
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-file-storage
spec:
  type: LoadBalancer
  ports:
     -  port: 80
        protocol: TCP
        targetPort: 80
  selector:
    app: nginx-file-storage
```

これらのYAMLファイルを反映し、nginxを動作させます。

```bash:
$ alias kubectl="sudo kubectl -n velero-test"
$ sudo kubectl apply -f 01.pvc.yaml -f 02.deploy.yaml -f 03.svc.yaml
```

バックアップが機能しているか確認するために、適当なコンテンツを配置します。

```bash:
$ kubectl exec -it "$(kubectl get pod -l app=nginx-block-storage -o jsonpath={.items[0].metadata.name})" -- bash -c "echo Hello Block Nginx, $(id -un) at $(date) > /usr/share/nginx/html/index.html"
$ kubectl exec -it "$(kubectl get pod -l app=nginx-file-storage -o jsonpath={.items[0].metadata.name})" -- bash -c "echo Hello Filesystem Nginx, $(id -un) at $(date) > /usr/share/nginx/html/index.html"
```

配置されたindex.htmlの内容はLoadBalancerに割り当てられたIPを通すか、ClusterIPで動作していればnginxのPodにexecコマンドで入ってcurlコマンド経由で確認できます。

配置したindex.htmlはシンプルな内容を返します。

```bash:
$ curl 192.168.100.192
Hello Block Nginx, ubuntu at Sun Sep 10 09:09:44 AM UTC 2023
$ curl 192.168.100.193
Hello Filesystem Nginx, ubuntu at Sun Sep 10 09:09:52 AM UTC 2023
```

## Backupの取得

バックアップは次のように実行しています。

```bash:バックアップの実行
## YAMLファイルにannotationを追加したのでコメントアウト
# $ sudo kubectl -n velero-test annotate pod/nginx-block-storage-85bd475f8b-fnjf5 backup.velero.io/backup-volumes=nginx-data-storage
# $ sudo kubectl -n velero-test annotate pod/nginx-file-storage-54cd65d46c-qk8fk backup.velero.io/backup-volumes=nginx-data-storage

## namespaceを指定して
$ sudo velero backup create velero-test-$(date +%Y%m%d.%H%M%S) --include-namespaces velero-test --wait
```

### 正常なレポートを出力させるための/etc/hostsの変更

backup describeでの出力は一見正常にみえますが、--detailsオプションを指定するとResource List:の取得に失敗しています。

```text:
Resource List:  <error getting backup resource list: Get "http://my-minio-svc.minio.svc.cluster.local:9000/my-backup-bucket/backups/velero-test-20230910.1845/velero-test-20230910.1845-resource-list.json.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=8b81073d6343afcc%2F20230910%2Fminio%2Fs3%2Faws4_request&X-Amz-Date=20230910T094928Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=31aa96c9cd32e364250aa3f3866bd9fb5ae8a772f6d962417b31810de30fdfc8": dial tcp: lookup my-minio-svc.minio.svc.cluster.local on 127.0.0.53:53: server misbehaving>
```

backup logsコマンドはファイルの取得でエラーになっています。

```text:
An error occurred: Get "http://my-minio-svc.minio.svc.cluster.local:9000/my-backup-bucket/backups/velero-test-20230910.2043/velero-test-20230910.2043-logs.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=8b81073d6343afcc%2F20230910%2Fminio%2Fs3%2Faws4_request&X-Amz-Date=20230910T114625Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=d91e85847e64ec4ef3313e858c6ecff25576d51337fabe06fce2242c5e9aea3b": dial tcp: lookup my-minio-svc.minio.svc.cluster.local on 127.0.0.53:53: server misbehaving
```

これはveleroを実行している環境からmy-minio-svc.minio.svc.cluster.localに対応するIPアドレスが取得できない事が原因です。

MinioにServiceオブジェクトを追加してLANのIPからアクセスできるようにした後、/etc/hostsにmy-minio-svc.minio.svc.cluster.localに対応するIPアドレスを追加することで正常な出力を得ることができます。

```yaml:minio/my-minio-lb-svc.yamlファイル
---
apiVersion: v1
kind: Service
metadata:
  name: my-minio-lb-svc
  namespace: minio
spec:
  ports:
  - name: http
    port: 9000
    protocol: TCP
    targetPort: 9000
  selector:
    app: minio
    release: my-minio
  type: LoadBalancer
  loadBalancerIP: 192.168.100.159
```

/etc/hostsにLANからアクセスできるIPアドレスとmy-minio-svc.minio.svc.cluster.localとの対応を追加します。

```text:/etc/hostsファイルへの追加内容
192.168.100.159 my-minio-svc.minio.svc.cluster.local
```

この状態でdescribeコマンドを入力すると正しい内容が出力されます。

```bash:describeの実行結果
$ sudo velero backup get      
NAME                          STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR                                     
velero-test-20240122.024922   Completed   0        0          2024-01-22 02:52:29 +0000 UTC   29d       default   <none>           

$ sudo velero backup describe velero-test-20240122.024922 --details

Name:         velero-test-20240122.024922                              
Namespace:    velero                                                  
Labels:       velero.io/storage-location=default                      
Annotations:  velero.io/resource-timeout=10m0s                        
              velero.io/source-cluster-k8s-gitversion=v1.27.7   
              velero.io/source-cluster-k8s-major-version=1      
              velero.io/source-cluster-k8s-minor-version=27
                                                     
Phase:  Completed       

...
Resource List:                                                        
  apps/v1/Deployment:                                                  
    - velero-test/nginx-block-storage                                  
    - velero-test/nginx-file-storage                                   
  apps/v1/ReplicaSet:                                                  
    - velero-test/nginx-block-storage-856b466974                       
    - velero-test/nginx-file-storage-77ff568999                        
  discovery.k8s.io/v1/EndpointSlice:                                   
    - velero-test/nginx-block-storage-kxrt8                           
    - velero-test/nginx-file-storage-gs5mx                            
  v1/ConfigMap:                                                       
    - velero-test/kube-root-ca.crt                              
  v1/Endpoints:                                                 
    - velero-test/nginx-block-storage                
    - velero-test/nginx-file-storage  
...
  v1/Service:
    - velero-test/nginx-block-storage
    - velero-test/nginx-file-storage
  v1/ServiceAccount:
    - velero-test/default

Velero-Native Snapshots: <none included>

kopia Backups:
  Completed:
    velero-test/nginx-block-storage-856b466974-cwp75: nginx-data-storage
    velero-test/nginx-file-storage-77ff568999-8pl49: nginx-data-storage
```

``sudo velero logs``についても正常に出力されるようになりました。


## リストアの実行

namespaceを削除して同名のnamespaceにリストアする方法もありますが、ここでは別のnamespaceを指定してrestoreしていきます。

```bash:リストア処理
$ sudo velero restore create --from-backup velero-test-20230910.1835 --namespace-mappings velero-test:velero-test2 --wait
```

curlを使ってサービスにアクセスすると、PVC上にあるindex.htmlが無事に復元されていることが分かりました。


```bash:別namespaceに復元したサービスの確認結果
$ sudo kubectl -n velero-test2 get svc
NAME                  TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE
nginx-block-storage   LoadBalancer   10.233.14.151   192.168.100.194   80:32494/TCP   4m29s
nginx-file-storage    LoadBalancer   10.233.16.125   192.168.100.195   80:30019/TCP   4m29s

$ curl 192.168.100.194
Hello Block Nginx, ubuntu at Sun Sep 10 09:09:44 AM UTC 2023

$ curl 192.168.100.195
Hello Filesystem Nginx, ubuntu at Sun Sep 10 09:09:52 AM UTC 2023
```

# さいごに

Veleroは変更作業時に利用しているので、都度 delete & install を実施して問題ない状態です。

とはいえ正常に動作するか確認は必要なので、簡単なテスト用のプロジェクトを作成できるようにメモを残しました。

これを利用して他のクラスターでもveleroを準備していく予定です。

以上