はじめに
ここ2ヶ月ほどEKS/Kubernetesを触っています。
アプリケーションをコンテナ化する以上、コンテナは状態をなるべく持たず状態はデータベースやオブジェクトストレージに保存するようにするのがベストプラクティスですが、どうしてもファイルシステムにファイルを保存したいという場合はあるのではないでしょうか。
そういった場合、KubernetesのPersistent Volumeの仕組みを使うとPodに非揮発性のファイルシステムをマウントすることができます。
ただ、マウント対象のファイルシステムは自分で用意しないといけません。
マウント対象としてはいくつか選べるのですが、複数のPodから同時に読めて状態を共有できるようにするにはNFSファイルシステムをマウントするのがよいと思われます。
そこで、マネージドNFSファイルシステムであるAmazon EFSのファイルシステムをEKSクラスタで利用しようとしました。
EKSもEFSもAWSのマネージドサービスだし楽勝だろ、と思っていたら意外とハマったので、手順を共有して苦しむ人が減ればと思います。
EFSファイルシステムを作成する
AWSコンソールからEFSファイルシステムを作成します。
このとき、EKSのワーカーノードが存在するサブネットすべてをマウントターゲットに追加し、またそれぞれセキュリティグループをEKSが勝手に作成するセキュリティグループを設定しておきます。
こちらのクイックスタートをつかっていれば、xxx-NodeSecurityGroup-yyy
みたいな名前のセキュリティグループができているかと思いますが、それです。

ワーカーノードのIAMロール
EKSワーカーノードのロールに1で作ったEFSボリュームに関するポリシーを追加します。こちらもクイックスタートを使っていると、xxx-NodeInstanceRole-yyy
という名前になっているかと。
こちらのロールに、さきほど作成したEFSファイルシステムの「リスト・読み込み・書き込み」の権限が付与されていればOKです。
efs-provisioner の設定
EFSをKubernetesの永続ボリュームとして使うには、efs-provisioner
を使う必要があります。
しかし、これがREADMEの通りに手順をたどっても動かせないという罠があります。
リポジトリのサンプルマニフェストの記述が間違っているからです。。😡
こちらのIssueに解決策が載っていました。
ただマウントしたいだけなら、
と
https://github.com/kubernetes-incubator/external-storage/blob/master/aws/efs/deploy/manifest.yaml
の2つをapplyする必要がありますが、両方とも修正する必要があります。
まずrbac.yamlですが、よくわからないRoleとClusterRoleの使い分けがありますが、ClusterRoleに一本化しましょう。また、サービスロールの記述も追加しないといけません。
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: efs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-efs-provisioner
subjects:
- kind: ServiceAccount
name: efs-provisioner
namespace: development # ClusterRoleBindingの指定はネームスペースごと
roleRef:
kind: ClusterRole
name: efs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: development # ServiceAccountの指定もネームスペースごと
name: efs-provisioner
そして、manifest.yamlは、Deploymentのところにネームスペースとサービスアカウントを追記します。
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
namespace: development # この記述もネームスペースごと
name: efs-provisioner
spec:
serviceAccount: efs-provisioner
containers:
- name: efs-provisioner
image: quay.io/external_storage/efs-provisioner:latest
ディレクトリ分割
前の手順までで、Podの永続ボリュームとしてEFSファイルシステムを利用できるようになります。
適当なEC2インスタンスをたててEFSファイルシステムをマウントしてみるとわかるのですが、manifest.yamlのPersistentVolumeClaim
ごとにディレクトリが切られて、各Podからはその中しか見られないようになっています。
なので、1つのEFSファイルシステムを複数のPodで相乗り利用する場合は、共通のStorageClass
を利用するPersistentVolumeClaim
を複数定義すればよいです。
おわりに
これでEKSクラスタ上で動くPodの永続ボリュームとしてEFSファイルシステムを利用できるようになりました。
EKSもEFSもAWSの製品なのでありがちなユースケースなのではないかと思うのですが、意外とドンピシャな情報がなかったので、参考になればと思います。