のべラボ.blog

謙虚に、臆せず、さぼらずにブログを書く

Amazon EKS で Amazon EFS CSI ドライバー を使ってみる

今回は、Amazon EKS で Amazon EFS CSI ドライバー を使って、Podから EFSボリュームにアクセスしてみます。

手順としては前回の「Amazon EKS で Amazon EBS CSI ドライバー を使ってみる 」の記事の内容と似ているところが多いので、今回の記事も内容や構成が似ていることはご容赦下さいww

ここに記述している内容は、2022 年 9 月11 日時点で動作を確認しています。

また、対象にしている Kubernetes のバージョンは 1.23 です。

今後の Update により、手順等が変更される可能性があることをご留意ください。

なお、下記のドキュメントを参考にしていますので、こちらも併せてご参照ください。

docs.aws.amazon.com

aws.amazon.com


前提と環境

今回は、東京リージョンの「 test123-cluster 」という名前の EKS クラスター (バージョンは 1.23 ) を使う前提とします。

kubectl や eksctl 、AWS CLI 、git が使用でき、対象のクラスターに接続できる Amazon Linux2 の環境で実施していきます。

記事の中で出てくる AWS アカウント ID は、12 桁すべてゼロで表記しています。


Amazon EFS CSI ドライバー用の Service Account の作成

Amazon EFS CSI ドライバーには、Amazon EFS のファイルシステムを操作する権限を付与する必要があります。

その権限を付与するため、AWS の IAM ロールと関連づいた Kubernetes の Service Account を作成します。

まず、クラスター用に IAM OpenID Connect (OIDC) プロバイダーを用意します。 (もし前に IAM ロールと関連付けた Service Account を作成したことがあるなら、すでに実施済のはずなので、その場合は不要です。)

eksctl utils associate-iam-oidc-provider --cluster test123-cluster --approve

次に、IAM ロール に付与する許可ポリシーを作成します。

ここでは、ポリシー名を AmazonEKS_EFS_CSI_Driver_Policy にしています。

curl -o iam-policy-example.json https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/docs/iam-policy-example.json

aws iam create-policy \
    --policy-name AmazonEKS_EFS_CSI_Driver_Policy \
    --policy-document file://iam-policy-example.json

ダウンロードした iam-policy-example.json にも目を通しておくと、どのようなポリシーが必要か確認できます。

そして、Service Account を作成します。

ここでは、Service Account 名を ebs-csi-controller-sa に、IAM ロール名を AmazonEKS_EBS_CSI_DriverRole にしています。

eksctl create iamserviceaccount \
    --cluster test123-cluster \
    --namespace kube-system \
    --name efs-csi-controller-sa \
    --attach-policy-arn arn:aws:iam::000000000000:policy/AmazonEKS_EFS_CSI_Driver_Policy \
    --approve \
    --region ap-northeast-1

Amazon EFS CSI ドライバー を Amazon EKS アドオンとしてインストールする

インストールではHelm も使用できますが、今回は kubectl でマニフェストを使って行います。

また、マニフェストで参照するイメージは、パブリック Amazon ECR レジストリに保存されているイメージを使う前提とします。

最初にマニフェストを取得します。

kubectl kustomize \
    "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.4" > public-ecr-driver.yaml

public-ecr-driver.yaml ファイルを編集して、次の行を削除します。 これは、Service Account は前の手順ですでに作成しているためです。 この作業は注意して下さい。ファイル内に Service Account のマニフェストが複数存在している場合、削除する対象を間違えないようにしましょう。

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-controller-sa
  namespace: kube-system
---

これでマニフェストの準備が完了したので、適用します。

kubectl apply -f public-ecr-driver.yaml

インストールを確認します。

kubectl get deploy efs-csi-controller -n kube-system

次の出力例のように、efs-csi-controller の Deployment が起動できていることを確認します。

NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
efs-csi-controller   2/2     2            2           3m1s

 EFS ファイルシステムを作成する

EFS ファイルシステムを作成するために、まずは VPC の情報を環境変数に入れておきます。

EKSクラスターの VPC の ID の取得

vpc_id=$(aws eks describe-cluster \
    --name test123-cluster \
    --query "cluster.resourcesVpcConfig.vpcId" \
    --output text)

EKSクラスターの VPC の CIDR の取得

cidr_range=$(aws ec2 describe-vpcs \
    --vpc-ids $vpc_id \
    --query "Vpcs[].CidrBlock" \
    --output text)

次に EFS ファイルシステムのマウントポイントに適用するセキュリティグループを作成します。 今回は、セキュリティグループ名を MyEfsSecurityGroup にしています。

security_group_id=$(aws ec2 create-security-group \
    --group-name MyEfsSecurityGroup \
    --description "My EFS security group" \
    --vpc-id $vpc_id \
    --output text)

作成したセキュリティグループに イングレスルールを設定します。

今回は、アクセス元がクラスターの VPC の CIDR であれば NFS トラフィックを許可するルールにします。

aws ec2 authorize-security-group-ingress \
    --group-id $security_group_id \
    --protocol tcp \
    --port 2049 \
    --cidr $cidr_range

これで EFS ファイルシステムを作成する準備ができました。

リージョンを指定して EFS ファイルシステムを作成します。

file_system_id=$(aws efs create-file-system \
    --region ap-northeast-1 \
    --performance-mode generalPurpose \
    --query 'FileSystemId' \
    --output text)

EFS ファイルシステムのマウントターゲットを作成します。

そのために、まず EKS クラスターのVPCのサブネットの ID を取得します。

aws ec2 describe-subnets \
    --filters "Name=vpc-id,Values=$vpc_id" \
    --query 'Subnets[*].{SubnetId: SubnetId,AvailabilityZone: AvailabilityZone,CidrBlock: CidrBlock}' \
    --output table

出力された表形式の内容から、EKS で EFS ファイルシステムをマウントするノードのサブネットの ID をメモしておきます。

そのサブネット ID を指定して、EFS のマウントターゲットを作成します。 次の例では、サブネット ID を subnet-0b10aaaaaaaaaaaaa と指定しています。

aws efs create-mount-target \
    --file-system-id $file_system_id \
    --subnet-id subnet-0b10aaaaaaaaaaaaa \
    --security-groups $security_group_id

 サンプルアプリケーションで確認する

では、Pod から EFS ファイルシステムにアクセスできるかをサンプルアプリケーションを使って試していきます。

まず、作成した EFS ファイルシステムの ID をメモしておきます。 これまでの手順で、$file_system_id という環境変数で参照できます。

echo $file_system_id

もしくは、AWS CLI でも確認できます。

aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text

次に、EFS の StorageClass を作成するためのマニフェストを入手します。

curl -o storageclass.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml

ダウンロードした storageclass.yaml を編集し、fileSystemId: 部分をメモしておいた ファイルシステム ID に変更します。 次の例では、ファイルシステム ID として fs-54321abc を指定してます。

fileSystemId: fs-54321abc

これで準備ができたので、StorageClassを作成します。

kubectl apply -f storageclass.yaml

Storage Class の情報を表示してみます。NAME に efs-sc 、PROVISONER に efs.csi.aws.com の Storage Class が表示されることを確認します。

kubectl get sc

次にサンプルアプリケーションを取得します。

curl -o pod.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/pod.yaml

今回は、動的に EFS のボリュームをプロビジョニングするサンプルを動かしていきます。

ダウンロードしたマニフェスト pod.yaml を適用することで、Persistent Volume、Persistent Volume Claim、それを指定するサンプルの Pod が作成されます。

kubectl apply -f pod.yaml

Persistent Volume と Persistent Volume Claim の STATUS が Bound になっていることを確認します。

kubectl get pv
kubectl get pvc

efs-app というPod の STATUS が Running になっていることを確認します。

kubectl get pod efs-app

次のコマンドを実行し、このサンプルアプリケーションの Pod のマニフェストをみてみます。

cat  pod.yaml

次のように、Persistent Volume Claim を指定し、/data というパスにボリュームをマウントしています。

そして、echo コマンドを使用し、/data/out に日時を繰り返し書き込んでいます。 

apiVersion: v1
kind: Pod
metadata:
  name: efs-app
spec:
  containers:
    - name: app
      image: centos
      command: ["/bin/sh"]
      args: ["-c", "while true; do echo $(date -u) >> /data/out; sleep 5; done"]
      volumeMounts:
        - name: persistent-storage
          mountPath: /data
  volumes:
    - name: persistent-storage
      persistentVolumeClaim:

では、この Pod が EFS ボリュームに書き込み出来ているかを確認してみましょう。

kubectl exec efs-app -- bash -c "cat data/out"

次のような表示が確認できれば OK です。

出力例

Sun Sep 11 03:15:25 UTC 2022
Sun Sep 11 03:15:30 UTC 2022
Sun Sep 11 03:15:35 UTC 2022
Sun Sep 11 03:15:40 UTC 2022
Sun Sep 11 03:15:45 UTC 2022
Sun Sep 11 03:15:50 UTC 2022
Sun Sep 11 03:15:55 UTC 2022

ここで、もう1つ、同じ EFS のマウントターゲットを使用するPod を作成してみます。 次のマニフェストを作成して、nginx.yaml として保存します。

apiVersion: v1
kind: Pod
metadata:
  name: efs-app-nginx
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - name: persistent-storage
          mountPath: /data
  volumes:
    - name: persistent-storage
      persistentVolumeClaim:
        claimName: efs-claim

この Pod を作成します。

kubectl create -f  nginx.yaml

作成した Pod のシェルに接続してみます。

kubectl exec efs-app-nginx -it  -- /bin/bash

次のコマンドを実行し、efs-app の Pod が書き込んだファイルを参照できることを確認します。

cat /data/out

出力例

Sun Sep 11 03:15:25 UTC 2022
Sun Sep 11 03:15:30 UTC 2022
Sun Sep 11 03:15:35 UTC 2022
Sun Sep 11 03:15:40 UTC 2022
Sun Sep 11 03:15:45 UTC 2022
Sun Sep 11 03:15:50 UTC 2022
Sun Sep 11 03:15:55 UTC 2022

これで EFS なので、2つのコンピューティング環境から同時にマウントしてアクセスできることが確認できました!

確認出来たら、シェルを終了します。

exit

サンプルアプリケーションを停止する場合は、次を実行します。

これで、EFS ボリュームも削除されます。( EFS ファイルシステムは削除されません)

kubectl delete po efs-app-nginx
kubectl delete -f pod.yaml

最後に

前回と今回の記事で、Amazon EKS の CSI ドライバーを使用して Amazon EBS や Amazon EFS のボリュームをプロビジョニングして Pod から使用する手順を確認しました。 AWS の公式のドキュメント の内容をベースにしていますが、少し補足しつつ、よりシンプルに確認できる手順にしたつもりです。 これがどなたかのお役に立てば嬉しいです。