Amazon Web Services ブログ

Amazon EFS CSI dynamic provisioningの御紹介

このブログはMike Stefaniak (Sr. Product Manager for Amazon EKS)、Marco Ballerini (DevOps Architect)によって執筆された内容を日本語化した物です。原文はこちらを参照して下さい。

企業がワークロードの多くをKubernetesに移行するにつれ、データをコンテナの外で共有したり持続させたりする方法を必要とするアプリケーションを導入するケースが増えています。Kubernetesは、Container Storage Interface(CSI)を介してブロックおよびファイルストレージシステムをコンテナ化されたワークロードに提供することで、このニーズに対応しています。Amazon Elastic Kubernetes Service (Amazon EKS) は現在、CSIを介して、Amazon Elastic File System (Amazon EFS)、Amazon Elastic Block Store (Amazon EBS)、およびAmazon FSx for Lustreの3つのストレージオプションをサポートしています。この記事では、お客様に人気のストレージオプションであるAmazon EFSに焦点を当てます。Amazon EFSは、同じAWSリージョン内の異なるアベイラビリティーゾーンからアクセス可能な共有ファイルシステムを提供し、高い耐久性を持つように設計されています。これは、Amazon EKSクラスタが複数のアベイラビリティーゾーンにまたがっている場合、またはコンテナ化されたアプリケーションが設定ファイル、静的資産、または複数のポッドで共有される何かを保持するために永続的なストレージを必要とする場合に特に役立ちます。

Kubernetesは、同じクラスタ内のストレージ関連の業務を論理的に分離します。PersistentVolumes (PV)は、管理者によってプロビジョニングされた、又はCSIドライバを使って動的にプロビジョニングされた、クラスタ内のストレージの単位です。PersistentVolumeClaim (PVC)は、通常、ユーザーまたはアプリケーションによって作成され、ストレージ領域を必要とする時にPVを要求します。これはポッドと似ており、一般的にはアプリケーションのライフサイクルに沿って行われます。

これまで、Amazon EFS CSIドライバを使用するKubernetes管理者は、ユーザーがPVCを作成する前に、PV(および必要なAmazon EFSリソース)を静的にプロビジョニングする必要がありました。今回、Amazon EFS CSIドライバーの最新バージョンにダイナミックプロビジョニングが搭載されたことをお知らせします。ダイナミック・プロビジョニングは、EFSアクセスポイント(EFSファイルシステムへのアプリケーション固有のエントリーポイント)を使用して、単一のファイルシステムで最大120のPVを自動的にプロビジョニングすることができます。

このブログの残りの部分では、新しくリリースされたAmazon EFS CSIドライバーのバージョン1.2を使用して、ダイナミック・プロビジョニングを開始する方法を紹介します。

セットアップ

ドライバは、EFS アクセスポイントを作成および管理するために IAM 権限を必要とします。IAM roles for service accounts (IRSA)機能を使用することで、ノードのIAMロールに拡張パーミッションを提供する事なく、ノード上のポッドがAWS APIを呼び出すことができるようになります。

この記事では、既存のEFSファイルシステム、および関連するOIDCプロバイダーを持つEKSクラスターがすでにあることを前提としています。この設定方法の詳細な手順は、公式ドキュメントに記載されています。また、クラスタにアクセスするためにeksctlkubectlがインストールされ、設定されていることを前提としています。なお、EFS CSIのダイナミックプロビジョニングを使用するには、Kubernetesのバージョン1.17以上が必要です。

1. まず、ドライバーがEFSアクセスポイントを管理するためのIAMロールを作成する必要があります。<example values> (< >を含む)は必ず自分の値に置き換えてください。

## IAMポリシードキュメントのダウンロード 
curl -S https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/v1.2.0/docs/iam-policy-example.json -o iam-policy.json

## IAMポリシーの作成 
aws iam create-policy \
--policy-name EFSCSIControllerIAMPolicy \
--policy-document file://iam-policy.json

## Kubernetesサービスアカウントの作成 
eksctl create iamserviceaccount \
--cluster=<cluster> \
--region <AWS Region> \
--namespace=kube-system \
--name=efs-csi-controller-sa \
--override-existing-serviceaccounts \
--attach-policy-arn=arn:aws:iam::<AWS account ID>:policy/EFSCSIControllerIAMPolicy \
--approve

このステップは、AWSマネジメントコンソールやAWS CLIを使っても実現できます。ステップバイステップのガイドは、公式ドキュメントを参照してください。

2a. Helmチャートを使用して、Amazon EFS CSIドライバをインストールします。御使用のAWSリージョンに対応するAmazon ECRリポジトリのURLプレフィックスは、EKSのドキュメントで見つけることができます。

helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver
helm repo update
helm upgrade -i aws-efs-csi-driver aws-efs-csi-driver/aws-efs-csi-driver \
  --namespace kube-system \
  --set image.repository=602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/aws-efs-csi-driver \
  --set serviceAccount.controller.create=false \
  --set serviceAccount.controller.name=efs-csi-controller-sa

2b: 別の方法として、以下のマニフェストを使用してEFS CSIドライバーをインストールすることもできます。

kubectl kustomize "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.2" > driver.yaml
vim driver.yaml # delete the service account created in step 1.
kubectl apply -f driver.yaml

TIP: EFSファイルシステムに関連付けられたセキュリティグループのポート2049で、EKSクラスターに割り当てられたCIDRからのトラフィックを許可していることを確認してください。

テスト

1. ダイナミックプロビジョニングをテストするために、EFS用のストレージクラスを作成してみましょう。ストレージクラスの定義には、EFSファイルシステムIDを必ず追加してください。

パラメーターや設定オプションの全リストは、GitHub pageの公式ページでご確認ください。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: <EFS file system ID>
  directoryPerms: "700"

2. 自動プロビジョニングをテストするために、PersistentVolumeClaimを使用するポッドをデプロイします。EFSのサービスの特性上、容量を明示的にプロビジョニングする必要がないため、Persistent Volume Claimのストレージ容量の値は実際には使用されないことに注意してください。ただし、ストレージ容量はKubernetesの必須フィールドなので、値を指定する必要があります。容量には任意の有効な値を使用できます。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 20Gi
  ---
  apiVersion: v1
  kind: Pod
  metadata:
    name: efs-example
  spec:
    containers:
      - name: app
        image: centos
        command: ["/bin/sh"]
        args: ["-c", "while true; do echo $(date -u) >> /example/out.txt; sleep 5; done"]
        volumeMounts:
          - name: persistent-storage
            mountPath: /example
    volumes:
      - name: persistent-storage
        persistentVolumeClaim:
          claimName: efs-claim

3. 数秒後、コントローラーが変更を認識する様子が見られます(読みやすさを考慮して編集しています):

➜ kubectl logs efs-csi-controller-55ff98d4-wt54t -n kube-system -c csi-provisioner --tail 10
[cut]
	1 controller.go:737] successfully created PV pvc-4df6c960-a9e6-4626-bcff-62d6c4d7fe13 for PVC efs-claim and csi volume name fs-1eff1845::fsap-04c355c91d3af1544

4. この時点で、PersistentVolume は自動的に作成され、PersistentVolumeClaim に「バインド」されるはずです:

➜ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-0922e0e2-2ea5-4b70-82e9-f45c4866dc24 20Gi RWX Delete Bound default/efs-claim efs-sc 3s

➜ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
efs-claim Bound pvc-0922e0e2-2ea5-4b70-82e9-f45c4866dc24 20Gi RWX efs-sc 8s

5. さらに検証するために、EKSワーカーノードを終了させ、ポッドが再スケジュールされるのを待ってみましょう:

➜ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
efs-example 1/1 Running 0 30s 172.31.81.36 ip-172-31-89-143.eu-central-1.compute.internal➜ kubectl exec efs-example -- bash -c "cat example/out.txt"Tue Mar 2 09:31:15 UTC 2021Tue Mar 2 09:31:20 UTC 2021Tue Mar 2 09:31:25 UTC 2021Tue Mar 2 09:31:30 UTC 2021Tue Mar 2 09:31:35 UTC 2021

➜ k get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
efs-example 1/1 Running 0 15s 172.31.56.18 ip-172-31-49-60.eu-central-1.compute.internal

➜ kubectl exec efs-example -- bash -c "cat example/out.txt"
Tue Mar 2 09:31:15 UTC 2021
Tue Mar 2 09:31:20 UTC 2021
Tue Mar 2 09:31:25 UTC 2021
Tue Mar 2 09:31:30 UTC 2021
Tue Mar 2 09:31:35 UTC 2021
Tue Mar 2 09:31:40 UTC 2021
[cut]
	Tue Mar 2 09:37:23 UTC 2021

StatefulSets

お客様とお話ししていて気付いたことは、KubernetesのStatefulSetsとストレージの自動プロビジョニングの関係について混乱されている方がいらっしゃるということです。ただ実際には、StatefulSetsにはストレージの自動プロビジョニングに対する難しい要求事項はありません。実際、今回のリリース以前には、StatefulSetsが使用するパーシステントボリュームを事前に作成するだけで、EKSやEFS CSIと一緒にStatefulSetsを使用することができました。今回御紹介している機能では、永続的なボリュームを事前に作成する必要がなくなり、StatefulSetsを使用する際のユーザーエクスペリエンスが向上します。YAML 定義で StatefulSets を宣言すると、EFS CSI ドライバーが自動的にボリュームをプロビジョニングします。

AWS Fargate

ダイナミックプロビジョニングは Fargate ポッドではまだサポートされていません。EFS CSIドライバには、ダイナミックプロビジョニングのためにEFSへの呼び出しを行うコントローラと、ポッドにボリュームをマウントするノードエージェントの2つのコンポーネントが含まれるようになりました。Amazon EKS on AWS Fargateでは、このノードエージェントが組み込まれています。EFS CSIヘルムチャートをよく見ると、ノードエージェントのインストール対象としてFargateが除外されているのがわかります。一方、コントローラは内蔵されていないため、別のデプロイメントとして実行する必要があります。コントローラーのバージョン1.2は、Fargate上で動作するノードエージェントv1.1と互換性がありません。さらに、コントローラはIMDSへのアクセスを必要としますが、これはFargate上で動作するポッドと互換性がありません。現在、EFS CSIノードエージェントのアップデートをFargateフリート全体に展開しているところです。これにより、コントローラがEC2ベースのワーカーノード上で動作している限り、ダイナミックプロビジョニングが可能になります。このGitHub issueを購読することで、進捗状況を知ることができます。さらに、コントローラをFargateポッドとして実行できるように、コントローラのIMDS要件の回避策を検討しています。

まとめ

Amazon Elastic File Systemは、ギガバイトからペタバイトのデータまで自動的に拡張でき、保存時および転送時のデータの自動暗号化をサポートし、AWSバックアップとのシームレスな統合を実現します。今回、KubernetesにEFS PersistentVolumesのダイナミックプロビジョニングが導入されたことで、ストレージを動的にプロビジョニングすることが可能になり、最新のコンテナ型アプリケーションとの連携が強化されました。EFSアクセスポイントをCSIドライバーと組み合わせて使用することで、ユーザー毎のアクセス管理を強化し、同じEFSファイルシステム内のストレージスペース間の論理的な分離を、すぐに実現することができます。詳細については、GitHubのオープンソースEFS CSIドライバープロジェクトをご覧いただくか、Amazon EKSのドキュメントをご参照ください。