{"id":307,"date":"2026-04-14T04:53:00","date_gmt":"2026-04-14T04:53:00","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=307"},"modified":"2026-04-14T04:53:00","modified_gmt":"2026-04-14T04:53:00","slug":"provsion-persistent-volume-on-eks","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=307","title":{"rendered":"How to Provision Persistent Volume on EKS Cluster"},"content":{"rendered":"<p>In this blog we will look at detailed steps to provision different types of persistent volume on AWS EKS using recommended EBS CSI Driver.<\/p><p>At the end of the guide, you will learn about the following.<\/p><ol><li>Understand EBS CSI Driver Workflow in volume provisioning.<\/li><li>Create custom StorageClass<\/li><li>Provision volume using StorageClass<\/li><li>Creating default StorageClass using annotation.<\/li><li>Enabling CSI Driver in existing clusters.<\/li><\/ol><p>Lets get started.<\/p><h2 id=\"setup-prerequisites\">Setup Prerequisites<\/h2><p>The prerequisites to follow this guide are as follows:<\/p><ol><li><a href=\"https:\/\/devopscube.com\/create-aws-eks-cluster-eksctl\/\">EKS Cluster<\/a> v1.30 or later<\/li><li>eksctl utility installed on your workstation<\/li><li>AWS CLI installed with admin privileges to EKS service.<\/li><\/ol><h2 id=\"ebs-csi-driver-workflow\">EBS CSI Driver Workflow<\/h2><p>The following workflow explains how the EBS CSI works with the Pod Identity Agent Plugin to provision a persistent EBS volume from the AWS Cloud for EKS.<\/p><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\/03\/ebs-csi-driver-1.gif\" class=\"kg-image\" alt=\"the workflow diagram of the EBS CSI Driver in the eks cluster\" loading=\"lazy\" width=\"800\" height=\"926\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/ebs-csi-driver-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/ebs-csi-driver-1.gif 800w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<!--kg-card-begin: html-->\n<ol class=\"wp-block-list is-style-cnvs-list-styled\">\n<li>The developer creates a <strong>Persistent Volume Claim (PVC)<\/strong> to get the required persistent storage for the Application Pod. The volume type and FS type will be mentioned in the<strong> StorageClass<\/strong> object.<\/li>\n\n\n<li><!--kg-card-begin: html--><span style=\"margin: 0px;padding: 0px\">The request is ro<\/span><!--kg-card-end: html-->uted from the&nbsp;Kubernetes <strong>API server<\/strong>&nbsp;in the&nbsp;control plane&nbsp;and then routed to the&nbsp;<strong>EBS CSI Controller<\/strong>&nbsp;to provision storage.<\/li>\n\n\n<li>The <strong>EBS CSI Controller<\/strong> needs to access the <strong>AWS EBS API<\/strong> to provision the <strong>EBS volume<\/strong><!--kg-card-begin: html--><span style=\"margin: 0px;padding: 0px\"><strong>,<\/strong>&nbsp;so the&nbsp;<strong>EKS Pod Identity Plugin<\/strong>&nbsp;will provide the temporary <\/span><!--kg-card-end: html-->credentials to the controller.<\/li>\n\n\n<li>The controller will validate the request and communicate with the AWS to provision an EBS volume.<\/li>\n\n\n<li>After provisioning the EBS volume, the EBS CSI Controller will get the <strong>EBS Volume ID<\/strong> and update the Persistent Volume. By the way, since it is dynamic provisioning, the PV will automatically be created. <\/li>\n\n\n<li>Also, the EBS Volume will not be attached to any Nodes until the Application Pod deployment, but the PV and PVC will be bound. <\/li>\n\n\n<li>When the Application Pod is created with the PVC, the <strong>EBS CSI Node driver<\/strong>, which is available in each node, requests that the provisioned EBS volume be attached to the particular node where the Application Pod will be run.<\/li>\n\n\n<li>Once the Node mounting is successfully completed, the CSI Node driver will get the node&#8217;s EBS mount path from the AWS API, and then the Pod will start with the volume. <\/li>\n<\/ol>\n<!--kg-card-end: html-->\n<h2 id=\"eks-cluster-with-and-without-csi-driver\">EKS Cluster With and Without CSI Driver<\/h2><p><strong>The key requirement<\/strong> for provisioning volumes with EBS is the EBS CSI Driver. Also it requires IAM privileges to manage EBS volumes for Persistent Volumes.<\/p><p>You can follow our <a href=\"https:\/\/devopscube.com\/create-aws-eks-cluster-eksctl\/\" rel=\"noreferrer\">EKS cluster creation using eksctl<\/a> guide  to spin up a cluster with EBS CSI Driver and associated IAM roles using pod Identity agent.<\/p><p>The following configuration in the eksctl YAML enables required permissions for EBS CSI Driver.<\/p><pre><code class=\"language-yaml\">addons:\n  - name: aws-ebs-csi-driver\n    version: latest\n  - name: eks-pod-identity-agent\n    version: latest\n\naddonsConfig:    \n   autoApplyPodIdentityAssociations: true<\/code><\/pre><p>If you have an existing EKS cluster <strong>but don&#8217;t have the EBS CSI Driver,<\/strong> the installation step is provided in the later section of this guide.<\/p><p>Assuming you already have an EKS cluster with the EBS CSI Driver Plugin, you can start from <strong>step 1<\/strong> to provision the Persistent Volume.<\/p><h2 id=\"provision-storage-class\">Provision Storage Class<\/h2><p>We all know that the AWS<strong> EBS<\/strong> Volumes are <strong>zone-based,<\/strong> so keep that in mind if you provision an EBS volume as persistent storage for your <strong>Pods<\/strong> in the <strong>EKS<\/strong> Cluster.<\/p><p>The <strong>Node<\/strong> and the <strong>EBS volume<\/strong> should be in the <strong>same availability zone<\/strong>. Choosing the type of EBS is also really important because it can affect the performance of your application or service.<\/p><p>EBS provides different types of storage, such as General-Purpose (SSD), Provisioned IOPS (SSD), Throughput-Optimized<strong> (HDD), Cold (HDD), and EBS Magnetic (HDD).<\/strong><\/p><p>When choosing the <strong>storage type<\/strong>, consider IOPS (Input\/Output Operations Per Second) and Throughput. If the application handles a high amount of transactional workloads such as Databases, then <strong>IOPS<\/strong> should be high.<\/p><p>In the EBS SSD-based storage types such as <strong>General Purpose (gp2, gp3) and Provisioned IOPS (Io1, Io2)<\/strong> have high <strong>IOPS<\/strong>, and can almost handle <strong>16,000 to 256,000  Input\/Output Per Second.<\/strong><\/p><p>If the requirement is to store a larger amount of data for analysis or processing then HDD-based storage options would be good, and in this, <strong>Throughput Optimized (St1), Cold (Sc1) and Magnetic (standard)<\/strong> are the available options.<\/p><p>I am creating a<strong> Storage Class<\/strong> with one of the high IOPS EBS volume types, which is <strong>Provisioned IOPS SSD (io2)<\/strong><\/p><pre><code class=\"language-yaml\">cat &lt;&lt;EOF &gt; ebs-io2-volume.yaml\nkind: StorageClass\napiVersion: storage.k8s.io\/v1\nmetadata:\n  name: io2-volume\nprovisioner: ebs.csi.aws.com\nparameters:\n  type: io2\n  iopsPerGB: \"50\"  \n  fsType: ext4    \nvolumeBindingMode: Immediate\nEOF<\/code><\/pre><p>I am using the <strong>volumeBindingMode<\/strong> as <strong>Immediate<\/strong> so that when someone creates a Persistent Volume Claim (PVC) that matches this Storage Class configuration, the PV and PVC will be immediately bound once the volume is provisioned.<\/p><p>Another option is <strong>WaitForFirstConsumer<\/strong>. In this, the bounding process waits until the pod is created because the Pod configuration should also match this configuration.<\/p><p>To deploy this configuration, use the following command.<\/p><pre><code class=\"language-bash\">kubectl apply -f ebs-io2-volume.yaml<\/code><\/pre><p>If you check the available <strong>StorageClasses<\/strong>, you will see the new one on the list.<\/p><pre><code class=\"language-bash\">kubectl get storageclass<\/code><\/pre><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\/03\/image-15-11.png\" class=\"kg-image\" alt=\"listing the available storage class of the eks cluster\" loading=\"lazy\" width=\"1000\" height=\"341\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-15-11.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-15-11.png 1000w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>In most cases, we create a Persistent Volume(PV) first, then a Persistent Volume Claim (PVC) to get the required storage from the Persistent Volume. <\/p><p>In this case, we don&#8217;t need PV but directly provision the volume only with a <strong>Persistent volume Claim<\/strong>, which is known as <strong>dynamic provisioning. <\/strong><\/p><h2 id=\"create-persistent-volume-claim\">Create Persistent volume Claim<\/h2><p>Now, we can create a <strong>PersistentVolumeClaim<\/strong> manifest <code>io2-pvc.yaml<\/code> with the required storage size, I am providing 12GB of storage for testing purposes. <\/p><pre><code class=\"language-yaml\">cat &lt;&lt;EOF &gt; io2-pvc.yaml\nkind: PersistentVolumeClaim\napiVersion: v1\nmetadata:\n  name: my-pvc\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: io2-volume\n  resources:\n    requests:\n      storage: 12Gi\nEOF<\/code><\/pre><p>Here, you would have noticed the <strong>accessModes<\/strong> value is <strong>ReadWriteOnce<\/strong>; this means that only one Node (Volume attached node) can read and write on the volume because I have already mentioned that the <strong>EBS volumes are zone-specified<\/strong>.<\/p><p>Various access modes are available, but not every storage type supports all these access modes.<\/p><p>The available access modes are.<\/p><ol><li><strong>ReadWriteOnce<\/strong>: This mode is suitable if only one node performs the read and write in the volume.<\/li><li><strong>ReadOnlyMany<\/strong>: This mode is suitable if many nodes need to read the contents but not to write.<\/li><li><strong>ReadWriteMany<\/strong>: This mode is for both; many nodes can read and write on the volume.<\/li><li><strong>ReadWriteOncePod<\/strong>: This mode is the same as the first one but is not a node; a pod can read and write on the volume.<\/li><\/ol><p>To deploy this configuration, use the following command.<\/p><pre><code class=\"language-bash\">kubectl apply -f io2-pvc.yaml<\/code><\/pre><p>Once the configuration is properly done, we can list the available <strong>PersistentVolumeClaims<\/strong> on our Cluster.<\/p><pre><code class=\"language-bash\">kubectl get pvc<\/code><\/pre><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\/03\/image-16-15.png\" class=\"kg-image\" alt=\"the binding status of the Pvc of the eks cluster\" loading=\"lazy\" width=\"1236\" height=\"280\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-16-15.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-16-15.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-16-15.png 1236w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>This output ensures that the <strong>EBS volume<\/strong> is successfully created. We can also see other details such as capacity, access modes, storage class, etc.<\/p><p>We can see this provisioned volume from the <strong>AWS console<\/strong> as well.<\/p><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\/03\/image-17-11.png\" class=\"kg-image\" alt=\"listing the availabe ebs volumes from the AWS ec2 console. \" loading=\"lazy\" width=\"1453\" height=\"863\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-17-11.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-17-11.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-17-11.png 1453w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>The <strong>EBS<\/strong> volume is in an <strong>Available state<\/strong>, so we can attach this as persistent volumes in the Pods.<\/p><h2 id=\"attach-persistent-volume-to-a-pod\">Attach Persistent Volume to a Pod<\/h2><p>Now lets attach the created volume to a pod and validate it.<\/p><p>For testing purposes, I am creating an Nginx deployment and attaching the <code>\/usr\/share\/nginx\/html<\/code> directory of the container to the EBS volume.<\/p><pre><code class=\"language-yaml\">cat &lt;&lt;EOF &gt; deployment.yaml\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: io2-volume-deployment\n  labels:\n    app: io2-app\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: io2-app\n  template:\n    metadata:\n      labels:\n        app: io2-app\n    spec:\n      containers:\n        - name: io2-container\n          image: nginx:latest\n          ports:\n            - containerPort: 80\n          volumeMounts:\n            - name: io2-volume\n              mountPath: \/usr\/share\/nginx\/html\n      volumes:\n        - name: io2-volume\n          persistentVolumeClaim:\n            claimName: my-pvc\nEOF<\/code><\/pre><pre><code class=\"language-bash\">kubectl apply -f deployment.yaml<\/code><\/pre><p>If we check the EBS volume state in the AWS console after the successful deployment, it will be in use.<\/p><blockquote>When creating the PVC, the EBS volume will be provisioned and when create a Pod with the PVC, the EBS volume will be attached with the node where the Pod is going to run.<\/blockquote><p>This way, we can permanently store the data on the EBS volumes.<\/p><h2 id=\"creating-default-storage-class\">Creating Default Storage Class<\/h2><p>Up to version 1.29, Amazon EKS automatically identified gp2 as its default StorageClass. With EKS 1.30, Amazon stopped specifying a default storage class.<\/p><p>So on any cluster 1.30+, you need to set this up yourself.<\/p><p>To set a storage class as default, you need to explicitly annotate it as the <strong><code>default:storageclass.kubernetes.io\/is-default-class: \"true\"<\/code><\/strong>Only then the unbound PVCs start getting provisioned.<\/p><p>For example, here is the storage class manifest to make gp3 volumes as default storage class.<\/p><pre><code class=\"language-yaml\">apiVersion: storage.k8s.io\/v1\nkind: StorageClass\nmetadata:\n  name: gp3\n  annotations:\n    storageclass.kubernetes.io\/is-default-class: \"true\"\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\nallowVolumeExpansion: true\nparameters:\n  type: gp3\n  fsType: ext4\n  encrypted: \"true\"<\/code><\/pre><h2 id=\"setup-the-ebs-csi-driver-in-existing-eks-cluster\">Setup the EBS CSI Driver in Existing EKS Cluster<\/h2><p>If you have an existing EKS cluster without the <strong>EBS CSI Driver<\/strong> and <strong>Pod Identity Agent<\/strong> plugin for this hands-on, you can install and configure them using the following steps.<\/p><p>Before provisioning the EBS volume in the EKS cluster, we need to set up the <strong>Amazon EBS CSI Driver<\/strong> on the cluster.<\/p><h3 id=\"step-1-check-iam-oidc-provider-integration\">Step 1: Check IAM OIDC Provider Integration<\/h3><blockquote><strong>Note<\/strong>: If OIDC has already been added to your cluster, you can ignore this step.<\/blockquote><p>The EBS CSI driver needs dedicated IAM privileges to provision EBS volumes when requested for PVCs.<\/p><p>However, you can use the <strong>OIDC provider<\/strong> to add IAM Permission to the EKS Pods.<\/p><p>When we create an EKS Cluster, an <strong>OIDC provider ID<\/strong> is also generated.<\/p><p>You can get it from the <strong>Identity Providers<\/strong> section in the IAM portal, as shown below.<\/p><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\/03\/image-3-17.png\" class=\"kg-image\" alt=\"oidc provider id of the eks cluster from the iam console\" loading=\"lazy\" width=\"887\" height=\"607\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-3-17.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-3-17.png 887w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Let&#8217;s list the available clusters in the AWS account, us-west-2 region.<\/p><pre><code class=\"language-bash\">aws eks list-clusters --region us-west-2<\/code><\/pre><p>This will show you the available clusters in the particular region.<\/p><p>Set the <strong>Region<\/strong> and the <strong>Cluster Name<\/strong> as environment variables.<\/p><pre><code class=\"language-bash\">export REGION=us-west-2\nexport CLUSTER_NAME=terraform-eks-cluster-poc<\/code><\/pre><p>Check whether the <strong>IAM OIDC Provider<\/strong> is associated with the cluster or use the following command to associate the <strong>OIDC<\/strong> provider.<\/p><pre><code class=\"language-bash\">eksctl utils associate-iam-oidc-provider --region=$REGION --cluster=$CLUSTER_NAME --approve<\/code><\/pre><p>You will get the prompt <code>IAM Open ID Connect provider is already associated with cluster<\/code> If the OIDC association is already present in the cluster.<\/p><h3 id=\"step-2-install-aws-ebs-csi-driver\">Step 2: Install AWS EBS CSI Driver<\/h3><p>Use the following command to install the EBS CSI Driver on the EKS Cluster.<\/p><pre><code class=\"language-bash\">eksctl create addon --cluster $CLUSTER_NAME --region $REGION --name aws-ebs-csi-driver<\/code><\/pre><p>The <strong>EBS CSI add-on<\/strong> will be created with the necessary permissions, as seen in the AWS Console.<\/p><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\/03\/image-4-15.png\" class=\"kg-image\" alt=\"listing the available addons in the aws eks dashboard\" loading=\"lazy\" width=\"1109\" height=\"857\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-4-15.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-4-15.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-4-15.png 1109w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><blockquote><strong>Important Note: <\/strong>The current IAM permissions are attached to the drivers using the IAM Role for Service Account (IRSA) method. However, the IRSA method is deprecated, so we will use the Pod Identity Agent to assign IAM roles to pods, which will be done in the next step<\/blockquote><p>The IAM Role and Policy will be automatically created for the CSI Driver. As shown below, you can check them from the IAM console.<\/p><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\/03\/image-5-21.png\" class=\"kg-image\" alt=\"the iam role for the ebs csi driver to access the aws services\" loading=\"lazy\" width=\"1091\" height=\"838\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-5-21.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-5-21.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-5-21.png 1091w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>You can view all the permissions if you click the <code>+<\/code> symbol of the Policy.<\/p><p>If you check the <strong>Trust relationships<\/strong>, you will see the following information related to the OIDC.<\/p><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\/03\/image-11-18.png\" class=\"kg-image\" alt=\"the trust relationship of the ebs csi driver iam role\" loading=\"lazy\" width=\"799\" height=\"577\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-11-18.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-11-18.png 799w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>The EBS CSI Driver runs as Pods in the Cluster, so let&#8217;s check the running Pods.<\/p><pre><code class=\"language-bash\">kubectl get pods -n kube-system<\/code><\/pre><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\/03\/image-6-13.png\" class=\"kg-image\" alt=\"the list of available pods of the kube-system namespace including the ebs csi driver controller and driver pods\" loading=\"lazy\" width=\"753\" height=\"591\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-6-13.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-6-13.png 753w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>I have four-node clusters, which is why the four CSI Node Drivers are running.<\/p><p>The <strong>EBS CSI Controller<\/strong> Pods will deploy on any of the Nodes. The <strong>EBS CSI Node Drivers<\/strong> is a <a href=\"https:\/\/devopscube.com\/kubernetes-daemonset\/\">DaemonSet<\/a> and will be available in each worker node.<\/p><p>Now that the <strong>Amazon EBS CSI <\/strong>Plugin has been successfully installed. <\/p><p>we can provision the EBS volumes from the <strong>EKS Cluster.<\/strong><\/p><p>If we describe the EBS CSI Driver&#8217;s Service Account, we can see the annotation of the AWS IAM Role.<\/p><pre><code class=\"language-bash\">kubectl -n kube-system describe sa ebs-csi-controller-sa<\/code><\/pre><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\/03\/image-7-20.png\" class=\"kg-image\" alt=\"the more informations of the ebs csi driver's service account\" loading=\"lazy\" width=\"740\" height=\"386\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-7-20.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-7-20.png 740w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><h3 id=\"step-3-migrate-to-pod-identity\">Step 3: Migrate to Pod Identity<\/h3><p>However, providing AWS IAM Permissions to a Pod using <strong>IRSA<\/strong> is deprecated, so we are migrating this to the <strong>EKS Pod Identity Agent<\/strong>.<\/p><p>First, we need to ensure the <strong>Pod Identity Agent Plugin<\/strong> is installed in the EKS Cluster.<\/p><pre><code class=\"language-bash\">aws eks list-addons --cluster-name $CLUSTER_NAME<\/code><\/pre><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\/03\/image-8-16.png\" class=\"kg-image\" alt=\"the list of available addons of the eks cluster \" loading=\"lazy\" width=\"741\" height=\"364\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-8-16.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-8-16.png 741w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>If the Plugin is not available, install it using the following command.<\/p><pre><code class=\"language-bash\">aws eks create-addon --cluster-name $CLUSTER_NAME --addon-name eks-pod-identity-agent<\/code><\/pre><p>Once the Pod Identity Agent is available, we can migrate everything from <strong>IRSA<\/strong> to <strong>Pod Identity<\/strong>.<\/p><pre><code class=\"language-bash\">eksctl utils migrate-to-pod-identity --cluster $CLUSTER_NAME --approve<\/code><\/pre><p>After the successful migration, we can list the <strong>Pod Identity Associations<\/strong>.<\/p><pre><code class=\"language-bash\">eksctl get podidentityassociation --cluster $CLUSTER_NAME<\/code><\/pre><p>or<\/p><pre><code class=\"language-bash\">aws eks list-pod-identity-associations --cluster-name $CLUSTER_NAME<\/code><\/pre><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\/03\/image-9-16.png\" class=\"kg-image\" alt=\"the list of pod identity associations of the eks cluster. \" loading=\"lazy\" width=\"1280\" height=\"734\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-9-16.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-9-16.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-9-16.png 1280w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Now, we cannot see the annotation in the Service Account.<\/p><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\/03\/image-10-19.png\" class=\"kg-image\" alt=\"the more informations of the ebs csi driver's service account and showing the annotation.\" loading=\"lazy\" width=\"961\" height=\"446\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-10-19.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-10-19.png 961w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>We can see some changes if we check the <strong>Trust relationship<\/strong> of the <strong>IAM Role<\/strong>, which is related to the Pod Identity Agent.<\/p><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\/03\/image-12-14.png\" class=\"kg-image\" alt=\"the updated trust relationship of the ebs csi driver iam role\" loading=\"lazy\" width=\"1074\" height=\"838\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-12-14.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-12-14.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-12-14.png 1074w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>We can even check the add-on&#8217;s update history and ensure the Pod Identity Association is properly configured.<\/p><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\/03\/image-13-16.png\" class=\"kg-image\" alt=\"the update history of the ebs csi driver\" loading=\"lazy\" width=\"1253\" height=\"747\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-13-16.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-13-16.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-13-16.png 1253w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Now the EBS CSI Driver is successfully installed on the existing EKS cluster with the Pod Identity Agent, and is ready to provision the EBS volumes for the EKS cluster.<\/p><h3 id=\"conclusion\">Conclusion<\/h3><p>This will help your EKS Pod data be permanently stored in the EBS volumes and give you an overall idea of the EBS CSI Driver and its configurations.<\/p><p>Choose the appropriate volume type for your workload. Depending on the underlying storage you choose for the persistent storage, some configurations will be changed in the <strong>StorageClass<\/strong> manifest.<\/p><p>Always remember to back up the storage. In EBS, we can take snapshots or use the AWS Backup service to take backups. We can also try third-party backup options.<\/p><p>If you are looking for NFS based storage solution, check out the <a href=\"https:\/\/devopscube.com\/setup-efs-csi-driver-eks\/\" rel=\"noreferrer\">EFS on EKS<\/a> guide for the full setup. <\/p>\n<hr><p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/provsion-persistent-volume-on-eks\/\" target=\"_blank\" rel=\"noopener noreferrer\">How to Provision Persistent Volume on EKS Cluster \u2014 DevOpsCube<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/provsion-persistent-volume-on-eks\/<\/p>\n","protected":false},"author":1,"featured_media":308,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-307","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\/307","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=307"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/307\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/308"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}