S3マウント用のCSIドライバーが提供され、EKSからS3を永続ボリュームとしてマウント可能になりました! #AWSreInvent

EKSからのS3利用がかなり楽になるアップデートです。設定は若干手間がかかりますが、使い所をおさえればめっちゃ便利かと。
2023.12.05

「Kubernetesで大型のファイル扱うの面倒くさい。NodeのAMIに埋め込むとかじゃだめ?」

「やりたいことはわかるけど、運用めっちゃ面倒くさいでしょ、それ」

大型のファイルを扱う場合、ストレージの料金や運用に手間がかかるため、オブジェクトストレージ(S3)に格納することはよくあるシチュエーションだと思います。

今回のアップデートで、S3のマウントポイントがCSI(Container Storage Interface)に対応し、Kubernetesの永続ボリュームとしてS3をマウントすることができるようになりました。Kubernetesでホストするアプリケーションの活用方法が大幅に広がる意欲的なアップデートとなります。

このブログでは、アップデートの概要と、公式ドキュメントに準ずる形で、実際の設定と動作確認をした様子をお届けします。Kubernetes上で大型のファイルの扱いに悩んでいた方は、検証してみて損はないと思いますよ!

(祭) ∧ ∧
 Y  ( ゚Д゚)
 Φ[_ソ__y_l〉     S3マツリダワッショイ ナンデモオクヨ
    |_|_|
    し'´J

用法用量は守って適切にお使いくださいませ。

アップデート内容

アップデート:Mountpoint for Amazon S3 CSI driver is now generally available

With the new Mountpoint for Amazon S3 Container Storage Interface (CSI) driver, your Kubernetes applications can access S3 objects through a file system interface, achieving high aggregate throughput without any changes to your application. Built on Mountpoint for Amazon S3, the CSI driver presents an S3 bucket as a volume accessible by containers in Amazon Elastic Kubernetes Service (Amazon EKS) and self-managed Kubernetes clusters. As a result, distributed machine learning training jobs in Amazon EKS and self-managed Kubernetes clusters can read data from Amazon S3 at high throughput to accelerate training times.

以下、日本語訳。

新しいMountpoint for Amazon S3 Container Storage Interface(CSI)ドライバにより、Kubernetesアプリケーションはファイルシステムインタフェースを通じてS3オブジェクトにアクセスでき、アプリケーションに変更を加えることなく高い集約スループットを達成できます。Mountpoint for Amazon S3上に構築されたCSIドライバは、Amazon Elastic Kubernetes Service(Amazon EKS)および自己管理型Kubernetesクラスタのコンテナからアクセス可能なボリュームとしてS3バケットを提示します。その結果、Amazon EKSと自己管理型Kubernetesクラスタの分散型機械学習トレーニングジョブは、高いスループットでAmazon S3からデータを読み取り、トレーニング時間を短縮できる。

2023年の8月に、S3バケットをローカルファイルシステムとしてマウントするためのMountpoit for Amazon S3はリリースされていました(参考:Mountpoint for Amazon S3 – Generally Available and Ready for Production Workloads | AWS News Blog)。

今回は、Container Storegae Interface(CSI)に対応したことで、Kubernetesアプリケーションのファイルシステムから直接S3オブジェクトにアクセスできます。

主な制約

  • Windowsコンテナイメージでは利用不可
  • AWS Fargateは未サポート。EC2上で動作するKubernetesに対応
  • 静的プロビジョニングのみに対応。動的プロビジョニング(新バケットの作成)は未対応

前提条件

  • Kubernetesクラスター用のIAM OpenID Connect(OIDC)プロバイダ
  • AWS CLIバージョン2.12.3以降
  • kubectlコマンドラインツールのインストール

実際にAmazon S3 CSI driverを利用してみる

というわけで、公式ドキュメント(Mountpoint for Amazon S3 CSI driver - Amazon EKS)に則り、実際に動作を試してみます。環境は以下の通り。

$ sw_vers
ProductName:            macOS
ProductVersion:         13.4.1
BuildVersion:           22F82

$ aws --version
aws-cli/2.14.5 Python/3.11.6 Darwin/22.5.0 exe/x86_64 prompt/off

$ kubectl version
Client Version: v1.28.3-eks-e71965b
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.3-eks-4f4795d

S3バケットの作成

事前に適当な名前でS3バケットを作成しておきます。自分は、test-s3-csi-driverという名前でマネジメントコンソールから作成しておきました。設定などは全てデフォルトのままです。

IAMポリシーの作成

Mountpoint for Amazon S3 CSIドライバは、ファイルシステムとやり取りするためにAmazon S3の権限が必要です。

以下のポリシー例は、Mountpointに対するIAMパーミッションの推奨に従っています。代わりに、AWSのマネージドポリシーAmazonS3FullAccessを使用できますが、パーミッションとしては必要以上に大きい点は考慮しておきましょう。詳細な、IAMポリシーについては、mountpoint-s3/doc/CONFIGURATION.mdを参照。

以下のJSONを利用したIAMポリシーを作成します。DOC-EXAMPLE-BUCKET1は、自分の環境のS3バケット名を指定します。ポリシー名はAmazonS3CSIDriverPolicyとします。

{
   "Version": "2012-10-17",
   "Statement": [
        {
            "Sid": "MountpointFullBucketAccess",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET1"
            ]
        },
        {
            "Sid": "MountpointFullObjectAccess",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:AbortMultipartUpload",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET1/*"
            ]
        }
   ]
}

ドライバー用のIAMロールと、そこに紐づくKubernetesサービスアカウントの作成

本来は、サービスアカウントとIAMロールは別の手順で作成する必要がありますが、eksctlには、便利なcreate iamserviceaccountというコマンドがあり、それを使うことで、IAMロールの作成とサービスアカウントの作成を同時に実行できます。

コマンドはこちら。POLICY_ARNには、前手順で作成したAmazonS3CSIDriverPolicyのARNを入力しています。その他パラメータを各自の環境に合わせて変更し、実行してみてください。

POLICY_ARN=$(aws iam list-policies --query 'Policies[?PolicyName==`AmazonS3CSIDriverPolicy`].Arn' --output text)
CLUSTER_NAME=my-cluster
REGION=region-code
ROLE_NAME=AmazonEKS_S3_CSI_DriverRole
eksctl create iamserviceaccount \
    --name s3-csi-driver-sa \
    --namespace kube-system \
    --cluster $CLUSTER_NAME \
    --attach-policy-arn $POLICY_ARN \
    --approve \
    --role-name $ROLE_NAME \
    --region $REGION

うまくいくと、IAMロールとKubernetesのサービスアカウントがkube-system名前空間にs3-csi-driver-saという名前で作成されています。中身を参照すると、Annotationsに、作成したRoleのARNが含まれていることがわかります。

$ kubectl -n kube-system describe sa s3-csi-driver-sa
Name:                s3-csi-driver-sa
Namespace:           kube-system
Labels:              app.kubernetes.io/managed-by=eksctl
Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/AmazonEKS_S3_CSI_DriverRole
Image pull secrets:  <none>
Mountable secrets:   <none>
Tokens:              <none>
Events:              <none>

Mountpoint for Amazon S3 CSI driverのインストール

ここまででdriverに適用するIAM Roleを作成しました。この手順では、いよいよS3 CSI driverをEKSクラスターに導入していきます。

Mountpoint for Amazon S3 CSI driverは、EKSのadd-onとしてインストールできます。インストール方法はいくらかありますが、ここではマネジメントコンソールから作業していきます。その他手順は、Managing Amazon EKS add-ons - Amazon EKSを参考にしてください。

マネジメントコンソールでEKSクラスターを参照し、[Add-ons]タブをクリックし[Get more add-ons]をクリックすると、クラスターに導入可能なAmazon EKS add-onsが表示されます。

[Amazon Mountpoint for S3 CSI Drive]を選択し、[Next]ボタンクリックでアドオンの設定画面になります。ここでは、[Select IAM role]で先程作成した[AmazonEKS_S3_CSI_DriverRole]を、[Optional configuration settings]で[Override]を指定します。

[Next]をクリックすると確認画面が表示されるので、そのまま[Create]をクリックします。

Add-onsの一覧画面に戻り、Amazon Mountpoint for S3 CSI DriverのStatusがActiveになれば、正常にdriverのインストールは完了です。

サンプルアプリケーションによる動作確認

ここまでで前準備は完了です。いよいよ、実際にボリュームをマウントして動作確認をしていきましょう。

GitHub上に動作確認用のサンプルアプリケーションがアップロードされているので合わせて参考にしてみてください。

mountpoint-s3-csi-driver/examples/kubernetes/static_provisioning/README.md

ファイル名static_provisioning.yamlで、以下のyamlを用意します。変更点は、Bucket nameBucket region。このマニフェストファイルで、S3のPersistentVolumeへのマウントと、ファイル作成用のcentosコンテナからシェル実行で、S3にファイルを書き込みます。

  • Bucket name (required): PersistentVolume -> csi -> volumeAttributes -> bucketName
  • Bucket region (if bucket and cluster are in different regions): PersistentVolume -> csi -> mountOptions

簡単に、このマニフェストファイルを解説すると、このyamlで以下3つのリソースが作成されます。

  • name:s3-pv
    • kind: PersistentVolume
    • 解説: ここでcsiドライバーのs3.csi.aws.comを利用して、S3バケットをs3-csi-driver-volumeという名前でマウントします。capacityの設定は必須なのでありますが、S3にサイズ上限はないので実際的には無視されるようです。また、accessModesで、ボリュームの動作種別の設定も可能
  • name:s3-claim
    • kind: PersistentVolumeClaim
    • 解説: 実際のボリュームマウント処理です。s3-pvという名前で、ボリュームをマウントします。これにより、S3がコンテナ内のファイルシステムとしてマウントされ利用可能となります
  • name:s3-app
    • kind: Pod
    • 解説: centosのイメージを使い、シェルコマンドでボリュームしたディレクトリの/data/配下にファイルを書き込みます。これにより、正常にS3にファイルが作成されていれば、S3マウントが完了していることがわかります。/dataディレクトリは、上で定義したs3-claimを利用してマウントします

static_provisioning.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: s3-pv
spec:
  capacity:
    storage: 1200Gi # ignored, required
  accessModes:
    - ReadWriteMany # supported options: ReadWriteMany / ReadOnlyMany
  mountOptions:
    - allow-delete
    - region ap-northeast-1
  csi:
    driver: s3.csi.aws.com # required
    volumeHandle: s3-csi-driver-volume
    volumeAttributes:
      bucketName: <your_bucketname>
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: s3-claim
spec:
  accessModes:
    - ReadWriteMany # supported options: ReadWriteMany / ReadOnlyMany
  storageClassName: "" # required for static provisioning
  resources:
    requests:
      storage: 1200Gi # ignored, required
  volumeName: s3-pv
---
apiVersion: v1
kind: Pod
metadata:
  name: s3-app
spec:
  containers:
    - name: app
      image: centos
      command: ["/bin/sh"]
      args: ["-c", "echo 'Hello from the container!' >> /data/$(date -u).txt; tail -f /dev/null"]
      volumeMounts:
        - name: persistent-storage
          mountPath: /data
  volumes:
    - name: persistent-storage
      persistentVolumeClaim:
        claimName: s3-claim

上記作成したマニフェストファイルをデプロイ。

$ kubectl apply -f static_provisioning.yaml

S3へのファイル書き込み用Podのs3-appが起動しているか確認します。

$ kubectl get pod s3-app

正常にS3がマウントされてファイルシステムへの書き込みができていれば、指定したバケットにファイルが作成されています。お疲れ様でした!

$ aws s3 ls <your_bucket_name>
2023-12-05 07:31:03         26 Mon Dec  4 22:31:02 UTC 2023.txt

ボリュームとPodの削除は以下コマンドで実施。

$ kubectl delete -f static_provisioning.yaml

以上、S3へのVolumeマウントとファイル書き込みの様子をお届けしました。

まとめ「Kubernetesからよりネイティブな方式でS3マウントを実現」

大量、あるいは大型のファイルをKubernetesで扱う場合、NodeのファイルシステムからEFSなどをマウントしてKubernetesからボリュームを割り当て利用しているパターンも多かったのではないでしょうか?今回のアップデートでは、大量あるいは大型のファイルはS3に用意しておきアプリケーション側から都度マウントして利用することで、より柔軟にS3の拡張性と耐久性を利用してファイルシステムとして手軽にKubernetesから利用することができるようになっています。

IAMロール周辺の事前設定やドライバーのインストールがそれなりに手間ですが、このあたりをIaC管理できれば、非常に手軽にS3をKubernetesのボリュームとして利用することが可能です。Kubernetesのアプリケーションワークロードのさらなる広がりを感じるアップデートなので、皆さんも是非活用してみることをおすすめします。

それでは、今日はこのへんで。濱田(@hamako9999)でした。