Amazon EFS is a fully managed, elastic file system that can be mounted on multiple compute instances simultaneously. When you need to share data between pods running in Amazon Elastic Kubernetes Service (EKS), or persist data beyond the lifecycle of a pod, EFS is often the go-to solution. The Elastic File System (EFS) CSI driver makes this integration seamless.

Let’s see it in action. Imagine we have a simple web application that needs to store uploaded user images. We want these images to be accessible by any pod running our web app, and we want them to survive pod restarts or scaling events.

First, we need an EFS file system. You can create one via the AWS console or CLI. Let’s assume we have an EFS file system with the ID fs-0123456789abcdef0.

Next, we need to install the EFS CSI driver in our EKS cluster. This is typically done using Helm:

helm repo add aws-ecr-public https://public.ecr.aws/helm-charts
helm repo update
helm install efs-csi-driver aws-ecr-public/aws-efs-csi-driver --namespace kube-system

This command deploys the necessary controller and node plugins into your cluster.

Now, we define a StorageClass. This tells Kubernetes how to dynamically provision storage. For EFS, it’s straightforward:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisionerName: efs.csi.aws.com
  dnsName: fs-0123456789abcdef0.efs.us-east-1.amazonaws.com # Replace with your EFS DNS name

Note: Using the dnsName parameter is generally preferred over fileSystemId as it’s more resilient to EFS file system re-creation. Ensure the dnsName correctly points to your EFS file system in the appropriate region.

With the StorageClass defined, we can create a PersistentVolumeClaim (PVC) that requests storage from this class:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-data-claim
spec:
  accessModes:
    - ReadWriteMany # EFS supports ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 1Gi # This is a logical request; EFS is elastic

The crucial part here is accessModes: ReadWriteMany. This signifies that the storage can be mounted as read-write by many nodes. EFS is the only AWS storage service that supports this at the block level, making it ideal for shared access.

Finally, we mount this PVC into our application pod. Here’s a simplified Deployment definition:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web-app
        image: nginx:latest # Example image
        ports:
        - containerPort: 80
        volumeMounts:
        - name: efs-storage
          mountPath: /usr/share/nginx/html/uploads # Where images will be stored
      volumes:
      - name: efs-storage
        persistentVolumeClaim:
          claimName: efs-data-claim

When this deployment is created, Kubernetes will:

  1. See the PersistentVolumeClaim requesting efs-sc.
  2. The efs-sc StorageClass tells the EFS CSI driver to provision a volume. The driver, in this case, doesn’t "provision" in the traditional sense but rather configures Kubernetes to use your existing EFS file system.
  3. The CSI driver, running on the EKS nodes, will handle the actual mounting of the EFS file system to the node’s filesystem.
  4. The pod will then mount the PVC, which is backed by the EFS file system, to the specified mountPath.

Now, any pod running this Deployment can write to /usr/share/nginx/html/uploads, and those files will be immediately available to other pods running the same Deployment, even if they are on different nodes. If you scale the Deployment to 10 replicas, all 10 pods will share the same underlying EFS file system.

The most surprising thing about EFS integration with Kubernetes is that you’re not "provisioning" a new file system per PVC in the way you might with EBS. Instead, the CSI driver acts as a sophisticated connector, allowing Kubernetes to leverage an existing, shared EFS file system. Your StorageClass simply tells the driver which EFS file system to use and how to expose it to pods.

The EFS CSI driver uses the AWS SDK to interact with EFS and the Kubernetes CSI interface. On the worker nodes, it runs a "node plugin" which is responsible for the actual mounting and unmounting of the EFS volume to the pod’s filesystem. When a pod requests an EFS volume, the node plugin translates this into an NFS mount command to the EFS mount target.

A common point of confusion is around the accessModes. While you can request ReadWriteOnce or ReadOnlyMany, EFS is fundamentally a ReadWriteMany service. The CSI driver exposes this capability. If your StorageClass or PersistentVolumeClaim specifies ReadWriteOnce, Kubernetes will still allow multiple pods to mount it, but it’s crucial to understand that the underlying EFS file system itself supports concurrent writes from multiple clients.

This setup is incredibly powerful for shared configuration, data persistence, and distributed workloads within EKS.

When you encounter issues with EFS mounts, the first thing to check is network connectivity from your EKS worker nodes to the EFS mount targets, specifically ensuring that NFS traffic (TCP port 2049) is allowed.

Want structured learning?

Take the full Eks course →