Backup and Restore Stateful App with Static IP for Load Balancer Service (CSI Edition)

Page last updated:

This topic describes how to use Velero to backup and restore a stateful application with a load balancer service with a static IP address.


This topic describes how to use Velero to backup and restore a Kubernetes stateful application with a service of type load balancer that uses a static IP address.

The application used to demonstrate Velero backup and restore with fixed IP is the Wordpress stateful app. By design Wordpress stores in its data structure the original IP address that was used during its initial launch. To successfully restore from backup a Wordpress app, the service of type load balancer must be deployed with a fixed IP address. This ensures the same IP will be used when a Velero restore is performed.


Install and configure Minio, Velero, and Restic.

Download the Wordpress app YAML files to a local known directory:

  • mysql-deployment.yaml
  • wordpress-deployment.yaml

Configure Wordpress YAML Files

Edit the wordpress-deployment.yaml to include the static IP for the load balancer (loadBalancerIP: IP). In this example, the IP address used is taken from the NSX-T floating IP pool that is resourced for TKGI.

apiVersion: v1
kind: Service
  name: wordpress
    app: wordpress
    - port: 80
    app: wordpress
    tier: frontend
  type: LoadBalancer

Create the kustomization.yaml file` with a value for YOUR_PASSWORD:

- name: mysql-pass
  - password=YOUR_PASSWORD
  - mysql-deployment.yaml
  - wordpress-deployment.yaml

Create the default storage class YAML default-sc.yaml:

kind: StorageClass
  name: default-sc
  annotations: "true"
    diskformat: thin

Apply the storage class YAML file:

kubectl apply -f 0-default-sc.yaml created

Verify the storage class:

kubectl get sc

default-sc (default)   Delete          Immediate           false                  3m38s

Deploy Wordpress App

Create Wordpress namespace:

kubectl create ns wordpress-lbstaticip

namespace/wordpress-lbstaticip created

Deploy the Wordpress app:

kubectl apply -k . -n wordpress-lbstaticip
secret/mysql-pass-c57bb4t7mf created
service/wordpress-mysql created
service/wordpress created
deployment.apps/wordpress-mysql created
deployment.apps/wordpress created
persistentvolumeclaim/mysql-pv-claim created
persistentvolumeclaim/wp-pv-claim created

Verify Wordpress app deployment:

kubectl get all -n wordpress-lbstaticip
kubectl get pvc,pv -n wordpress-lbstaticip

Access the Wordpress app at Use the static IP you set for the load balancer.

Wordpress App

Create a user and log in.

Wordpress Interface

Create blog post.

Wordpress Blog

Publish the blog.

<img src="images/backup-restore/wordpress-04.png" alt="Wordpress Blog" width="538">

Backup the Wordpress App Using Namespace

Because the Wordpress app is stateful, add annotations for the stateful pods with the volume name.

From wordpress-deployment.yaml, the volume name is wordpress-persistent-storage.

From mysql-deployment.yaml the volume name is mysql-persistent-storage.

Get the pod names:

kubectl get pod -n wordpress-lbstaticip

Annotate the pods:

kubectl -n wordpress-lbstaticip annotate pod/wordpress-675699f695-f5zdl
pod/wordpress-675699f695-f5zdl annotated

kubectl -n wordpress-lbstaticip annotate pod/wordpress-mysql-69dcc4fc49-zpjrd
pod/wordpress-mysql-69dcc4fc49-zpjrd annotated

Verify the annotations:

kubectl -n wordpress-lbstaticip describe pod wordpress-675699f695-f5zdl | grep Annotations
Annotations: wordpress-persistent-storage

kubectl -n wordpress-lbstaticip describe pod wordpress-mysql-69dcc4fc49-zpjrd | grep Annotations
Annotations: mysql-persistent-storage

Perform the Velero backup:

velero backup create wordpress-lbstaticip-backup --include-namespaces wordpress-lbstaticip

Backup request "wordpress-lbstaticip-backup" submitted successfully.
Run `velero backup describe wordpress-lbstaticip-backup` or `velero backup logs wordpress-lbstaticip-backup` for more details.

Verify the backup that was created.

velero backup get

NAME                          STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
wordpress-lbstaticip-backup   Completed   0        0          2020-07-24 11:35:46 -0700 PDT   29d       default            <none>

Verify backup details:

velero backup describe wordpress-lbstaticip-backup --details

Use Velero CRD commands to further verify the backup:

kubectl get crd
kubectl get -n velero
kubectl describe wordpress-lbstaticip-backup -n velero

Restore the Wordpress App

To test the restoration of the Wordpress app, delete it.

Delete the namespace:

kubectl delete ns wordpress-lbstaticip

namespace "wordpress-lbstaticip" deleted

Verify namespace deletion:

kubectl get ns
kubectl get pvc,pv --all-namespaces

Make sure the storage class used by the application is still present:

kubectl get sc

Restore the Wordpress app:

velero restore create --from-backup wordpress-lbstaticip-backup

Restore request "wordpress-lbstaticip-backup-20200724114046" submitted successfully.
Run `velero restore describe wordpress-lbstaticip-backup-20200724114046` or `velero restore logs wordpress-lbstaticip-backup-20200724114046` for more details.

Verify that the Wordpress app is restored:

velero restore get
NAME                                         BACKUP                        STATUS      ERRORS   WARNINGS   CREATED                         SELECTOR
wordpress-lbstaticip-backup-20200724114046   wordpress-lbstaticip-backup   Completed   0        0          2020-07-24 11:40:46

Verify restoration details:

velero restore describe wordpress-lbstaticip-backup-20200724114046

Name:         wordpress-lbstaticip-backup-20200724114046
Namespace:    velero
Labels:       <none>
Annotations:  <none>

Phase:  Completed

Backup:  wordpress-lbstaticip-backup

  Included:  all namespaces found in the backup
  Excluded:  <none>

  Included:        *
  Excluded:        nodes, events,,,,
  Cluster-scoped:  auto

Namespace mappings:  <none>

Label selector:  <none>

Restore PVs:  auto

Restic Restores (specify --details for more information):
  Completed:  2

Verify the Wordpress namespace:

kubectl get ns
NAME                   STATUS   AGE
default                Active   16d
kube-node-lease        Active   16d
kube-public            Active   16d
kube-system            Active   16d
pks-system             Active   16d
velero                 Active   2d21h
wordpress-lbstaticip   Active   68s

Check for all Wordpress objects in the namespace:

kubectl get all -n wordpress-lbstaticip

Verify persistent volume for Wordpress:

kubectl get pvc,pv -n wordpress-lbstaticip

Access the Wordpress blog at Use the static IP you set for the load balancer.

Wordpress Blog


Key takeaways from the Velero backup and restore operation for this type of application:

  • Pod annotation is still required for Velero backup of PV
  • The namespace ‘wordpress-lbstaticip’ was automatically re-created
  • The K8s SVC LB IP has been preserved as expected

Please send any feedback you have to