Backup

Couchbase Backup / Restore in K8s Environment

1. Introduction

Periodic backup of data is an important part of any production database deployment, which helps ensure data recovery in the event of a disaster and it also minimizes data inconsistency when a restore is required.

Couchbase provides cbbackupmgr utility that has been improved over the years to become an enterprise-grade Backup and Restore tool to backup large data sets with much higher performance therefore we recommend this tool to be used in the production. It is worth mentioning that in Couchbase Server 6.5 we have overhauled the backup-storage engine completely, and introduced higher compression ratio, which has resulted in much improved backup-restore performance and reduced storage requirements for each backup snapshot, resulting in cost saving.


2. Best Practice

Although cbbackupmgr exists under Couchbase_HOME, it is not recommended to run this utility from any of the active nodes in the cluster. As it would be competing for resources of active requests and could potentially hamper the performance of your database system.

It is, therefore, a best practice to provide a separate instance (for backup and restore needs) with only the Couchbase binaries installed but no Couchbase services running, so resources can be better managed for both the database cluster and the backup node.

Backup Manager

As can be seen from the above figure, a separate backup/restore node is provisioned in addition to a five node Couchbase cluster. Another best practice is to allocate sufficient storage to hold at least 5x the Couchbase data set size so there is enough space to store required snapshots of the database to meet the Recovery Point Objective (RPO) of the business.

3. Backup Strategy

cbbackupmgr provides a suite of commands which enables DBAs to implement a backup strategy that best suite their business needs. Here are some of the commands:

Using these commands one can implement any of the three backup strategies as mentioned in the documentation. In the example below, we will describe Periodic Merge strategy, in context of Couchbase Cluster running within Kubernetes environment.

4. Periodic Merge

This backup strategy is intended to have the lowest database overhead as it requires the least amount of time to backup the changes and practically no resources consumption from the database cluster to consolidate the data during the compaction and merge process (as it happens on the backup node).

On a high level here is how Periodic Merge strategy works:

  1. Setup backup repository using cbbackupmgr config
  2. Take an incremental backup of the database (in the repository) using cbbackupmgr backup
  3. Perform backup compaction using cbbackupmgr compact so that disk space can be efficiently used.
  4. Merge ‘n’ oldest backups using cbbackupmgr merge so that the number of backups in the repository doesn’t grow infinitely and space requirements remain under check.

Note: The above steps are captured in the backup-with-periodic-merge.sh script, which we will later use in our Kubernetes setup to take periodic backups.

5. Backup Couchbase Data

In my last blog on Couchbase Autonomous Operator, I have described step-by-step on how to deploy self-healing, highly-available Couchbase cluster using Persistent Volumes. Assuming you have followed those steps and deployed the cluster already, steps below will describe how you can setup automatic backup capability using cronjob. It is considered best practice to regularly backup your data, and also test restoring backups to confirm the restore process before disaster recovery is actually required.

This functionality is not provided by the Operator and left to the cluster administrator to define backup policies and test data restoration. This section describes some common patterns that may be employed to perform the required functions.

5.1. Create Storage Class

The Kubernetes resource definitions below illustrate a typical arrangement for backup that saves the state of the entire cluster. We would need to first define the StorageClass which we will format using xfs for the most optimal performance.

# Create storage class for backup/restore operations
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  labels:
    k8s-addon: storage-aws.addons.k8s.io
  name: gp2-backup-storage
parameters:
  type: gp2
  fsType: xfs
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer

Using above definition in backup-sc.yaml file, we can create storage class like this:

$ kubectl create -f backup-sc.yaml -n emart

5.2. Create Persistent Volume

A persistent volume is claimed to keep data safe in the event of an outage. You will need to plan the claim size based on your expected data set size, the number of days data retention and whether incremental backups are used at all.

# Define backup storage volume
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: backup-pvc
spec:
  storageClassName: gp2-backup-storage
  resources:
    requests:
      storage: 50Gi
  accessModes:
    - ReadWriteOnce

Save above definition in backup-pvc.yaml and create the claim:

$ kubectl create -f backup-pvc.yaml -n emart

5.3. Configure Backup repository

Before we can begin taking snapshots of our data periodically, we need to configure the backup archive location. A job is created to mount the persistent volume and initialize a backup repository. The repository is named couchbase which will map to the cluster name in later specifications.

# Create a backup repository
kind: Job
apiVersion: batch/v1
metadata:
  name: couchbase-cluster-backup-config
spec:
  template:
    spec:
      containers:
        - name: backup-config
          image: couchbase/server:enterprise-6.5.0
          command: ["cbbackupmgr", "config", "--archive", "/backups", "--repo", "couchbase"]
          volumeMounts:
            - name: "couchbase-cluster-backup-volume"
              mountPath: "/backups"
      volumes:
        - name: couchbase-cluster-backup-volume
          persistentVolumeClaim:
            claimName: backup-pvc
      restartPolicy: Never

Save above definition in config.yaml and create backup repository:

$ kubectl create -f config.yaml -n emart

5.3. Run Backup as CronJob

Create a cronjob as described in the periodic-backup.yaml file, which takes a backup of the Couchbase cluster by a) downloading the backup script in the pod b) running the script and taking backup of the cluster data using the persistent storage volume.

kind: CronJob
apiVersion: batch/v1beta1
metadata:
  name: couchbase-cluster-backup-create
spec:
  schedule: "*/5 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            #Delete backup-with-periodic-merge script so that new one can be pulled with each run
            - name: delete-script
              image: couchbase/server:enterprise-6.5.0
              command: ["rm", "/backups/backup-with-periodic-merge.sh"]
              volumeMounts:
                - name: "couchbase-cluster-backup-volume"
                  mountPath: "/backups"
          initContainers:
            #Download the backup script from the git repo
            - name: wget-backup-script
              image: couchbase/server:enterprise-6.5.0
              command: ["wget", "https://raw.githubusercontent.com/couchbaselabs/cboperator-hol/master/eks/cb-operator-guide/files/sh/backup-with-periodic-merge.sh", "-P", "/backups/."]
              volumeMounts:
                - name: "couchbase-cluster-backup-volume"
                  mountPath: "/backups"
            #Change the mod of the backup script to execution
            - name: chmod-script
              image: couchbase/server:enterprise-6.5.0
              command: ["chmod", "700", "/backups/backup-with-periodic-merge.sh"]
              volumeMounts:
                - name: "couchbase-cluster-backup-volume"
                  mountPath: "/backups"
            #Run the script so it can do a) Backup b) Compaction c) Merge with each snapshot
            - name: periodic-merge
              image: couchbase/server:enterprise-6.5.0
              command: ["sh", "-c" ,"/backups/backup-with-periodic-merge.sh --cluster cbdemo-srv.emart.svc"]
              volumeMounts:
                - name: "couchbase-cluster-backup-volume"
                  mountPath: "/backups"
          volumes:
            - name: couchbase-cluster-backup-volume
              persistentVolumeClaim:
                claimName: backup-pvc
          restartPolicy: Never

In the above YAML we are running backup every 5 mins but you can change the frequency so it can meet your business RPO. As our Couchbase cluster is deployed within namespace emart so we will deploy the backup cronjob under the same namespace:

$ kubectl apply -f periodic-backup.yaml -n emart

cronjob.batch/couchbase-cluster-backup-create created

5.4 Validate Periodic Backup Job

At this point, you can begin to watch the cronjob kicking in at every 5 minutes. And once it becomes active it will execute three initContainers (wget-backup-script, chmod-script, periodic-merge) in sequential order followed by the cointainers (delete-script):

$ kubectl get pods -n emart -w

NAME                                            READY     STATUS    RESTARTS   AGE
backup-node                                     1/1       Running   0          1d
cbdemo-0000                                     1/1       Running   0          5d
cbdemo-0001                                     1/1       Running   0          5d
cbdemo-0002                                     1/1       Running   0          5d
cbdemo-0003                                     1/1       Running   0          5d
cbdemo-0004                                     1/1       Running   0          5d
couchbase-operator-7654d844cb-gn4bw             1/1       Running   0          5d
couchbase-operator-admission-7ff868f54c-5pklx   1/1       Running   0          5d

couchbase-cluster-backup-create-1580357820-tz2hg   0/1       Pending   0         2s
couchbase-cluster-backup-create-1580357820-tz2hg   0/1       Pending   0         2s
couchbase-cluster-backup-create-1580357820-tz2hg   0/1       Init:0/3   0         2s
couchbase-cluster-backup-create-1580357820-tz2hg   0/1       Init:1/3   0         3s
couchbase-cluster-backup-create-1580357820-tz2hg   0/1       Init:2/3   0         4s
couchbase-cluster-backup-create-1580357820-tz2hg   0/1       Init:2/3   0         6s
couchbase-cluster-backup-create-1580357820-tz2hg   0/1       PodInitializing   0         27s
couchbase-cluster-backup-create-1580357820-tz2hg   0/1       Completed   0         30s

You can view the logs of each initContainers after the pod displays status Completed. The initContainers we are interested in is called periodic-merge:

$ kubectl logs couchbase-cluster-backup-create-1580357820-tz2hg -n emart -c periodic-merge


---------------------------------------------------------
BEGIN STEP 1: BACKUP : Thu Jan 30 04:17:12 UTC 2020
Running backup...
 Command:  cbbackupmgr backup  --archive /backups --repo couchbase --cluster couchbase://cbdemo-srv.emart.svc --username Administrator --password password --threads 2
Warning: Progress bar disabled because terminal width is less than 80 characters
Backup successfully completed
Backed up bucket "gamesim-sample" succeeded
Mutations backedup; 586, Mutations failed to backup: 0
Deletions backedup: 0, Deletions failed to backup: 0
Backed up bucket "travel-sample" succeeded
Mutations backedup; 0, Mutations failed to backup: 0
Deletions backedup: 0, Deletions failed to backup: 0
---------------------------------------------------------
BEGIN STEP 2: COMPACTION : Thu Jan 30 04:17:20 UTC 2020
List of backup snapshots ...

2020-01-28T23_01_37.592188562Z
2020-01-28T23_03_34.160387835Z
2020-01-28T23_05_08.103740281Z
2020-01-30T04_17_12.702824188Z
Last backup name is: 2020-01-30T04_17_12.702824188Z
Compacting the backup...
 Command: cbbackupmgr compact --archive /backups --repo couchbase --backup 2020-01-30T04_17_12.702824188Z
Compaction succeeded, 0 bytes freed
---------------------------------------------------------
BEGIN STEP 3: Merging old backup : Thu Jan 30 04:17:24 UTC 2020

 Size      Items          Name
 604.93MB  -              + couchbase
 192.00MB  -                  + 2020-01-28T23_01_37.592188562Z
 192.00MB  -                      + beer-sample
 37B       0                          analytics.json
 414B      0                          bucket-config.json
 192.00MB  7303                       + data
 192.00MB  7303                           1024 Shards
 2B        0                          full-text.json
 1.94KB    1                          gsi.json
 784B      1                          views.json
 192.02MB  -                  + 2020-01-28T23_03_34.160387835Z
 192.02MB  -                      + travel-sample
 0B        0                          analytics.json
 416B      0                          bucket-config.json
 192.00MB  31591                      + data
 192.00MB  31591                          1024 Shards
 2B        0                          full-text.json
 15.57KB   10                         gsi.json
 2B        0                          views.json
 64.02MB   -                  + 2020-01-28T23_05_08.103740281Z
 64.02MB   -                      + travel-sample
 0B        0                          analytics.json
 416B      0                          bucket-config.json
 64.00MB   0                          + data
 64.00MB   0                              1024 Shards
 2B        0                          full-text.json
 15.57KB   10                         gsi.json
 2B        0                          views.json
 156.89MB  -                  + 2020-01-30T04_17_12.702824188Z
 92.88MB   -                      + gamesim-sample
 0B        0                          analytics.json
 417B      0                          bucket-config.json
 92.88MB   586                        + data
 92.88MB   586                            1024 Shards
 2B        0                          full-text.json
 1.95KB    1                          gsi.json
 501B      1                          views.json
 64.02MB   -                      + travel-sample
 0B        0                          analytics.json
 416B      0                          bucket-config.json
 64.00MB   0                          + data
 64.00MB   0                              1024 Shards
 2B        0                          full-text.json
 15.57KB   10                         gsi.json
 2B        0                          views.json
Start 2020-01-28T23_01_37.592188562Z, END 2020-01-28T23_03_34.160387835Z
Merging old backups...
 Command: cbbackupmgr merge --archive /backups --repo couchbase --start 2020-01-28T23_01_37.592188562Z --end 2020-01-28T23_03_34.160387835Z

Merge completed successfully

Size      Items          Name
 412.92MB  -              + couchbase
 192.02MB  -                  + 2020-01-28T23_03_34.160387835Z
 192.02MB  -                      + travel-sample
 37B       0                          analytics.json
 416B      0                          bucket-config.json
 192.00MB  31591                      + data
 192.00MB  31591                          1024 Shards
 2B        0                          full-text.json
 15.57KB   10                         gsi.json
 2B        0                          views.json
 64.02MB   -                  + 2020-01-28T23_05_08.103740281Z
 64.02MB   -                      + travel-sample
 0B        0                          analytics.json
 416B      0                          bucket-config.json
 64.00MB   0                          + data
 64.00MB   0                              1024 Shards
 2B        0                          full-text.json
 15.57KB   10                         gsi.json
 2B        0                          views.json
 156.89MB  -                  + 2020-01-30T04_17_12.702824188Z
 92.88MB   -                      + gamesim-sample
 0B        0                          analytics.json
 417B      0                          bucket-config.json
 92.88MB   586                        + data
 92.88MB   586                            1024 Shards
 2B        0                          full-text.json
 1.95KB    1                          gsi.json
 501B      1                          views.json
 64.02MB   -                      + travel-sample
 0B        0                          analytics.json
 416B      0                          bucket-config.json
 64.00MB   0                          + data
 64.00MB   0                              1024 Shards
 2B        0                          full-text.json
 15.57KB   10                         gsi.json
 2B        0                          views.json

Note: As can be seen from the logs above, before the merge step there were four backups available and after merge there are three backup snapshots that are referred to as RESTOREPOINTS in backup-with-periodic-merge.sh script.

This concludes the backup section.

6. Restoring

Much like a backup, we can restore data to a new Couchbase cluster with a Kubernetes Job.

kind: Job
apiVersion: batch/v1
metadata:
  name: couchbase-cluster-restore
spec:
  template:
    spec:
      containers:
        - name: couchbase-cluster-restore
          image: couchbase/server:enterprise-6.0.2
          command: ["cbbackupmgr", "restore", "--archive", "/backups", "--repo", "couchbase", "--cluster", "couchbase://cbdemo-srv.emart.svc", "--username", "Administrator", "--password", "password"]
          volumeMounts:
            - name: "couchbase-cluster-backup-volume"
              mountPath: "/backups"
      volumes:
        - name: couchbase-cluster-backup-volume
          persistentVolumeClaim:
            claimName: backup-pvc
      restartPolicy: Never

If you would rather like to create a temporary backup-restore pod to see what backups are available or to troubleshoot an issue, you can mount the same persistentVolumeClaim to a new pod. Here is the definition of the pod which can be stored in backup-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: backup-node
spec:  # specification of the pod's contents
  containers:
    - name: backup-pod
      image: couchbase/server:enterprise-6.5.0
      # Just spin & wait forever
      command: [ "/bin/bash", "-c", "--" ]
      args: [ "while true; do sleep 30; done;" ]
      volumeMounts:
        - name: "couchbase-cluster-backup-volume"
          mountPath: "/backups"
  volumes:
    - name: couchbase-cluster-backup-volume
      persistentVolumeClaim:
        claimName: backup-pvc
  restartPolicy: Never

Run kubectl to bring up the pod temporarily:

$ kubectl apply -f br/backup-pod.yaml -n emart
$ kubectl get pods -n emart

NAME                                            READY     STATUS    RESTARTS   AGE
backup-node                                     1/1       Running   0          3d1h
cbdemo-0000                                     1/1       Running   0          7d1h
cbdemo-0001                                     1/1       Running   0          7d1h
cbdemo-0002                                     1/1       Running   0          7d1h
cbdemo-0003                                     1/1       Running   0          7d1h
cbdemo-0004                                     1/1       Running   0          7d1h
couchbase-operator-7654d844cb-gn4bw             1/1       Running   0          7d2h
couchbase-operator-admission-7ff868f54c-5pklx   1/1       Running   0          7d2h

Once backup-node is Running, we can login to that pod:

$ kubectl exec -it backup-node -n emart -- /bin/bash

root@backup-node:/

And execute cbbackupmgr list command to view existing backups:

# cbbackupmgr list --repo couchbase --archive /backups

Size      Items          Name
256.04MB  -              + couchbase
0B        -                  + 2020-01-30T04_17_12.702824188Z
0B        -                      + gamesim-sample
0B        0                          analytics.json
0B        0                          + data
0B        0                              Error: no data shards were found
0B        0                          full-text.json
0B        0                          gsi.json
0B        0                          views.json
128.02MB  -                  + 2020-01-30T04_18_13.021340423Z
....

And you can also run cbbackupmgr restore command manually:

# cbbackupmgr restore --archive /backups --repo couchbase --cluster couchbase://cbdemo-srv.emart.svc --username Administrator --password password

Once you are done restoring just delete the pod:

$ kubectl delete -f backup-pod.yaml -n emart

7. Conclusion

We walked through step-by-step on how one can configure a backup cronjob, which automates the process of taking the periodic backup at a predefined interval. We used a backup-with-periodic-merge.sh script, that executes a) backup, b) compaction and c) merge within a single script. This script was then used in the periodic-backup.yaml file, which automated the process of taking backup within the Kubernetes environment. We hope you would use the best practices described in this blog and plan on taking regular backups as well as validate those backups using restore command regularly.

Share this article
Get Couchbase blog updates in your inbox
This field is required.

Author

Posted by Anuj Sahni, Cloud and Solutions Architecture Leader, Couchbase

<strong>Anuj Sahni</strong> is a seasoned cloud and solutions architecture leader with over two decades of experience designing scalable, high-performance enterprise applications across AWS, Azure, and GCP. Currently part of the <strong>Capella team at Couchbase</strong>, he helps organizations modernize their applications and navigate cloud migration using cloud-native technologies. Prior to Couchbase, Anuj was <strong>Principal Product Manager at Oracle</strong>, where he led strategic initiatives for Oracle NoSQL Database and Oracle Service Cloud, focusing on distributed, always-available data platforms. He holds a <strong>Master’s in Electrical and Computer Engineering</strong> from the <strong>University of Florida</strong> and is an active thought leader in the data architecture space.

Leave a comment

Ready to get Started with Couchbase Capella?

Start building

Check out our developer portal to explore NoSQL, browse resources, and get started with tutorials.

Use Capella free

Get hands-on with Couchbase in just a few clicks. Capella DBaaS is the easiest and fastest way to get started.

Get in touch

Want to learn more about Couchbase offerings? Let us help.