AWS EKSで動かしているアプリケーション用にEFSを使って永続ボリュームを用意してみたので、その方法をまとめてみようと思います。
とあるテスト用Kubernetes環境でMySQLのイメージを使ってデータベースを動かしているのですが、何かの拍子にpodが一旦削除などされてしまうとデータベースの中身のデータが全て無くなってしまいます。
そこで永続ボリュームを確保しておいて、MySQLデータ用のディレクトリをマウントしたボリュームにすればOKというわけです。
手順はほぼこのドキュメントどおりですが、一部変えないと動かなかった箇所があるのでその点も触れつつ書いてみようと思います。
Amazon EFS CSI ドライバー
ドキュメントに従っても動かないよ!という件のissueはこちら。
Missing permission in the example IAM policy file · Issue #489 · kubernetes-sigs/aws-efs-csi-driver · GitHub
また、今回やってみた環境は以下のようになっています。
Kubernetes v1.21
EKSプラットフォーム eks.2
EFS CSI ドライバー v1.3.4
- Amazon EFS CSI ドライバー
まずはIAMポリシーを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticfilesystem:DescribeAccessPoints",
"elasticfilesystem:DescribeFileSystems",
"elasticfilesystem:DescribeMountTargets",
"ec2:DescribeAvailabilityZones"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"elasticfilesystem:CreateAccessPoint"
],
"Resource": "*",
"Condition": {
"StringLike": {
"aws:RequestTag/efs.csi.aws.com/cluster": "true"
}
}
},
{
"Effect": "Allow",
"Action": "elasticfilesystem:DeleteAccessPoint",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/efs.csi.aws.com/cluster": "true"
}
}
}
]
}
AmazonEKS_EFS_CSI_Driver_Policy
というポリシーを作成してこのjsonでアクセス権限を設定します。
AWSのドキュメントからリンクされているポリシーと比べると"elasticfilesystem:DescribeMountTargets", "ec2:DescribeAvailabilityZones"が増えているのですが、これを追加しないと権限不足のエラーが出てドライバーが動きませんでした。🤔
このポリシーでサービスアカウントを作成します。<cluster-name>
と<Account ID>
, <region>
はお使いの環境に合わせて置き換えてください。
$ eksctl create iamserviceaccount \
--name efs-csi-controller-sa \
--namespace kube-system \
--cluster <cluster-name> \
--attach-policy-arn arn:aws:iam::<Account ID>:policy/AmazonEKS_EFS_CSI_Driver_Policy \
--approve \
--override-existing-serviceaccounts \
--region <region>
$ eksctl create iamserviceaccount \
--name efs-csi-node-sa \
--namespace kube-system \
--cluster <cluster-name> \
--attach-policy-arn arn:aws:iam::<Account ID>:policy/AmazonEKS_EFS_CSI_Driver_Policy \
--approve \
--override-existing-serviceaccounts \
--region <region>
Helmを使ってドライバーをクラスターにインストールします。
クラスターのリージョンによってimage.repository
は変えないといけないようなので↓を参照してください。
Amazon EKS アドオンコンテナイメージのアドレス - Amazon 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.ap-northeast-1.amazonaws.com/eks/aws-efs-csi-driver \
--set controller.serviceAccount.create=false \
--set controller.serviceAccount.name=efs-csi-controller-sa \
--set node.serviceAccount.create=false \
--set node.serviceAccount.name=efs-csi-node-sa
AWSのドキュメントでは efs-csi-node-sa
は出てこないのですが、こちらも試した環境ではこのサービスアカウントを作成してhelmで指定しないと動きませんでした。🤔
- EFS ファイルシステム作成
ここはインフラ管理の都合上terraformで行いました。
セキュリティグループ、ファイルシステム、マウントターゲット(AWSコンソールでは「ネットワーク」という表示名になっています)を作成します。
VPCに複数のプライベートサブネットがある場合は aws_efs_mount_target
も同様に複数作っておきましょう。
resource "aws_security_group" "efs" {
name = "eks-${var.cluster_name}-efs"
# ↓クラスターがあるVPCのid
vpc_id = var.vpc_id
ingress {
from_port = 2049
to_port = 2049
protocol = "tcp"
# ↓VPCのCIDR
cidr_blocks = [var.vpc_cidr]
}
}
resource "aws_efs_file_system" "fs" {
creation_token = "eks-${var.cluster_name}-fs"
tags = {
"Name" = "eks-${var.cluster_name}-fs"
}
}
resource "aws_efs_mount_target" "az" {
file_system_id = aws_efs_file_system.fs.id
# ↓プライベートサブネットのID
subnet_id = var.subnet_private.id
security_groups = [aws_security_group.efs.id]
}
- クラスターでStorageClassを追加
まずはストレージクラスの宣言です。StorageClassはnamespaceに属していないので、一度applyしておけばOKです。
parametersについてはこちらを参考にしてください👇
aws-efs-csi-driver/examples/kubernetes/dynamic_provisioning at master · kubernetes-sigs/aws-efs-csi-driver · GitHub
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: efs-sc
provisioner: efs.csi.aws.com
parameters:
provisioningMode: efs-ap
# EFSで作成したファイルシステムのID
fileSystemId: fs-00abcdef123456789
directoryPerms: "700"
- アプリケーションで永続ボリュームを確保、マウント
これで準備ができたので、PersistentVolumeを使うアプリケーションでのyamlを書いていきます。
まずはPVC(PersistentVolumeClaim)です。
storageClassName
は3.で宣言したStorageClassのnameですね。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: efs-claim
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 2Gi
このPVCで確保したボリュームをコンテナにマウントします。
以下のyamlはdeploymentでやる場合のvolumeに関するところを書き出したものです。 claimName
がPVCリソースのnameですね。
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: mysql
image: mysql:8.0.25
volumeMounts:
- name: persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: efs-claim
と、このような作業で永続ボリュームを利用できました。
冒頭で触れたドキュメント不完全問題もあって少し手間取りましたが、振り返ってまとめてみるとそう難しいことはなさそうですね。
EKSで永続ボリュームが欲しくなったときはお試しください👐