{"id":430,"date":"2025-09-11T11:48:38","date_gmt":"2025-09-11T11:48:38","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=430"},"modified":"2025-09-11T11:48:38","modified_gmt":"2025-09-11T11:48:38","slug":"setup-efs-csi-driver-eks","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=430","title":{"rendered":"How to Use AWS EFS on EKS with the EFS CSI Driver (Step-by-Step)"},"content":{"rendered":"<p>In this guide, you will learn to provision Amazon EFS as persistent storage for an Amazon EKS cluster. It includes dynamic and static provisioning, StorageClass, PVC, and a practical example.<\/p>\n<p>Here is what we are going to do.<\/p>\n<ol>\n<li>Enable the EFS CSI driver addon<\/li>\n<li>Create an EFS filesystem<\/li>\n<li>Create a StorageClass for EFS Dynamic provisioning.<\/li>\n<li>Deploy a sample app to test the EFS based PVC using Dynamic provisioing.<\/li>\n<li>Try out Static Provisioning on the existing EFS file system<\/li>\n<\/ol>\n<p>Lets dive in!<\/p>\n<h2 id=\"use-case\">Use Case<\/h2>\n<p>There are many use cases where you might need EFS backed storage for your applications running on AWS EKS.<\/p>\n<p>The main advantage of using the EFS as persistent storage is that it is a Network File System (NFS), so multiple worker nodes can share the same storage space.<\/p>\n<p>Unlike <a href=\"https:\/\/devopscube.com\/provsion-persistent-volume-on-eks\/\" rel=\"noreferrer\">EBS volumes<\/a> which can only be attached to one pod at a time, EFS supports concurrent access from multiple <a href=\"https:\/\/devopscube.com\/kubernetes-pod\/\" rel=\"noreferrer\">Kubernetes pods<\/a> (<strong><code>ReadWriteMany<\/code><\/strong> access mode), making it ideal for use cases requiring shared storage.<\/p>\n<h2 id=\"what-is-amazon-efs-csi-driver\">What is Amazon EFS CSI Driver?<\/h2>\n<p>EKS does not natively support EFS volumes out of the box.<\/p>\n<p>To use EFS, you need to enable the EFS CSI driver add-on provided by AWS. It is a plugin which allows Kubernetes to use Amazon EFS file systems as persistent storage.<\/p>\n<p>Once you enable it, you will be able to create EFS based persistent volumes using the EFS storage class.<\/p>\n<h2 id=\"prerequisites\">Prerequisites<\/h2>\n<p>The following are the prerequisites to follow this guide.<\/p>\n<ol>\n<li><a href=\"https:\/\/devopscube.com\/use-aws-cli-create-ec2-instance\/\" rel=\"noreferrer\">AWS CLI<\/a> (v2.18.10 or later) installed with admin privileges to the EKS service [Local Machine]<\/li>\n<li>Existing EKS cluster or create a new one with this guide &#8211;&gt; <a href=\"https:\/\/devopscube.com\/create-aws-eks-cluster-eksctl\/\" rel=\"noreferrer\">Create AWS EKS Cluster Using eksctl<\/a><\/li>\n<li>EKSCTL (v0.193.0 or later) utility installed on your workstation [Local Machine]<\/li>\n<li><a href=\"https:\/\/devopscube.com\/kubectl-set-context\/\" rel=\"noreferrer\">Kubectl<\/a> &#8211;&gt; A suitable version as the EKS cluster should be present on the local machine [Local Machine]<\/li>\n<\/ol>\n<h2 id=\"install-the-efs-csi-driver-eksctl-alternatives\">Install the EFS CSI Driver (eksctl + alternatives)<\/h2>\n<p>You can add parameters to the <a href=\"https:\/\/devopscube.com\/create-aws-eks-cluster-eksctl\/#create-eks-cluster-using-eksctl\" rel=\"noreferrer\"><strong><code>eksctl<\/code><\/strong> manifest <\/a>to install the EFS CSI driver. This is the easiest method if you are creating the EKS cluster with the driver.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">Other methods for installing the CSI Driver, such as via <a href=\"https:\/\/devopscube.com\/create-helm-chart\/\" rel=\"noreferrer\">Helm<\/a>, <a href=\"https:\/\/devopscube.com\/create-kubernetes-yaml\/\" rel=\"noreferrer\">YAML manifest<\/a>, Eksctl manifest, or UI.<\/div>\n<\/div>\n<h3 id=\"eksctl-manifest-installation\">EKSCTL Manifest Installation<\/h3>\n<p>To enable the EFS CSI Driver, add the following parameters under the <code>addons<\/code> section of the <strong>eksctl<\/strong> manifest.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-71.png\" class=\"kg-image\" alt=\"efs csi driver addon configuration in eksctl config file\" loading=\"lazy\" width=\"1069\" height=\"737\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-71.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-71.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-71.png 1069w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<blockquote><p><strong>Note:<\/strong> Ensure the <code>addonsConfig.autoApplyPodIdentityAssociations<\/code> paramenter is set to <code>true<\/code> to work this plugin with the <strong>Pod Identity Agent Plugin.<\/strong><\/p><\/blockquote>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Pod Identity Agent <\/strong><\/b>is another EKS plugin that helps pods get the IAM permissions to access the AWS resources.<\/p>\n<p>Ensure the <b><strong style=\"white-space: pre-wrap;\">Pod Identity Agent Plugin<\/strong><\/b> is present in the cluster by listing the available plugins <code spellcheck=\"false\" style=\"white-space: pre-wrap;\">aws eks list-addons --cluster-name ${CLUSTER_NAME} --region ${REGION}<\/code><\/div>\n<\/div>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udc49<\/div>\n<div class=\"kg-callout-text\">If you already have an EKS cluster deployed by the Eksctl manifest, but want to update it with the plugin configuration, you can use the following command.<\/p>\n<p><code spellcheck=\"false\" style=\"white-space: pre-wrap;\">eksctl create cluster -f your-cluster.yaml --update-config<\/code><\/div>\n<\/div>\n<h3 id=\"validating-the-installation\">Validating the Installation<\/h3>\n<p>Once the installation is completed, we can list the pods in the <code>kube-system<\/code> namespace to ensure the EFS CSI controller and node pods are running properly.<\/p>\n<pre><code>kubectl -n kube-system get po<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-72.png\" class=\"kg-image\" alt=\"The list of ebs csi driver pods on the kube-system namespace\" loading=\"lazy\" width=\"1201\" height=\"800\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-72.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-72.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-72.png 1201w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>The status of the EFS CSI Driver controller and agent pods ensures that the deployment is properly done.<\/p>\n<h2 id=\"create-efs-file-system-security-groups-mount-targets\">Create EFS (file system, security groups, mount targets)<\/h2>\n<p>Unlike the EBS CSI driver, <strong>EFS CSI will not provision EFS<\/strong> itself, instead it will create access points inside the EFS as per the pod requirements. <\/p>\n<p>So we need to manually create an EFS. We will use aws cli to create EFS.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-text\"><b><strong style=\"white-space: pre-wrap;\">Note: <\/strong><\/b>If you already have an EFS, you can directly jump into the <b><strong style=\"white-space: pre-wrap;\">Storage Class<\/strong><\/b> creation, or you can follow the steps.<\/div>\n<\/div>\n<p>Set the Filesystem name and region as the environment variable<\/p>\n<pre><code class=\"language-bash\">EFS_NAME=EKSEFSFileSystem\nEFS_CREATION_TOKEN=eks-efs\nREGION=us-west-2<\/code><\/pre>\n<p>Use the following command to create an EFS using the CLI.<\/p>\n<pre><code>aws efs create-file-system \\\n    --performance-mode generalPurpose \\\n    --throughput-mode bursting \\\n    --encrypted \\\n    --creation-token ${EFS_CREATION_TOKEN} \\\n    --region ${REGION} \\\n    --tags Key=Name,Value=${EFS_NAME}<\/code><\/pre>\n<ul>\n<li><code>performance-mode<\/code> &#8211;&gt; To specify the performance mode (<code>generalPurpose<\/code> or <code>maxIO<\/code>)<\/li>\n<li><code>--throughput-mode<\/code> &#8211;&gt; specifies the throughput mode (<code>bursting<\/code> or <code>provisioned<\/code>)<\/li>\n<li><code>--encrypted<\/code> &#8211;&gt; Enables the data encryption at rest<\/li>\n<li><code>--creation-token<\/code> &#8211;&gt; <strong>unique identifier<\/strong> for the EFS.<\/li>\n<\/ul>\n<p>To check the creation of the EFS, open the EFS dashboard on the AWS console.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-65.png\" class=\"kg-image\" alt=\"The created efs volume on the efs dashboard\" loading=\"lazy\" width=\"658\" height=\"415\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-65.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-65.png 658w\"><\/figure>\n<p>This is the basic EFS creation, but you can customize the configurations as per your requirements.<\/p>\n<p>Save the file system ID as the environment variable for the upcoming configuration.<\/p>\n<pre><code>export FILESYSTEM_ID=&lt;FILE SYSTEM ID&gt;<\/code><\/pre>\n<h3 id=\"configure-security-groups\">Configure Security Groups<\/h3>\n<p>Our cluster only needs to access the EFS via its mount targets, so we need to carefully configure the EFS security group for inbound and outbound traffic.<\/p>\n<p>We will talk about the mount targets in the next section.<\/p>\n<p>We need to set some required values as environment variables to create the Security Group.<\/p>\n<pre><code>export VPC_ID=&lt;YOUR VPC ID&gt;\nexport CLUSTER_SG_ID=&lt;CLUSTER SECURITY GROUP ID&gt;<\/code><\/pre>\n<p>You can create a new security group with the following command.<\/p>\n<pre><code>aws ec2 create-security-group --group-name eks-efs-mount-target-sg --description \"Security group for EFS mount targets\" --vpc-id ${VPC_ID} --region ${REGION}<\/code><\/pre>\n<p>From the terminal output, note down the Security Group ID and create it as an environment variable.<\/p>\n<pre><code>export SG_ID=&lt;SECURITY GROUP ID&gt;<\/code><\/pre>\n<p>Add inbound rules for Protocol <strong>TCP<\/strong> and Port <strong>2049<\/strong>. The source should be the Security Group of the EKS Cluster.<\/p>\n<pre><code>aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol tcp --port 2049 --source-group ${CLUSTER_SG_ID} --region ${REGION}<\/code><\/pre>\n<p>For now, we give outbound traffic to allow all, but you can also restrict it.<\/p>\n<pre><code>aws ec2 authorize-security-group-egress \\\n  --group-id ${SG_ID} \\\n  --protocol -1 \\\n  --port all \\\n  --cidr 0.0.0.0\/0 \\\n  --region ${REGION}\n<\/code><\/pre>\n<p>We can ensure the rules are properly configured in the security group from the UI.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-69.png\" class=\"kg-image\" alt=\"The security group inbound rules for the incoming traffic\" loading=\"lazy\" width=\"1175\" height=\"562\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-69.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-69.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-69.png 1175w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>EFS creation is completed, so now, we need to create mount targets in EFS and attach the Security Group to those.<\/p>\n<h3 id=\"set-up-efs-mount-targets\">Set up EFS Mount Targets<\/h3>\n<p><strong>EFS mount targets<\/strong> are network entry points allowing worker nodes to connect with the File System, and are based on availability zones.<\/p>\n<p>We need to create mount targets on each availability zone of the worker nodes so that each node can access the EFS.<\/p>\n<p>In our case, we only use two subnets in two AZs for our cluster, which are <code>us-west-2c<\/code> and <code>us-west-2d<\/code> so that we need to create two mount targets.<\/p>\n<p>Create environment variables for these two subnet IDs.<\/p>\n<pre><code>export SUBNET_1=&lt;ZONE C SUBNET ID&gt;\nexport SUBNET_2=&lt;ZONE D SUBNET ID&gt;<\/code><\/pre>\n<p>Replace with your actual subnet IDs.<\/p>\n<p>Use the following command to create mount targets with the subnet IDs.<\/p>\n<pre><code>aws efs create-mount-target --file-system-id ${FILESYSTEM_ID} --subnet-id  ${SUBNET_1} --security-groups ${SG_ID} --region ${REGION}<\/code><\/pre>\n<pre><code>aws efs create-mount-target --file-system-id ${FILESYSTEM_ID} --subnet-id  ${SUBNET_2} --security-groups ${SG_ID} --region ${REGION}<\/code><\/pre>\n<p>When you execute these commands, you can see the output on the terminal, and you can ensure that with the <strong>EFS<\/strong> dashboard.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-70.png\" class=\"kg-image\" alt=\"listing the created mount targets on the elastic file system \" loading=\"lazy\" width=\"1409\" height=\"625\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-70.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-70.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-70.png 1409w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<h2 id=\"provisioning-methods\">Provisioning methods<\/h2>\n<p>EFS CSI supports the following two provisioning methods.<\/p>\n<ol>\n<li><strong>Static Provisioning:<\/strong> Manually create an access point and attach it to the workload. Access point are Filesystem entry points. Meaning directories inside the EFS. <\/li>\n<li><strong>Dynamic Provisioning<\/strong> &#8211; Workloads will automatically create access points based on requirements.<\/li>\n<\/ol>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">We can set the same Linux directory permissions for these access points, including user ID and group ID for access, as well as set permissions for read and write.<\/div>\n<\/div>\n<p>The provisioning method depends on the StorageClass configuration. <\/p>\n<p>First we will look at <strong>Dynamic Provisioning<\/strong> which is a commonly used provisioning method.<\/p>\n<h2 id=\"dynamic-provisioning-storageclass-pvc\">Dynamic Provisioning (StorageClass + PVC)<\/h2>\n<p>With EFS now successfully configured, the next step is to create Kubernetes <strong><code>StorageClasses<\/code><\/strong> to integrate it as persistent storage for the cluster.<\/p>\n<p>In this method, we don&#8217;t create the access points manually. Instead, when PVC is created with the specified StorageClass, the access point will be automatically created.<\/p>\n<p>Let&#8217;s create the storage class with the following parameters.<\/p>\n<pre><code class=\"language-yaml\">cat &lt;&lt;EOF &gt; dynamic-efs-sc.yaml\napiVersion: storage.k8s.io\/v1\nkind: StorageClass\nmetadata:\n  name: dynamic-efs-sc\nprovisioner: efs.csi.aws.com\nreclaimPolicy: Delete\nparameters:\n  provisioningMode: efs-ap\n  fileSystemId: ${FILESYSTEM_ID}\n  subPathPattern: \"\\${.PVC.name}\"\n  directoryPerms: \"0777\"\nEOF<\/code><\/pre>\n<p>For dynamic provisioning, we required the <code>fileSystemID<\/code> parameter to define the EFS and used the <code>subPathPattern<\/code> parameter to create unique subdirectories inside the EFS file system for each provisioning.<\/p>\n<p>In this dynamic provisioning method, when we create a PVC object, the EFS CSI driver will create an access point in EFS, based on the <code>subPathPattern<\/code>.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\"><code spellcheck=\"false\" style=\"white-space: pre-wrap;\">.PVC.name<\/code> &#8211;&gt; This defines the name of the access point and is same as the PVC, instead, you can use <code spellcheck=\"false\" style=\"white-space: pre-wrap;\">PV.name<\/code> and <code spellcheck=\"false\" style=\"white-space: pre-wrap;\">.NAMESPACE.name<\/code> as well.<\/div>\n<\/div>\n<p>To deploy this Storage Class, use the following command.<\/p>\n<pre><code>kubectl apply -f dynamic-efs-sc.yaml<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-75.png\" class=\"kg-image\" alt=\"listing the newly created storage class for the dynamic access point creation of the efs file system\" loading=\"lazy\" width=\"1844\" height=\"461\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-75.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-75.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/05\/image-75.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-75.png 1844w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">AWS has a quota of <a href=\"https:\/\/docs.aws.amazon.com\/efs\/latest\/ug\/efs-access-points.html?ref=devopscube.com\" rel=\"noreferrer\"><b><strong style=\"white-space: pre-wrap;\">10000 Access Points<\/strong><\/b><\/a><b><strong style=\"white-space: pre-wrap;\"> per EFS file system<\/strong><\/b>.<\/div>\n<\/div>\n<h2 id=\"deploy-sample-app-nginx-verify-persistence\">Deploy Sample App (Nginx) &amp; Verify Persistence<\/h2>\n<p>Now that we have created a StorageClass object for dynamic provisioning, we need to test it with a real application.<\/p>\n<p>For the testing, we will do the following.<\/p>\n<ol>\n<li>Creates a PVC for the demo application with the previously created Storage Class.<\/li>\n<li>Creates a demo nginx deployment with the PVC to test the creation and mounting of the EFS access point.<\/li>\n<\/ol>\n<h3 id=\"create-a-persistent-volume-claim-pvc\">Create a Persistent Volume Claim (PVC)<\/h3>\n<p>The first step is to create a <strong>PVC<\/strong> with the <strong>Storage Class<\/strong>, so that it can request a volume section from the EFS for the application.<\/p>\n<p>Create a PVC manifest.<\/p>\n<pre><code class=\"language-yaml\">cat &lt;&lt;EOF &gt; nginx-efs-claim.yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: nginx-efs-claim\nspec:\n  accessModes:\n    - ReadWriteMany\n  storageClassName: dynamic-efs-sc\n  resources:\n    requests:\n      storage: 1Gi  \nEOF<\/code><\/pre>\n<p>Since the EFS is a Network Filesystem, we have chosen the access modes as <code>ReadWriteMany<\/code> . This mode lets multiple nodes access the same access point.<\/p>\n<p>Onverall, EFS supports almost all access modes,<\/p>\n<ol>\n<li><code>ReadWriteOnce<\/code> &#8211;&gt; Only one pod can read and write<\/li>\n<li><code>ReadWriteMany<\/code> &#8211;&gt; Multiple pods can read and write<\/li>\n<li><code>ReadOnlyMany<\/code> &#8211;&gt; Multiple pods can read the same volume<\/li>\n<\/ol>\n<p>Deploy the PVC<\/p>\n<pre><code class=\"language-bash\">kubectl apply -f nginx-efs-claim.yaml<\/code><\/pre>\n<p>Once the PVC manifest is deployed, the EFS Access Point will be created immediately, and binding with the PVC will happen in parallel<\/p>\n<p>Let&#8217;s check the PVC to see the binding status.<\/p>\n<pre><code class=\"language-bash\">kubectl get pvc<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-77.png\" class=\"kg-image\" alt=\"the created pvc by the efs csi driver\" loading=\"lazy\" width=\"1825\" height=\"293\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-77.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-77.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/05\/image-77.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-77.png 1825w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>To list the PVs<\/p>\n<pre><code class=\"language-bash\">kubectl get pv<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-78.png\" class=\"kg-image\" alt=\"the created pvc and the confirmation of tha bounding with the pv\" loading=\"lazy\" width=\"1857\" height=\"372\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-78.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-78.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/05\/image-78.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-78.png 1857w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>One more thing we need to check is the created access point in the AWS console as shown below..<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-79.png\" class=\"kg-image\" alt=\"the dynamically created access points from the efs file system\" loading=\"lazy\" width=\"973\" height=\"384\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-79.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-79.png 973w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>This ensures that the access point is dynamically created, so now we can create a sample workload to attach and test this volume.<\/p>\n<h3 id=\"deploying-a-sample-nginx-workload-with-efs-mount\">Deploying a Sample Nginx Workload With EFS Mount<\/h3>\n<p>You can choose any of your applications for this demo purpose. For now, I am choosing the Nginx web server.<\/p>\n<p>We are creating an Nginx deployment manifest and mounting the <code>\/usr\/share\/nginx\/html<\/code> directory of the web server to the EFS access point, so the data won&#8217;t be deleted even if the Pod gets destroyed.<\/p>\n<p>Create a deployment manifest<\/p>\n<pre><code class=\"language-yaml\">cat &lt;&lt;EOF &gt; nginx-deployment.yaml\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: nginx-efs-deployment\n  labels:\n    app: nginx-efs\nspec:\n  replicas: 2 \n  selector:\n    matchLabels:\n      app: nginx-efs\n  template:\n    metadata:\n      labels:\n        app: nginx-efs\n    spec:\n      containers:\n        - name: nginx\n          image: nginx:latest\n          ports:\n            - containerPort: 80\n          volumeMounts:\n            - name: efs-storage\n              mountPath: \/usr\/share\/nginx\/html\n      volumes:\n        - name: efs-storage\n          persistentVolumeClaim:\n            claimName: nginx-efs-claim\n\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-efs-service\nspec:\n  type: NodePort\n  selector:\n    app: nginx-efs\n  ports:\n    - protocol: TCP\n      port: 80\n      targetPort: 80\n      nodePort: 30080\nEOF<\/code><\/pre>\n<p>Here, you can see that under the <code>volumes<\/code> section, we are referring to the PVC that we have previously created.<\/p>\n<p>Deploy the Nginx deployment.<\/p>\n<pre><code>kubectl apply -f nginx-deployment.yaml<\/code><\/pre>\n<p>Wait a few seconds for the pods to become ready, and if the pod status turns into ready, that means the mounting is properly done.<\/p>\n<p>In the next section, we can verify the data persistence.<\/p>\n<h3 id=\"verify-data-persistence\">Verify Data Persistence<\/h3>\n<p>We can even test that the data is persistent if the pods get rescheduled.<\/p>\n<p>Let&#8217;s write something custom in the <code>index.html<\/code> file on one of the Pods, which is actually in the <code>\/usr\/share\/nginx\/html<\/code><\/p>\n<pre><code>kubectl exec -it $(kubectl get pod -l app=nginx-efs -o jsonpath='{.items[0].metadata.name}') -- \/bin\/bash<\/code><\/pre>\n<p>Use the following command to rewrite the index file.<\/p>\n<pre><code>echo \"&lt;h1&gt;Hello from EFS\\!&lt;\/h1&gt;\" &gt; \/usr\/share\/nginx\/html\/index.html\nexit<\/code><\/pre>\n<p>For testing, let&#8217;s access the web page of the web server.<\/p>\n<h4 id=\"access-the-nginx-webpage\">Access the Nginx Webpage<\/h4>\n<p>Get the public IP of one of the worker nodes and note down the Node Port number of the deployment <code>30080<\/code>.<\/p>\n<p>Open any of the web browsers and paste the URL <code>http:\/\/&lt;WORKER NODE PUBLIC IP&gt;:30080<\/code><\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/06\/image-80.png\" class=\"kg-image\" alt=\"the output of the web page sharing the same space by the efs volume\" loading=\"lazy\" width=\"1042\" height=\"441\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/06\/image-80.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/06\/image-80.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/06\/image-80.png 1042w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>The output ensures that the original data in the index file is modified.<\/p>\n<p>Now, we can test if the Pods get deleted, and the data will persist or not.<\/p>\n<h4 id=\"simulate-pod-restart\">Simulate Pod Restart<\/h4>\n<p>We can delete the pod so that the new pod will spin up automatically.<\/p>\n<p>The new pod can also be mounted with the existing PVC, so that the new pod will also get the same data.<\/p>\n<pre><code>kubectl delete pod $(kubectl get pod -l app=nginx-efs -o jsonpath='{.items[0].metadata.name}')<\/code><\/pre>\n<p>After the new pod is up, you can do the same test to ensure you are getting the same data.<\/p>\n<p>We have created mount targets on each AZ, so no matter how much you scale the application, all the pods will get the same data. Let&#8217;s check that as well.<\/p>\n<h3 id=\"scaling-pods-to-test-cross-pod-access\">Scaling Pods to Test Cross Pod Access<\/h3>\n<p>I have already mentioned that even multiple pods in different zone nodes can also access the same data. <\/p>\n<p>This is because the <strong>EFS supports cross-AZ access<\/strong>. Also, we have created more than one mount target for various zones.<\/p>\n<p>To scale the deployment, use the following command.<\/p>\n<pre><code>kubectl scale deployment nginx-efs-deployment --replicas=4<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-81.png\" class=\"kg-image\" alt=\"listing the pods of the replications\" loading=\"lazy\" width=\"1484\" height=\"293\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-81.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-81.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-81.png 1484w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Here, you can see the replications are spread across different nodes, each in a different zone, even though all pods can get the same data from the EFS storage.<\/p>\n<p>To check this, <code>exec<\/code> to any of the pod and curl <code>localhost<\/code><\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-82.png\" class=\"kg-image\" alt=\"the same output of the each pod by the efs volume\" loading=\"lazy\" width=\"2000\" height=\"461\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-82.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-82.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/05\/image-82.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w2400\/2025\/05\/image-82.png 2400w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>The output clearly shows that the new pods are also getting the same data, and this is how the EFS works as a persistent storage for the EKS cluster.<\/p>\n<p>In the next section, we will do a simulation test to know what happens even if the Pod writes data more than the resource limitation of the PVC.<\/p>\n<h2 id=\"static-provisioning-storage-class-creation-optional\">Static Provisioning Storage Class Creation (Optional)<\/h2>\n<p>Static provisioning refers that if we have an existing filesystem (EFS root dir), or access point (Dir inside root dir) we can mount as a volume.<\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">If you are using Fargate nodes on the EKS cluster, static provisioning is only supported.<\/div>\n<\/div>\n<p>Create a Storage Class for the static provisioning with the following contents.<\/p>\n<pre><code>apiVersion: storage.k8s.io\/v1\nkind: StorageClass\nmetadata:\n  name: efs-static-fs\nprovisioner: efs.csi.aws.com\nreclaimPolicy: Retain\nvolumeBindingMode: Immediate\nallowVolumeExpansion: true\n<\/code><\/pre>\n<p>Apply this configuration.<\/p>\n<pre><code>kubectl apply -f static-efs-sc.yaml<\/code><\/pre>\n<p>Check and verify that the <strong>StorageClass<\/strong> is successfully created.<\/p>\n<pre><code>kubectl get storageclass<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-74.png\" class=\"kg-image\" alt=\"listing the storage class object on the eks cluster\" loading=\"lazy\" width=\"1817\" height=\"377\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-74.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/05\/image-74.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/05\/image-74.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-74.png 1817w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Here, I will show how the existing access point to mount with the workload but for that we need to create one.<\/p>\n<h5 id=\"create-an-efs-access-point\">Create an EFS Access Point<\/h5>\n<p>To create an EFS access point, use the following command.<\/p>\n<pre><code>aws efs create-access-point \\\n  --file-system-id ${FILESYSTEM_ID} \\\n  --posix-user Uid=1000,Gid=1000 \\\n  --root-directory 'Path=\/static-fs-access-point,CreationInfo={OwnerUid=1000,OwnerGid=1000,Permissions=750}' \\\n  --region ${REGION}\n<\/code><\/pre>\n<p>The access point is the directory inside the root file system  (<code>\/static-fs-access-point<\/code>)<\/p>\n<p>Also, we are setting the permission for that directory is <code>750<\/code> and the owner and group ID is <code>1000<\/code>.<\/p>\n<p>Once the access point creation is completed, we can ensure that it is from the UI.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-73.png\" class=\"kg-image\" alt=\"the created access point of the aws efs\" loading=\"lazy\" width=\"935\" height=\"370\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/05\/image-73.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/05\/image-73.png 935w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>In the next section, we mount this access point to the workload.<\/p>\n<h3 id=\"attaching-access-point-to-pv\">Attaching Access Point to PV<\/h3>\n<p>Now, you can use this Storage Class for the PV instead of PVC under the <code>spec<\/code> section to mount the access point to the workload.<\/p>\n<pre><code class=\"language-yaml\">apiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv-static\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteMany\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: static-efs-sc\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: [FILE SYSTEM ID]::[ACCESS POINT ID]\n<\/code><\/pre>\n<p>Now, we can attach this PV to the workload, then the access point will be mounted with the Pod.<\/p>\n<h2 id=\"understanding-pvc-limits-with-amazon-efs\">Understanding PVC Limits with Amazon EFS<\/h2>\n<p>You may be curious to know what happens if the pod writes data more than configured resource limit in the EFS based PVC.<\/p>\n<p>Well, let&#8217;s do a practical hands-on.<\/p>\n<p>Our current PVC resource limit is 1GB.<\/p>\n<p>We deploy a Pod with this same PVC and simulate writing 2GB of data inside it.<\/p>\n<pre><code class=\"language-yaml\">cat &lt;&lt;EOF &gt; nginx-efs-test.yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: nginx-efs-test\nspec:\n  containers:\n  - name: nginx\n    image: nginx\n    volumeMounts:\n    - name: efs-vol\n      mountPath: \/usr\/share\/nginx\/html\n  - name: write-stuff\n    image: busybox\n    command: [\"sh\", \"-c\", \"dd if=\/dev\/zero of=\/mnt\/data\/bigfile bs=10M count=200 &amp;&amp; sleep 3600\"]\n    volumeMounts:\n    - name: efs-vol\n      mountPath: \/mnt\/data\n  volumes:\n  - name: efs-vol\n    persistentVolumeClaim:\n      claimName: nginx-efs-claim\nEOF<\/code><\/pre>\n<p>Deploy the test application<\/p>\n<pre><code class=\"language-bash\">kubectl apply -f nginx-efs-test.yaml<\/code><\/pre>\n<p>Ensure the PV is created and the Pod is running without any issues.<\/p>\n<p>Now, we can check the storage usage from inside the pod<\/p>\n<pre><code class=\"language-bash\">kubectl exec -it nginx-efs-test -c write-stuff -- df -h \/mnt\/data\nkubectl exec -it nginx-efs-test -c write-stuff -- du -sh \/mnt\/data\n<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/06\/image-21.png\" class=\"kg-image\" alt=\"the stoage simulated data of the efs filesystem\" loading=\"lazy\" width=\"1206\" height=\"599\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/06\/image-21.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/06\/image-21.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/06\/image-21.png 1206w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Here, you can clearly see that the container writes data more than the configured PVC storage.<\/p>\n<p>So, if you request, say, 1 GiB in a PVC, the created PV is <strong>limitless<\/strong> (i.e. can store much more), because EFS does not enforce the capacity you ask in the PVC.<\/p>\n<p>This means, the <code>storage<\/code> size in PVC is required (you must put something, e.g. <code>5Gi<\/code>) because Kubernetes API needs that. But that number <strong>does not<\/strong> limit how much data can actually be stored in the EFS via that PVC.<\/p>\n<p>Let&#8217;s check the EFS to confirm that the simulated data is reflected in the EFS dashboard.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/06\/image-22.png\" class=\"kg-image\" alt=\"The efs dashboard to ensure the stored data by the simulation\" loading=\"lazy\" width=\"1268\" height=\"595\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/06\/image-22.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/06\/image-22.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/06\/image-22.png 1268w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">Unlike block storage like EBS, EFS does not enforce the capacity you ask in the PVC.<\/p>\n<p>The only way to avoid the unnecessary cost on EFS service, monitor the storage using AWS CloudWatch alarm on <b><code spellcheck=\"false\" style=\"white-space: pre-wrap;\"><strong>FileSystemSize<\/strong><\/code><\/b> or other external monitoring system.<\/p>\n<p>Also, if true quotas are mandatory, consider using EBS or self-managed NFS on EC2 where OS\/file-system quotas (XFS\/ZFS) are possible.<\/p><\/div>\n<\/div>\n<h2 id=\"cleaning-up-resources\">Cleaning Up Resources<\/h2>\n<h3 id=\"remove-the-workload\">Remove the Workload<\/h3>\n<pre><code class=\"language-bash\">kubectl delete -f nginx-deployment.yaml<\/code><\/pre>\n<h3 id=\"delete-persistentvolumeclaims-and-storageclasses\">Delete PersistentVolumeClaims and StorageClasses<\/h3>\n<pre><code class=\"language-bash\">kubectl delete -f nginx-efs-claim.yaml\nkubectl delete -f static-efs-sc.yaml\nkubectl delete -f dynamic-efs-sc.yaml<\/code><\/pre>\n<h3 id=\"delete-efs-access-points\">Delete EFS Access Points <\/h3>\n<pre><code class=\"language-bash\">aws efs delete-access-point --access-point-id &lt;access-point-id&gt; --region &lt;region&gt;<\/code><\/pre>\n<h3 id=\"delete-efs-mount-targets\">Delete EFS Mount Targets<\/h3>\n<pre><code class=\"language-bash\">aws efs delete-mount-target --mount-target-id &lt;mount-target-id&gt; --region &lt;region&gt;<\/code><\/pre>\n<h3 id=\"remove-efs-file-system\">Remove EFS File System<\/h3>\n<pre><code class=\"language-bash\">aws efs delete-file-system --file-system-id $FILESYSTEM_ID --region $REGION\n<\/code><\/pre>\n<h2 id=\"best-practices-for-efs-csi-driver\">Best Practices for EFS CSI Driver <\/h2>\n<p>Following are some of the important best practices to follow when using the EFS CSI driver.<\/p>\n<ol>\n<li>When creating the Security Group for the EFS, ensure only necessary ports and protocols are open.<\/li>\n<li>When creating the EFS, choose the configuration based on your use case, such as whether you are going to use this for the general workload or need a higher input and output speed.<\/li>\n<li>Monitor the EFS using AWS <a href=\"https:\/\/devopscube.com\/how-to-setup-and-push-serverapplication-logs-to-aws-cloudwatch\/\" rel=\"noreferrer\">CloudWatch<\/a> to see the I\/O and storage allocation. <\/li>\n<li>Backup the EFS File System using the AWS Backup service, AWS Datasync, or manually perform periodic backups.<\/li>\n<\/ol>\n<h2 id=\"conclusion\"><strong>Conclusion<\/strong><\/h2>\n<p>In this article, we have covered all the key options and configurations to use EFS as persistent volume on EKS cluster.<\/p>\n<p>When you are working through the setup, if you are facing any issues, do let us know in the comments.<\/p>\n<p>Also, to learn more about EKS storage options, please visit the AWS <a href=\"https:\/\/docs.aws.amazon.com\/eks\/latest\/userguide\/storage.html?ref=devopscube.com\">official documentation<\/a>.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/setup-efs-csi-driver-eks\/\" target=\"_blank\" rel=\"noopener noreferrer\">How to Use AWS EFS on EKS with the EFS CSI Driver (Step-by-Step) \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/setup-efs-csi-driver-eks\/<\/p>\n","protected":false},"author":1,"featured_media":431,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-430","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/430","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=430"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/430\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/431"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=430"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=430"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=430"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}