EKS上のPodからEFSアクセスポイントを利用するときのバックアップ・リストア方法

## はじめに

EKS上のPodからEFSをPersistentVolumeとして使用する方法の1つとして[EFS CSI Driver](https://github.com/kubernetes-sigs/aws-efs-csi-driver)が選択肢としてあります。
今回はEFSアクセスポイントを使用した際のバックアップとリストアの方法を説明します。
EKSは1.16を使用しています。


## 前準備

### EFS CSI Driver

EFS CSI Driverを以下のコマンドでデプロイします。

```console
$ kubectl apply -k "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/ecr/?ref=release-1.0"
```

次に、PersistentVolumeでEFSを使用するためにStorageClassを定義します。

```yaml:efs-sc.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
```

```console
$ kubectl apply -f efs-sc.yaml
```

### EFS

EFSアクセスポイントを以下のようにパス`/accesspoint`、ルートディレクトリ作成情報を`200:200(0777)`にします。今回はアプリケーションの実行ユーザを`200`にするためにこのような設定を入れます。
`0:0(0777)`で作成して後でinit containerでchownしてもいいですが、データ量が大きいと処理に時間がかかるのでEFS側で設定しておくことをお勧めします。

![スクリーンショット 2021-02-21 0.12.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/bcdad945-a226-1a50-aaa5-663d30cfafde.png)


### アプリケーション

今回はデータのバックアップ・リストアを確かめるためなのでCentosのDockerイメージを使用します。
SecurityContextで実行ユーザを`200`にしています。

```yaml:efs-app.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-sc
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-60ab6340::fsap-047db38c5e2c3486c
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: efs-app
spec:
  containers:
  - name: app
    image: centos
    command: ["/bin/sh"]
    args: ["-c", "while true; do sleep 5; done"]
    volumeMounts:
    - name: efs-volume
      mountPath: /mnt
  securityContext:
    runAsUser: 200
    runAsGroup: 200
    fsGroup: 200
  volumes:
  - name: efs-volume
    persistentVolumeClaim:
      claimName: efs-claim
```

```console
$ kubectl apply -f efs-app.yaml
```

ファイルとディレクトリを作成しておきます。

```console
$ kubectl exec -it efs-app /bin/bash
$ mkdir /mnt/test
$ touch /mnt/test.txt
$ ls -l /mnt
total 8
drwxr-xr-x 2 200 200 6144 Feb 20 15:42 test
-rw-r--r-- 1 200 200    0 Feb 20 15:41 test.txt
```

## バックアップ

AWS Backupでファイルシステムのバックアップを行います。
今回はオンデマンドバックアップを作成します。

![スクリーンショット 2021-02-21 0.28.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/56fc24bf-ad00-8def-6b7a-79d282228b94.png)

バックアップが完了したらコンテナ内のディレクトリとファイルを削除します。

```console
$ kubectl exec -it efs-app /bin/bash
$ rm -r /mnt/test
$ rm /mnt/test.txt
$ ls -l /mnt
total 0
```

## リストア

AWS Backupでデータの復元をしていきます。

![スクリーンショット 2021-02-21 0.48.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/b0bfa52a-3b1c-6c53-ddad-f3376678a6aa.png)

「項目レベルの復元」を選択して復元を実行します。実行までに10分かかります。

![スクリーンショット 2021-02-21 0.51.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/a3f9f1d7-05b6-4e05-6441-7471939b2078.png)

復元されたデータはファイルシステムの**ルートディレクトリ直下に格納されます**。
そのためルートディレクトリにアクセス可能なPodを別に立ててリストアを行います。

PersistentVolumeの`spec.csi.volumeHandle`には今回アクセスポイントを指定していません。

```yaml:efs-app-restore.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pv-restore
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-sc
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-60ab6340
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim-restore
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: efs-app-restore
spec:
  containers:
  - name: app
    image: centos
    command: ["/bin/sh"]
    args: ["-c", "while true; do sleep 5; done"]
    volumeMounts:
    - name: efs-volume
      mountPath: /mnt-restore
  securityContext:
    runAsUser: 200
    runAsGroup: 200
  volumes:
  - name: efs-volume
    persistentVolumeClaim:
      claimName: efs-claim-restore
```

```console
$ kubectl apply -f efs-app-restore.yaml
```

リストア用コンテナに入りバックアップデータをアプリ用コンテナのマウント先にコピーします。
実行ユーザをアプリケーション同様`200`にしているために後でchownをする必要がなくなります。データ量が大きいときにchownの処理も入れると時間がかかるので注意しましょう。

```console
$ kubectl exec -it efs-app-restore /bin/bash
$ ls -l /mnt-restore/
total 8
drwxrwxrwx 2  200  200 6144 Feb 20 15:46 accesspoint
drwxr-xr-x 4 root root 6144 Feb 20 15:03 aws-backup-restore_2021-02-20T16-05-41-036Z
$ ls -l /mnt-restore/accesspoint/
total 0
$ ls -l /mnt-restore/aws-backup-restore_2021-02-20T16-05-41-036Z/accesspoint/
total 8
drwxr-xr-x 2 200 200 6144 Feb 20 15:42 test
-rw-r--r-- 1 200 200    0 Feb 20 15:41 test.txt
$ cp -R /mnt-restore/aws-backup-restore_2021-02-20T16-05-41-036Z/accesspoint/* /mnt-restore/accesspoint/
$ ls -l /mnt-restore/accesspoint/
total 8
drwxr-xr-x 2 200 200 6144 Feb 20 16:15 test
-rw-r--r-- 1 200 200    0 Feb 20 16:15 test.txt
```

アプリコンテナでもリストアされているか確認をします。

```console
$ kubectl exec -it efs-app -- ls -l /mnt
total 8
drwxr-xr-x 2 200 200 6144 Feb 20 16:15 test
-rw-r--r-- 1 200 200    0 Feb 20 16:15 test.txt
```

## まとめ

EKS上のPodからEFSアクセスポイントを使用する際のデータのバックアップとリストアの方法を説明しました。
AWS Backupでは復元データはルートディレクトリ直下に配置されるので、それを考慮してリストアを実行する必要があります。

## 参考

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/efs-csi.html
https://github.com/kubernetes-sigs/aws-efs-csi-driver/blob/master/examples/kubernetes/access_points/specs/example.yaml