CSI Driver for Amazon EFS が EKS アドオンとして利用可能になったので試してみた

2023/08 に CSI Driver for Amazon EFS を EKS アドオンとして利用可能になりました。

これまでは kubernetes-sigs/aws-efs-csi-driver 記載の手順に従って manifest ファイル等を用意して手動インストールする必要がありましたが、今後はアドオンを活用してより簡単にインストールやアップデート可能になります。

セットアップしてみた

今回は eksctl を使って試してみました。

eksctl version
0.158.0

まず、EKS クラスターを作成します。

eksctl create cluster \
  --name test-cluster \
  --version 1.24 \
  --vpc-cidr 10.0.0.0/16 \
  --with-oidc \
  --node-type t3.medium \
  --nodes 2 \
  --nodes-min 1 \
  --nodes-max 2

AmazonEFSCSIDriverPolicy という AWS 管理の IAM ポリシーがあるので、こちらの権限を付与しつつ Service Account に紐づけた IAM ロールを作成します。

eksctl create iamserviceaccount \
  --name efs-csi-controller-sa \
  --namespace kube-system \
  --cluster test-cluster \
  --role-name AmazonEKS_EFS_CSI_DriverRole \
  --role-only \
  --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEFSCSIDriverPolicy \
  --approve

今回は EKS 1.24 を利用しているので、対応しているアドオンのバージョンを調べてみました。

eksctl utils describe-addon-versions --kubernetes-version 1.24 --name aws-efs-csi-driver | grep AddonVersion
    "AddonVersions": [
        "AddonVersion": "v1.6.0-eksbuild.1",
        "AddonVersion": "v1.5.9-eksbuild.1",
        "AddonVersion": "v1.5.8-eksbuild.1",

aws-efs-csi-driver をアドオンとして追加します。バージョンは一番新しい v1.6.0-eksbuild.1 とします。

eksctl create addon \
  --cluster test-cluster \
  --name aws-efs-csi-driver \
  --version v1.6.0-eksbuild.1 \
  --service-account-role-arn arn:aws:iam::12345678912:role/AmazonEKS_EFS_CSI_DriverRole \
  --force

deployment(efs-csi-controller) と daemonset(efs-csi-node) がそれぞれ作成されます。

kubectl get deployment -n kube-system
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
coredns              2/2     2            2           4h19m
efs-csi-controller   2/2     2            2           2m16s
kubectl get daemonset -n kube-system
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
aws-node       2         2         2       2            2           <none>                   4h19m
efs-csi-node   2         2         2       2            2           kubernetes.io/os=linux   2m27s
kube-proxy     2         2         2       2            2           <none>                   4h19m

EFS は CloudFormation でさくっと作りました。

AWSTemplateFormatVersion: "2010-09-09"
Description: This template creates an Amazon EFS file system
Parameters:
  VolumeName:
    Description: The name to be used for the EFS volume
    Type: String
    MinLength: "1"
    Default: myEFSvolume
  VPC:
    Description: VPC Id to create EFS volume
    Type: String
  Subnet1a:
    Description: Subnet Id in ap-northeast-1a
    Type: String
  Subnet1c:
    Description: Subnet Id in ap-northeast-1c
    Type: String
  Subnet1d:
    Description: Subnet Id in ap-northeast-1d
    Type: String
  VPCCIDR:
    Description: CIDR of VPC
    Type: String
    Default: 10.0.0.0/16
Resources:
  MountTargetSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId:
        Ref: VPC
      GroupDescription: Security group for mount target
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 2049
          ToPort: 2049
          CidrIp: !Ref VPCCIDR
  FileSystem:
    Type: AWS::EFS::FileSystem
    Properties:
      PerformanceMode: generalPurpose
      FileSystemTags:
        - Key: Name
          Value:
            Ref: VolumeName
  MountTarget1a:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId:
        Ref: FileSystem
      SubnetId: !Ref Subnet1a
      SecurityGroups:
        - Ref: MountTargetSecurityGroup
  MountTarget1c:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId:
        Ref: FileSystem
      SubnetId: !Ref Subnet1c
      SecurityGroups:
        - Ref: MountTargetSecurityGroup
  MountTarget1d:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId:
        Ref: FileSystem
      SubnetId: !Ref Subnet1d
      SecurityGroups:
        - Ref: MountTargetSecurityGroup
Outputs:
  FileSystemID:
    Description: File system ID
    Value:
      Ref: FileSystem

EFS を CLI で作成する場合は、こちらを参考にすると良いと思います。

動作確認

kubernetes-sigs/aws-efs-csi-driver でサンプルとして紹介されている manifest ファイルを利用して動作確認してみます。
クラスターを作成した状態では EBS を使うための StorageClass のみ存在します。

kubectl get sc
NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  4h29m

ここで下記マニフェストファイルを適用して、 StorageClass を追加します。

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

examples/kubernetes/static_provisioning/specs/storageclass.yaml に紹介されている manifest ファイルだと、apiVersion: v1と記載されています。
しかし、 Kubernetes 1.22 でこの API は廃止されているので、apiVersion: storage.k8s.io/v1 に修正して適用します。

kubectl apply -f storageclass.yaml
storageclass.storage.k8s.io/efs-sc created

無事ストレージクラスが追加されました。

kubectl get sc
NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
efs-sc          efs.csi.aws.com         Delete          Immediate              false                  3s
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  4h30m

PersistentVolume (PV) を作成します。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  storageClassName: efs-sc
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: efs.csi.aws.com
    volumeHandle: [FileSystemId]

この際、spec.csi.volumeHandle を EFS の ID に書き換えます。

kubectl apply -f pv.yaml
persistentvolume/efs-pv created

Available 状態で PV が作成されます。

kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
efs-pv   5Gi        RWO            Retain           Available           efs-sc                  24s

次に PersistentVolumeClaims(PVC) を作成します。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Gi
kubectl apply -f claim.yaml
persistentvolumeclaim/efs-claim created

PV の STATUS が Bound に変わります。

kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
efs-pv   5Gi        RWO            Retain           Bound    default/efs-claim   efs-sc                  2m22s

PVC の STATUS も同様です。

kubectl get pvc
NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
efs-claim   Bound    efs-pv   5Gi        RWO            efs-sc         4s

最後に pod を作成します。
この Pod では 5 秒ごとに /data/out.txtdata -u の出力を書き込むコンテナが定義されています。
pod を作成する際に、作成済みの PVC を指定することで EFS に書き込めるようになります。

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.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: efs-claim
kubectl apply -f pod.yaml

無事作成され、Volumes.persistent-storage を確認すると、先程作成した PVC を利用できています。

kubectl describe pod efs-app
Name:         efs-app
Namespace:    default
Priority:     0
Node:         ip-10-0-91-134.ap-northeast-1.compute.internal/10.0.91.134
Start Time:   Sun, 24 Sep 2023 20:48:51 +0900
Labels:       <none>
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Running
IP:           10.0.93.179
IPs:
  IP:  10.0.93.179
Containers:
  app:
    Container ID:  containerd://d4ff8ed835bf69946092d7b4a58ba48c8a523b137113f7399ff659f8167d1e60
    Image:         centos
    Image ID:      docker.io/library/centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/sh
    Args:
      -c
      while true; do echo $(date -u) >> /data/out.txt; sleep 5; done
    State:          Running
      Started:      Sun, 24 Sep 2023 20:49:12 +0900
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /data from persistent-storage (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-gvpwk (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  persistent-storage:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  efs-claim
    ReadOnly:   false
  kube-api-access-gvpwk:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  8m14s  default-scheduler  Successfully assigned default/efs-app to ip-10-0-91-134.ap-northeast-1.compute.internal
  Normal  Pulling    8m3s   kubelet            Pulling image "centos"
  Normal  Pulled     7m53s  kubelet            Successfully pulled image "centos" in 9.436549639s
  Normal  Created    7m53s  kubelet            Created container app
  Normal  Started    7m53s  kubelet            Started container app

下記コマンドを実行すると、/data/out.txt に書きこめていることが確認できました。

kubectl exec -ti efs-app -- tail -f /data/out.txt
Sun Sep 24 11:58:29 UTC 2023
Sun Sep 24 11:58:34 UTC 2023
Sun Sep 24 11:58:39 UTC 2023
Sun Sep 24 11:58:44 UTC 2023

まとめ

手動でドライバーの管理をするのは面倒なので、アドオンがあるなら積極的に使っていきたいです。
今は手動管理をしている場合もこれからクラスターを作る場合も、是非アドオンの利用を検討してみて下さい。