{"id":916,"date":"2024-10-25T06:57:22","date_gmt":"2024-10-25T06:57:22","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=916"},"modified":"2024-10-25T06:57:22","modified_gmt":"2024-10-25T06:57:22","slug":"backup-and-restore-eks-cluster-velero","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=916","title":{"rendered":"How To Backup and Restore EKS Cluster Using Velero"},"content":{"rendered":"<p>In this blog, we will look at step by step instructions to backup and restore <a href=\"https:\/\/devopscube.com\/create-aws-eks-cluster-eksctl\/\">EKS cluster<\/a> using Velero in Kubernetes.<\/p><p>We all know the importance of backing up a <a href=\"https:\/\/devopscube.com\/setup-kubernetes-cluster-kubeadm\/\">Kubernetes cluster<\/a>. There are several solutions are available for Kubernetes cluster backup and restoration.<\/p><p>However, Velero stands out because it can back up both cluster resources and the storage associated with the cluster.<\/p><p>When backing up a cluster, there are two key aspects to keep in mind:<\/p><ol><li><a href=\"https:\/\/devopscube.com\/backup-etcd-restore-kubernetes\/\">ETCD key-value store<\/a> that contains all the cluster-related configuration information.<\/li><li>Persistent storage solutions hold your applications&#8217; data running inside the cluster.<\/li><\/ol><p>So, when performing a backup, both should be included.<\/p><p>To store the backup, I am using Amazon S3, a storage service from AWS.<\/p><h3 id=\"prerequisites\">Prerequisites<\/h3><ol><li>EKS Cluster (v1.31)<\/li><li>EKSCTL (v0.191.0) should be available on the local machine<\/li><li>Kubectl (v1.31.0) should be available on the local machine<\/li><li>AWS CLI (v2.18.10) should be available on the local machine and configured with the required permissions.<\/li><li>Helm (v3.16.1) should be available on your local system.<\/li><\/ol><h2 id=\"velero-backup-workflow\">Velero Backup Workflow<\/h2><p>The following image shows Velero&#8217;s high-level workflow.<\/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\/velero-v2-1.gif\" class=\"kg-image\" alt=\"velero workflow diagram for the aws eks cluster and the components includes such as velero containers, pod identity agent, aws s3 and ebs.\" loading=\"lazy\" width=\"800\" height=\"783\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/velero-v2-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/velero-v2-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 Velero CLI is on the local machine, which can help initiate the backup\/restore using CLI commands.<\/li>\n\n\n<li>The request will go through the Kubernetes API server to the Velero Pod, and the Velero Pod contains the Init Container, which is for the AWS scoped plugin for Velero and has the main Velero container.<\/li>\n\n\n<li>The Init container provides the AWS-specific files to the main container before it starts. <\/li>\n\n\n<li>Both containers get the AWS temporary credentials via Pod Identity Agent to access the AWS services. <\/li>\n\n\n<li>The main container keeps watching the Velero Custom Resource Definitions (CRDs). If any changes happen on those resources, the Velero raises API calls to the Kubernetes API to make the changes. \n<ul class=\"wp-block-list\">\n<li><strong>Backup<\/strong><\/li>\n\n\n<li><strong>Restore<\/strong><\/li>\n\n\n<li><strong>Schedule<\/strong><\/li>\n\n\n<li><strong>BackupStorageLocation<\/strong><\/li>\n\n\n<li><strong>VolumeSnapshotLocation<\/strong><\/li>\n<\/ul>\n<\/li>\n\n\n<li>Velero creates the EBS Volume Snapshots for the Persistent Volume Claim (PVC) and upload the backup data &amp; metadata to the S3 bucket.<\/li>\n<\/ol>\n<!--kg-card-end: html-->\n<h2 id=\"setup-velero-in-an-eks-cluster\">Setup Velero in an EKS Cluster<\/h2><p>Follow the steps given below to set up the Velero in EKS Cluster.<\/p><h3 id=\"step-1-create-an-s3-bucket\">Step 1: Create an S3 Bucket<\/h3><p>We need a storage solution to back up the cluster components using Velero; for now, we are using <strong>AWS S3<\/strong> as the storage option.<\/p><p>To create an S3 bucket, use the following CLI command or use GUI to create one.<\/p><pre><code>BUCKET_NAME=\"velero-k8s-backup-bucket\"\nREGION=us-west-2\naws s3 mb s3:\/\/${BUCKET_NAME} --region ${REGION}<\/code><\/pre><p>Check that the bucket is created with the appropriate settings.<\/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-33-7.png\" class=\"kg-image\" alt=\"aws s3 bucket to store the velero backup data\" loading=\"lazy\" width=\"1025\" height=\"654\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-33-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-33-7.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-33-7.png 1025w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>I have created a simple S3 bucket with the default settings for the demo purpose, but you can customize the configuration with appropriate permissions.<\/p><h3 id=\"step-2-create-an-iam-policy-for-velero\">Step 2: Create an IAM Policy for Velero<\/h3><p>We need to create an <strong>IAM Policy <\/strong>with the required permissions because Velero should communicate with other AWS services for use cases such as taking snapshots of the EBS volumes and storing other cluster components&#8217; data on S3.<\/p><p>Use the following <strong>permissions<\/strong> to create the <strong>IAM Policy.<\/strong><\/p><pre><code>cat &lt;&lt; EOF | envsubst &gt; velero_policy.json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n      {\n          \"Effect\": \"Allow\",\n          \"Action\": [\n              \"ec2:DescribeVolumes\",\n              \"ec2:DescribeSnapshots\",\n              \"ec2:CreateTags\",\n              \"ec2:CreateVolume\",\n              \"ec2:CreateSnapshot\",\n              \"ec2:DeleteSnapshot\"\n          ],\n          \"Resource\": \"*\"\n      },\n      {\n          \"Effect\": \"Allow\",\n          \"Action\": [\n              \"s3:GetObject\",\n              \"s3:DeleteObject\",\n              \"s3:PutObject\",\n              \"s3:AbortMultipartUpload\",\n              \"s3:ListMultipartUploadParts\"\n          ],\n          \"Resource\": [\n              \"arn:aws:s3:::${BUCKET_NAME}\/*\"\n          ]\n      },\n      {\n          \"Effect\": \"Allow\",\n          \"Action\": [\n              \"s3:ListBucket\"\n          ],\n          \"Resource\": [\n              \"arn:aws:s3:::${BUCKET_NAME}\"\n          ]\n      }\n  ]\n}\nEOF<\/code><\/pre><p>The IAM Policy will be created with the S3 Bucket name, so provide your Bucket name properly.<\/p><p>Once the JSON file is created, we can create the <strong>IAM Policy<\/strong> using the following command.<\/p><pre><code>export POLICY_NAME=VeleroAccessPolicy<\/code><\/pre><pre><code>aws iam create-policy \\\n    --policy-name $POLICY_NAME \\\n    --policy-document file:\/\/velero_policy.json<\/code><\/pre><p>Once the IAM Policy is created, you can see the details in the output.<\/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-34-7.png\" class=\"kg-image\" alt=\"aws iam policy creation for the velero\" loading=\"lazy\" width=\"920\" height=\"412\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-34-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-34-7.png 920w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>To get the ARN of the created IAM Policy.<\/p><pre><code>export POLICY_ARN=$(aws iam list-policies --query \"Policies[?PolicyName=='$POLICY_NAME'].Arn\" --output text)<\/code><\/pre><p>We can use the AWS IAM console to ensure that the <strong>IAM policy<\/strong> is created.<\/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-35-10.png\" class=\"kg-image\" alt=\"aws iam policy permissions for the velero pod\" loading=\"lazy\" width=\"1022\" height=\"822\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-35-10.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-35-10.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-35-10.png 1022w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>The <strong>IAM Policy<\/strong> is ready, so we have to create an <strong>IAM Role <\/strong>with it. Then, we can attach it to the <strong>Velero Pod<\/strong>.<\/p><h3 id=\"step-3-create-an-iam-role-for-velero\">Step 3: Create an IAM Role for Velero<\/h3><p>First, we need to create a Trust Relationship JSON file for the Role.<\/p><pre><code>cat &lt;&lt;EOF &gt; trust-policy.json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"Service\": \"pods.eks.amazonaws.com\"\n      },\n      \"Action\": [\n        \"sts:AssumeRole\",\n        \"sts:TagSession\"\n      ]\n    }\n  ]\n}\nEOF<\/code><\/pre><p>We will use the <strong>EKS Pod Identity Agent<\/strong> to provide the IAM Credentials to the Velero Pods to access the AWS services.<\/p><p>Create an IAM Role with the Trust Policy; use the following command.<\/p><pre><code>export ROLE_NAME=VeleroAccessRole<\/code><\/pre><pre><code>aws iam create-role \\\n    --role-name $ROLE_NAME \\\n    --assume-role-policy-document file:\/\/trust-policy.json<\/code><\/pre><p>If the IAM Role is successfully created, you can see the following output.<\/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-36-8.png\" class=\"kg-image\" alt=\"the IAM role creation for the velero kubernetes pod\" loading=\"lazy\" width=\"919\" height=\"645\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-36-8.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-36-8.png 919w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Now, we need to attach the <strong>IAM Role<\/strong> <code>VeleroAccessRole<\/code> to the <strong>IAM Policy<\/strong> <code>VeleroAccessPolicy<\/code>.<\/p><pre><code>aws iam attach-role-policy \\\n    --role-name $ROLE_NAME \\\n    --policy-arn $POLICY_ARN<\/code><\/pre><p>We can check the IAM Role on the console after attaching it with the IAM Policy.<\/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-37-9.png\" class=\"kg-image\" alt=\"the aws iam role permissions for the velero pod\" loading=\"lazy\" width=\"1100\" height=\"713\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-37-9.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-37-9.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-37-9.png 1100w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>We can check the Trust Relationship 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-38-7.png\" class=\"kg-image\" alt=\"aws iam trust relationship for the velero iam role\" loading=\"lazy\" width=\"1118\" height=\"842\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-38-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-38-7.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-38-7.png 1118w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Use the following command to store the Role ARN as an environment variable for the upcoming configuration.<\/p><pre><code>export ROLE_ARN=$(aws iam get-role --role-name $ROLE_NAME --query \"Role.Arn\" --output text)<\/code><\/pre><h3 id=\"step-4-pod-identity-association\">Step 4: Pod Identity Association<\/h3><p>Before the Identity association, we need to create a Namespace and Service Account on the EKS Cluster for the Velero.<\/p><p>Follow the below commands to create Namespace and Service Account<\/p><pre><code>export NAMESPACE=velero\nexport SERVICE_ACCOUNT=velero-server<\/code><\/pre><pre><code>kubectl create ns $NAMESPACE\nkubectl -n $NAMESPACE create sa $SERVICE_ACCOUNT<\/code><\/pre><p>To list the available Namespaces<\/p><pre><code>kubectl get ns<\/code><\/pre><p>To list the Service Account in the particular Namespace.<\/p><pre><code>kubectl -n $NAMESPACE get sa<\/code><\/pre><p>Before performing the Pod Identity Association, we need to create the Cluster name as an environment variable and ensure that the Pod Identity Agent is present in the cluster.<\/p><p>To list the available EKS clusters.<\/p><pre><code>aws eks list-clusters --region ${REGION}<\/code><\/pre><p>To create a cluster name as an environment variable<\/p><pre><code>export CLUSTER_NAME=eks-cluster-poc<\/code><\/pre><p>To list the available addons in the cluster.<\/p><pre><code>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-39-7.png\" class=\"kg-image\" alt=\"the list of addons available in 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-39-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-39-7.png 741w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Use the following command if the Pod Identity Agent is unavailable in the cluster.<\/p><pre><code>aws eks create-addon --cluster-name $CLUSTER_NAME --addon-name eks-pod-identity-agent<\/code><\/pre><p>The Service Account is ready; we can perform the Pod Identity Association.<\/p><pre><code>eksctl create podidentityassociation \\\n    --cluster $CLUSTER_NAME \\\n    --namespace $NAMESPACE \\\n    --service-account-name $SERVICE_ACCOUNT \\\n    --role-arn $ROLE_ARN<\/code><\/pre><p>After the successful association, we can list the <strong>Pod Identity Associations<\/strong>.<\/p><pre><code>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-40-5.png\" class=\"kg-image\" alt=\"the pod identity association for the velero pod\" loading=\"lazy\" width=\"1155\" height=\"552\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-40-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-40-5.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-40-5.png 1155w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>This ensures the Pod Identity Association is properly done to the Velero Service Account.<\/p><h3 id=\"step-5-install-velero-on-eks-cluster\">Step 5: Install Velero on EKS Cluster<\/h3><p>We will use the Helm Chart to deploy the Velero in the Kubernetes cluster.<\/p><p>First, we need to add the Velero repo using Helm<\/p><pre><code>helm repo add vmware-tanzu https:\/\/vmware-tanzu.github.io\/helm-charts<\/code><\/pre><p>We need <code>values.yaml<\/code> file to know what changes we can make as per our requirements.<\/p><pre><code>helm search repo vmware-tanzu<\/code><\/pre><p>The output will provide the name of the chart and other details.<\/p><p>To get the values, we need the Chart name.<\/p><pre><code>helm show values vmware-tanzu\/velero<\/code><\/pre><p>This will show you all the available values we can use to modify the configuration for the Velero deployment.<\/p><p>We can take the entire output as a file, or we can copy only the necessary values to create a new <code>values.yaml<\/code> file.<\/p><p>For this tutorial, I am taking only the necessary information from the output and creating a new YAML file.<\/p><p>We need to set an environment variable for the provider; in our case, the provider is AWS.<\/p><pre><code>export PROVIDER=aws<\/code><\/pre><pre><code>cat &lt;&lt; EOF | envsubst &gt; dev-values.yaml\ninitContainers:\n  - name: velero-plugin-for-aws\n    image: velero\/velero-plugin-for-aws:v1.10.0\n    imagePullPolicy: IfNotPresent\n    volumeMounts:\n      - mountPath: \/target\n        name: plugins\n\nconfiguration:\n  backupStorageLocation:\n    - provider: ${PROVIDER}\n      bucket: ${BUCKET_NAME}\n      config: \n        region: ${REGION}\n  volumeSnapshotLocation:\n    - provider: ${PROVIDER}\n      config: \n        region: ${REGION}\n\nserviceAccount: \n  server:\n    create: false\n    name: ${SERVICE_ACCOUNT}\n\ncredentials:\n  useSecret: false\nEOF<\/code><\/pre><p>Ensure the <strong>S3 Bucke<\/strong>t name and other details are properly placed in the YAML file.<\/p><p>To install the Velero using the Helm chart, use the following command.<\/p><pre><code>helm install velero vmware-tanzu\/velero \\\n    --namespace velero \\\n    -f dev-values.yaml<\/code><\/pre><p>If the deployment is completed, we can see the following output.<\/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-42-5.png\" class=\"kg-image\" alt=\"the velero helm deployment success message\" loading=\"lazy\" width=\"1418\" height=\"689\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-42-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-42-5.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-42-5.png 1418w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>The Velero has been deployed, and we have to check what objects are created within.<\/p><pre><code>kubectl -n ${NAMESPACE} get all<\/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-43-7.png\" class=\"kg-image\" alt=\"the velero deployment components list and status\" loading=\"lazy\" width=\"1115\" height=\"523\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-43-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-43-7.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-43-7.png 1115w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Describing the Pod will give more detailed information.<\/p><pre><code>kubectl -n ${NAMESPACE} describe po &lt;POD NAME&gt;<\/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-44-5.png\" class=\"kg-image\" alt=\"the detailed informations of the velero pod\" loading=\"lazy\" width=\"1259\" height=\"876\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-44-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-44-5.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-44-5.png 1259w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Here, we can see how the <strong>Pod Identity Agent<\/strong> provides the Velero Pod with <strong>temporary AWS credentials<\/strong> to access the other AWS services.<\/p><p>We will perform the <strong>Backup<\/strong>, <strong>Restore<\/strong>, and <strong>Schedule<\/strong> using its <strong>Custom Resource Definitions<\/strong>, so let&#8217;s list the available CRDs.<\/p><pre><code>kubectl -n ${NAMESPACE} get crds | grep velero<\/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-45-7.png\" class=\"kg-image\" alt=\"the list of velero custom resource definitions of the velero\" loading=\"lazy\" width=\"935\" height=\"469\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-45-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-45-7.png 935w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>When we install Velero, we provide our <strong>backup storage <\/strong>and <strong>volume snapshot location, <\/strong>which will act as a default configuration.<\/p><p>But we can even configure it after the installation using <strong>Custom Resources<\/strong>, which are <code>kind: BackupStorageLocation<\/code> and <code>kind: VolumeSnapshotLocation<\/code> manifests.<\/p><h3 id=\"step-6-install-velero-cli\">Step 6: Install Velero CLI<\/h3><p>We will install the Velero CLI utility on our local machine.<\/p><p>For Linux, use the following command.<\/p><pre><code>curl -L https:\/\/github.com\/vmware-tanzu\/velero\/releases\/download\/v1.14.1\/velero-v1.14.1-linux-amd64.tar.gz -o velero.tar.gz\ntar -zxvf velero.tar.gz\nsudo mv velero-v1.14.1-linux-amd64\/velero \/usr\/local\/bin\/<\/code><\/pre><p>For macOS, use the following command.<\/p><pre><code>brew install velero<\/code><\/pre><p>Check the version and ensure the Velero CLI is installed.<\/p><pre><code>velero version<\/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-41-5.png\" class=\"kg-image\" alt=\"the locally installed version of the velero cli\" loading=\"lazy\" width=\"961\" height=\"509\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-41-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-41-5.png 961w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><h2 id=\"backing-up-cluster-using-velero\"><strong>Backing Up Cluster Using Velero<\/strong><\/h2><h3 id=\"manual-backup-method\">Manual Backup Method<\/h3><p>In Velero, we can <strong>manually<\/strong> take Backups or <strong>automate<\/strong> the process by scheduling.<\/p><p>The Backup and Restore operations we are going to perform using the <strong>Custom Resource Definitions (CRDs)<\/strong><\/p><p>But before that, I will deploy a demo <strong>Deployment<\/strong> to test the setup.<\/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-46-7.png\" class=\"kg-image\" alt=\"the demo deployment components to test the velero\" loading=\"lazy\" width=\"1455\" height=\"735\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-46-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-46-7.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-46-7.png 1455w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>I have deployed a <strong>MySQL StatefulSet<\/strong> with a <strong>Persistent Volume. <\/strong>The manifest repo is attached if you want to replicate the same setup.<\/p><pre><code>git clone https:\/\/github.com\/kubernetes-learning-projects\/mysql-statefulset.git<\/code><\/pre><p>Velero can back up the entire cluster, but it is also possible to Back up only particular objects.<\/p><p>First, I manually back up the whole cluster, and for that, we execute a command from our local machine using the Velero CLI.<\/p><pre><code>velero backup create test-backup<\/code><\/pre><p>Instead of using the command, we can create a Backup Custom Resource manifest to take backups.<\/p><pre><code>apiVersion: velero.io\/v1\nkind: Backup\nmetadata:\n  name: manual-backup\n  namespace: velero\nspec:\n  includedNamespaces:\n  - '*'\n  excludedNamespaces:\n  - kube-system\n  includedResources:\n  - '*'\n  excludedResources:\n  - storageclasses.storage.k8s.io\n  includeClusterResources: null\n  labelSelector:\n    matchLabels:\n      app: velero\n      component: server\n  snapshotVolumes: null\n  storageLocation: aws-primary\n  volumeSnapshotLocations:\n    - aws-primary\n    - gcp-primary\n  ttl: 24h0m0s\n  defaultVolumesToRestic: true<\/code><\/pre><p>Creating a manifest will give more flexibility to make modifications to the configuration, but this time, we are using a CLI command to take a backup.<\/p><p>To describe the Backup, use the following command.<\/p><pre><code>velero backup describe test-backup<\/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-47-5.png\" class=\"kg-image\" alt=\"the detailed information of the backup custom resource\" loading=\"lazy\" width=\"776\" height=\"916\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-47-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-47-5.png 776w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>The <strong>default validity<\/strong> of a Backup is <strong>30 days,<\/strong> but we can adjust that with the help of <code>--default-backup-ttl<\/code> flag.<\/p><p>Velero can snapshot the Node volumes on AWS only in the same regions.<\/p><p>To list the available backups.<\/p><pre><code>kubectl -n velero get backup<\/code><\/pre><p>Velero has taken a snapshot of the EBS volume and stored the other backup data in the S3 bucket.<\/p><p>First, we can check the snapshot of the EBS volume from 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-48-5.png\" class=\"kg-image\" alt=\"the ebs snapshot list created by the velero\" loading=\"lazy\" width=\"1616\" height=\"852\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-48-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-48-5.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/image-48-5.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-48-5.png 1616w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>To view the other object&#8217;s Backup, we have to look at S3.<\/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-49-3.png\" class=\"kg-image\" alt=\"the list of collected backup data in s3 by the velero \" loading=\"lazy\" width=\"1047\" height=\"861\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-49-3.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-49-3.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-49-3.png 1047w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>This ensures that the Cluster&#8217;s object information and the volume snapshot are successfully backed up.<\/p><h2 id=\"restoring-the-cluster-using-velero\">Restoring the Cluster Using Velero<\/h2><p>To test the Restoring process, I intentionally deleted the MySQL StatefulSet.<\/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-50-7.png\" class=\"kg-image\" alt=\"the velero restored resources details.\" loading=\"lazy\" width=\"1083\" height=\"576\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-50-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-50-7.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-50-7.png 1083w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Now, I am restoring from the previous Backup, and when we perform Restore, it won&#8217;t delete existing objects or resources on the cluster.<\/p><p>If the data is already in the cluster, the process will skip that part.<\/p><pre><code>velero restore create test-restore --from-backup test-backup<\/code><\/pre><p>The Restoring process is completed, but if you are Restoring it to another cluster, the API Server version should be the same as the source cluster.<\/p><pre><code>velero restore describe test-restore<\/code><\/pre><p>or<\/p><pre><code>kubectl -n velero describe restore test-restore<\/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-51-6.png\" class=\"kg-image\" alt=\"the detailed information of the velero restore object\" loading=\"lazy\" width=\"954\" height=\"895\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-51-6.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-51-6.png 954w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>This will completely Restore the cluster. In Velero, you can also migrate your entire cluster to another Region.<\/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-52-4.png\" class=\"kg-image\" alt=\"the restored resources list on the terminal by the velero\" loading=\"lazy\" width=\"1016\" height=\"458\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-52-4.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-52-4.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-52-4.png 1016w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><h3 id=\"automatic-backup-method\">Automatic Backup Method<\/h3><p>We can schedule our Backup process, so then, without human intervention, we can conduct periodical Backups.<\/p><p>If you don&#8217;t want the entire cluster to be Backed up but want some specific objects to be Backed up, we can do that, too, with the help of Velero.<\/p><h3 id=\"step-1-create-a-backup-storage-location\">Step 1: Create a Backup Storage Location<\/h3><p>First, we are creating the BackupStorageLocation Custom Resource manifest to provide the backup storage configuration. We already provided the backup storage location in the Velero installation time, but that is the default one.<\/p><p>The default configuration will work if you do not create any resources for the backup storage and volume snapshot.<\/p><pre><code>cat &lt;&lt; EOF | envsubst &gt; backup-storage-location.yaml\napiVersion: velero.io\/v1\nkind: BackupStorageLocation\nmetadata:\n  name: custom-bsl\n  namespace: velero\nspec:\n  backupSyncPeriod: 2m0s\n  accessMode: ReadWrite\n  provider: ${PROVIDER}\n  objectStorage:\n    bucket: ${BUCKET_NAME}\n    prefix: custom-bsl\n  config:\n    region: ${REGION}\nEOF<\/code><\/pre><pre><code>kubectl apply -f backup-storage-location.yaml<\/code><\/pre><p>To list the Backup Storage Locations.<\/p><pre><code>kubectl -n velero get backupstoragelocations<\/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-53-2.png\" class=\"kg-image\" alt=\"the list of the velero backup storage location resource\" loading=\"lazy\" width=\"961\" height=\"439\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-53-2.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-53-2.png 961w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><h3 id=\"step-2-create-a-volume-snapshot-location\">Step 2: Create a Volume Snapshot Location<\/h3><p>We need to create a VolumeSnapshotLocation custom resource manifest for the volume snapshot configuration.<\/p><pre><code>cat &lt;&lt; EOF | envsubst &gt; volume-snapshot-location.yaml\napiVersion: velero.io\/v1\nkind: VolumeSnapshotLocation\nmetadata:\n  name: custom-vsl\n  namespace: velero\nspec:\n  provider: ${PROVIDER}\n  config:\n    region: ${REGION}\nEOF<\/code><\/pre><pre><code>kubectl apply -f volume-snapshot-location.yaml<\/code><\/pre><p>To list the available Volume Snapshot Locations.<\/p><pre><code>kubectl -n velero get volumesnapshotlocations<\/code><\/pre><h3 id=\"step-3-create-a-backup-schedule\">Step 3: Create a Backup Schedule<\/h3><p>Here, I am creating a Velero <code>schedule<\/code> Custom Resource Manifest to Backup all objects from a particular <strong>Namespace.<\/strong><\/p><pre><code>cat &lt;&lt; EOF &gt; scheduled-backup.yaml\napiVersion: velero.io\/v1\nkind: Schedule\nmetadata:\n  name: scheduled-backup\n  namespace: velero\nspec:\n  schedule: \"0\/5 * * * *\"\n  template:\n    includedNamespaces:\n    - \"default\"\n    includedResources:\n    - \"secrets\"\n    storageLocation: \"custom-bsl\"\n    volumeSnapshotLocations:\n    - \"custom-vsl\"\nEOF<\/code><\/pre><p>This manifest will take a Backup of all <strong>Secrets<\/strong> objects only from the <code>default<\/code> <strong>Namespace<\/strong> in <strong>every 5 minutes.<\/strong><\/p><p>Before we schedule the backup, list the available secrets in the default namespace.<\/p><pre><code>kubectl get secrets<\/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-54-8.png\" class=\"kg-image\" alt=\"the availabe secrets list in the default namespace\" loading=\"lazy\" width=\"963\" height=\"383\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-54-8.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-54-8.png 963w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>The parameters of the Backup CRD and the Schedule CRD are almost the same.<\/p><pre><code>kubectl apply -f scheduled-backup.yaml<\/code><\/pre><p>Scheduled Backups will be saved with a <strong>timestamp. <\/strong>For more about the parameters, please refer to the <a href=\"https:\/\/velero.io\/docs\/v1.13\/api-types\/backup\/?ref=devopscube.com\">official documentation<\/a>.<\/p><p>After waiting some time, we can list the backups.<\/p><pre><code>kubectl -n velero get backup<\/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-56-7.png\" class=\"kg-image\" alt=\"the list of backups taken by the velero\" loading=\"lazy\" width=\"864\" height=\"578\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-56-7.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-56-7.png 864w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>We can see that each backups are created in the 5-minute intervals.<\/p><p>We can check this to the S3 bucket 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-58-5.png\" class=\"kg-image\" alt=\"the available scheduled backup list on the aws s3\" loading=\"lazy\" width=\"1074\" height=\"761\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-58-5.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-58-5.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-58-5.png 1074w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>I am deleting the Secret object from the default Namespace for testing purposes.<\/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-57-4.png\" class=\"kg-image\" alt=\"the secret delete message to check the velero demo\" loading=\"lazy\" width=\"1090\" height=\"608\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-57-4.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-57-4.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-57-4.png 1090w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>Now, we know that the Secret is deleted from the <code>default<\/code> Namespace.<\/p><p>We have a backup and restore this, but we are restoring these resources in a new namespace.<\/p><h3 id=\"step-4-configure-restore\">Step 4: Configure Restore<\/h3><p>First, I am creating a new Namespace <code>restore-secrets<\/code><\/p><pre><code>kubectl create ns restore-secrets<\/code><\/pre><p>When we perform Backup and Restore, we can exclude objects, too.<\/p><pre><code>cat &lt;&lt; EOF &gt; restore.yaml\napiVersion: velero.io\/v1\nkind: Restore\nmetadata:\n  name: my-daily-backup-restore\n  namespace: velero\nspec:\n  backupName: scheduled-backup-20241012065006\n  includedNamespaces:\n    - default\n  # excludedResources:\n  #   - \"Pods\"\n  # restorePVs: true\n  namespaceMapping:\n    default: restore-secrets\nEOF<\/code><\/pre><p>In <code>spec.namespaceMapping<\/code> section, on the left side, we provide the <strong>Backup from Namespace<\/strong> and on the right side, <strong>Restore to Namespace<\/strong> to migrate the objects from one Namespace to another.<\/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-59-6.png\" class=\"kg-image\" alt=\"the velero restored secrets list in the new namespace\" loading=\"lazy\" width=\"1123\" height=\"385\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/image-59-6.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/image-59-6.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/image-59-6.png 1123w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure><p>If you want to delete the backup data, you should clean up the EBS snapshots created by Velero from the EC2 dashboard and need to clean the S3 bucket data.<\/p><h2 id=\"conclusion\">Conclusion<\/h2><p>This is a high-level overview of the Velero and a hands-on. You can do more with this utility because Velero gives more flexibility when backing up the cluster.<\/p><p>To store backups, try different storage solutions at your convenience. To learn more about Velero, try all the Custom Resource definitions; please refer to the <a href=\"https:\/\/velero.io\/docs\/v1.8\/api-types\/?ref=devopscube.com\">official documentation<\/a>.<\/p>\n<hr><p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/backup-and-restore-eks-cluster-velero\/\" target=\"_blank\" rel=\"noopener noreferrer\">How To Backup and Restore EKS Cluster Using Velero \u2014 DevOpsCube<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/backup-and-restore-eks-cluster-velero\/<\/p>\n","protected":false},"author":1,"featured_media":917,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-916","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\/916","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=916"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/916\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/917"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=916"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=916"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=916"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}