FoundationDB Backup and Restore
All state of a simplyblock control plane is held in FoundationDB: the cluster topology, the logical volume metadata,
and the task queues. The FoundationDB Kubernetes Operator ⧉
is installed together with the control plane, and backups of that key-value store can be written to S3-compatible
object storage through it. A backup is driven by the FoundationDBBackup resource, a restore by the
FoundationDBRestore resource. Both live in the apps.foundationdb.org/v1beta2 API group.
Warning
A FoundationDB backup covers control plane metadata only. The data on the logical volumes is not part of it and is backed up separately, see Backup and Recovery.
The control plane ships FoundationDB 7.3.63 in a FoundationDBCluster resource named simplyblock-fdb-cluster,
deployed in the simplyblock namespace with imageType: unified. All examples below use those values. For the
surrounding components, see
Control Plane Cluster Architecture.
Prerequisites
Object Store Account
An account on an S3-compatible object store is required, and the backup is written into a bucket on it. The bucket
name defaults to fdb-backups. Bucket creation is attempted by the backup process, but object stores differ in
whether that is permitted, so the bucket is best created in advance.
Blob Store Credentials
The account key is passed to the backup agents through a credentials file in the format defined by the FoundationDB backup documentation ⧉. In that file the secret is keyed by the account name, written without its port:
apiVersion: v1
kind: Secret
metadata:
name: fdb-backup-credentials
namespace: simplyblock
type: Opaque
stringData:
credentials: |
{
"accounts": {
"[email protected]": {
"secret": "<ACCOUNT_KEY>"
}
}
}
kubectl apply -f fdb-backup-credentials.yaml
The path to the file is passed to the backup agents through the FDB_BLOB_CREDENTIALS environment variable.
Object Store Access for the Operator
The fdbbackup and fdbrestore commands are run by the FoundationDB operator itself, so the same credentials have
to be reachable from the simplyblock-fdb-controller-manager deployment. That deployment is rendered by the control
plane chart without a credentials mount and has to be patched:
spec:
template:
spec:
volumes:
- name: backup-credentials
secret:
secretName: fdb-backup-credentials
containers:
- name: manager
env:
- name: FDB_BLOB_CREDENTIALS
value: /var/backup-credentials/credentials
volumeMounts:
- name: backup-credentials
mountPath: /var/backup-credentials
kubectl -n simplyblock patch deployment simplyblock-fdb-controller-manager \
--type strategic \
--patch-file fdb-operator-credentials.yaml
Note
The patch is overwritten by the next helm upgrade of the control plane chart and has to be reapplied
afterward.
TLS Material
Backup agents connect to the cluster as ordinary FoundationDB clients. The enableTls flag of mainContainer and
sidecarContainer applies to server processes and has no effect on the backup agents. When the control plane is
installed with mutual TLS, the certificate, the key, and the CA file are read from the paths named by
FDB_TLS_CERTIFICATE_FILE, FDB_TLS_KEY_FILE, and FDB_TLS_CA_FILE. The material is held in the
simplyblock-foundationdb-tls secret and is mounted into the backup agent pods through podTemplateSpec. The same
three variables are set on the operator deployment by the chart whenever mutual TLS is enabled.
spec:
podTemplateSpec:
spec:
volumes:
- name: tls-fdb
secret:
secretName: simplyblock-foundationdb-tls
containers:
- name: foundationdb
env:
- name: FDB_TLS_CERTIFICATE_FILE
value: /var/fdb/tls/tls.crt
- name: FDB_TLS_KEY_FILE
value: /var/fdb/tls/tls.key
- name: FDB_TLS_CA_FILE
value: /var/fdb/tls/ca.crt
volumeMounts:
- name: tls-fdb
mountPath: /var/fdb/tls
readOnly: true
The certificate and the key have to be parseable so that the TLS subsystem of the agents initializes. They are not used for the connection to the object store, which is verified against the CA file instead.
Creating a Backup
A backup is started by creating a FoundationDBBackup resource that names the cluster and the object store:
apiVersion: apps.foundationdb.org/v1beta2
kind: FoundationDBBackup
metadata:
name: simplyblock-fdb-cluster
namespace: simplyblock
spec:
version: 7.3.63
clusterName: simplyblock-fdb-cluster
imageType: unified
agentCount: 2
snapshotPeriodSeconds: 86400
mainContainer:
imageConfigs:
- baseImage: quay.io/simplyblock-io/fdb-kubernetes-monitor
blobStoreConfiguration:
accountName: [email protected]:443
bucket: fdb-backups
podTemplateSpec:
spec:
volumes:
- name: backup-credentials
secret:
secretName: fdb-backup-credentials
containers:
- name: foundationdb
env:
- name: FDB_BLOB_CREDENTIALS
value: /var/backup-credentials/credentials
volumeMounts:
- name: backup-credentials
mountPath: /var/backup-credentials
kubectl apply -f fdb-backup.yaml
Two things are done by the operator in response. A deployment of backup agent pods is created, which connect to
simplyblock-fdb-cluster and perform the transfer. An fdbbackup start command is then run against the cluster,
which begins a continuous backup and keeps taking snapshots at the configured interval.
The version and the imageType have to match the FoundationDBCluster resource, since the agents run the same
FoundationDB binaries as the cluster. With imageType: unified the backup agent image is the
fdb-kubernetes-monitor image, which is why the same repository is named in mainContainer.imageConfigs.
The destination is derived from blobStoreConfiguration. The backup is written to the bucket under the name in
backupName, which defaults to the name of the FoundationDBBackup resource. When no port is given in
accountName, port 443 is used, or port 80 when secure connections are disabled.
Note
Backups are always continuous in this version of the CRD. A one-time snapshot is not offered, and neither are
backup tags, so one FoundationDBBackup resource per cluster is supported.
Spec Fields
| Field | Type | Description |
|---|---|---|
clusterName |
string | Name of the FoundationDBCluster to back up. Required. |
version |
string | FoundationDB version of the backup agents. Has to match the cluster. Required. |
blobStoreConfiguration.accountName |
string | Account and endpoint of the object store, as <ACCOUNT>@<HOST>:<PORT>. Required. |
blobStoreConfiguration.backupName |
string | Name of the backup in the bucket. Defaults to the name of the resource. |
blobStoreConfiguration.bucket |
string | Bucket the backup is written to. Defaults to fdb-backups. |
blobStoreConfiguration.urlParameters |
list | Additional backup URL parameters, each written as <KEY>=<VALUE>. |
agentCount |
int | Number of backup agent pods. Defaults to 2. |
snapshotPeriodSeconds |
int | Interval between two snapshots, in seconds. Defaults to 864000, ten days. |
backupState |
string | Desired state of the backup: Running, Stopped, or Paused. |
backupType |
string | backup_agent (default) or partitioned_log. |
deletionPolicy |
string | Action taken when the resource is deleted: noop (default), stop, or cleanup. |
imageType |
string | split (default) or unified. Has to match the cluster. |
mainContainer |
object | Image configuration and TLS settings of the foundationdb container. |
podTemplateSpec |
object | Pod template of the backup agents, used for credential and certificate volumes. |
customParameters |
list | Additional command line parameters passed to the backup agents. |
backupDeploymentMetadata |
object | Labels and annotations added to the backup agent deployment. |
encryptionKeyPath |
string | Path to the backup encryption key. Only passed when the FoundationDB version in use supports backup encryption. |
Backup Types
Two backup types are selectable through backupType:
backup_agent, the default, uses the file backup system. The whole backup lifecycle is managed by the operator.partitioned_loguses the partitioned log backup system. Key-range snapshots are taken by operator-managed backup agents, while the mutation backup requires backup workers in theFoundationDBClusterresource.
Warning
Migration between backup types is not supported. To switch, the existing backup is stopped and cleaned up, the
FoundationDBBackup resource is deleted, and a new resource is created with the other type.
Backup State
The backupState field holds the desired state of the backup. With Running, or with the field unset, snapshots
are taken at the configured interval. With Stopped, the backup agent deployment is kept in place but no backup is
run, which is the setting used to prepare a cluster for a restore. With Paused, the agents stop processing until
the state is set back to Running.
Pausing and resuming act on all backup agents of a cluster at once. There is no per-backup pause.
Deletion Policy
The deletionPolicy field decides what happens to the backup itself when the FoundationDBBackup resource is
deleted:
| Value | Behavior |
|---|---|
noop |
Default. The backup is left as it is. Mutation logs keep accumulating without agents to drain them. |
stop |
The backup is aborted. |
cleanup |
The backup is aborted and its data is deleted from the object store. |
With stop or cleanup, the foundationdb.org/fdb-kubernetes-operator finalizer is added to the resource.
Removing that finalizer by hand risks an incomplete removal and is not recommended. The deletion is carried out by
the operator. With cleanup, the removal of the backup data can block for up to ten minutes before the
reconciliation is retried.
Note
A noop policy leaves the backup running while its agents are gone. As long as the cluster still takes writes,
mutation logs are retained in the cluster and are never trimmed, which grows the keyspace until the backup is
aborted.
Connections Without TLS
Secure connections to the object store are used by default. Additional backup URL parameters are passed through
blobStoreConfiguration.urlParameters, among them secure_connection, which disables TLS toward the object store
when set to 0:
spec:
blobStoreConfiguration:
accountName: [email protected]:80
urlParameters:
- "secure_connection=0"
Checking the Backup Status
kubectl -n simplyblock get foundationdbbackup
NAME GENERATION RECONCILED AGE
simplyblock-fdb-cluster 1 1 12m
The backup is reconciled once RECONCILED has caught up with GENERATION. The state of the backup itself is
reported under status.backupDetails, which carries the destination url, the running and paused flags, and
the snapshotTime of the last snapshot:
kubectl -n simplyblock get foundationdbbackup simplyblock-fdb-cluster \
-o jsonpath='{.status.backupDetails}'
The agent pods carry the FoundationDB command line tools, so the backup can also be queried directly:
kubectl -n simplyblock exec deploy/simplyblock-fdb-cluster-backup-agents -- \
fdbbackup status
Restoring a Backup
A restore is started by creating a FoundationDBRestore resource. Two conditions have to be met before it succeeds.
The destination database has to be empty. A restore into a database that still holds keys is rejected, so a restore over an existing control plane requires the keyspace to be cleared first.
Backup agents have to exist for the destination cluster, because the restore is carried out by them. When the
destination is a freshly created cluster that is not being backed up itself, the agents are brought up by a
FoundationDBBackup resource with backupState: Stopped, which deploys the agents without starting a backup.
Warning
The destination cluster is locked for the duration of the restore, and the control plane cannot serve requests against it. After the restore completes, the control plane services are restarted so that the restored state is picked up.
apiVersion: apps.foundationdb.org/v1beta2
kind: FoundationDBRestore
metadata:
name: simplyblock-fdb-cluster
namespace: simplyblock
spec:
destinationClusterName: simplyblock-fdb-cluster
blobStoreConfiguration:
accountName: [email protected]:443
backupName: simplyblock-fdb-cluster
bucket: fdb-backups
kubectl apply -f fdb-restore.yaml
An fdbrestore command is run against the destination cluster by the operator. Without further fields, the entire
keyspace is restored to the most recent restorable version of the backup.
Spec Fields
| Field | Type | Description |
|---|---|---|
destinationClusterName |
string | Name of the FoundationDBCluster the backup is restored into. Required. |
blobStoreConfiguration.accountName |
string | Account and endpoint of the object store, as <ACCOUNT>@<HOST>:<PORT>. Required. |
blobStoreConfiguration.backupName |
string | Name of the backup in the bucket to restore from. |
blobStoreConfiguration.bucket |
string | Bucket the backup was written to. Defaults to fdb-backups. |
blobStoreConfiguration.urlParameters |
list | Additional backup URL parameters, each written as <KEY>=<VALUE>. |
backupVersion |
int | Version to restore to. Defaults to the highest restorable version of the backup. |
keyRanges |
list | Key ranges to restore, each with a start and an end. Defaults to the entire keyspace. |
customParameters |
list | Additional command line parameters passed to the restore. |
encryptionKeyPath |
string | Path to the encryption key of the backup. Only passed when the FoundationDB version in use supports backup encryption. |
A point in time is selected through backupVersion. Any version after the end of the first snapshot is restorable,
which is what makes the continuous backup a point-in-time backup.
Note
A control plane restore is only consistent when the whole keyspace is restored. The keyRanges field is meant
for partial recovery and leaves the metadata in a mixed state when used against a simplyblock control plane.
Checking the Restore Status
kubectl -n simplyblock get foundationdbrestore
NAME AGE STATE
simplyblock-fdb-cluster 4m running
The STATE column mirrors the state reported by fdbrestore and changes to completed once all data has been
written. The same information is available from a backup agent pod:
kubectl -n simplyblock exec deploy/simplyblock-fdb-cluster-backup-agents -- \
sh -c 'fdbrestore status --dest_cluster_file ${FDB_CLUSTER_FILE}'
Troubleshooting
When a restore does not start, the reason is recorded in the log of the simplyblock-fdb-controller-manager pod:
kubectl -n simplyblock logs deploy/simplyblock-fdb-controller-manager \
| grep "Error from FDB command"
The most common cause is a destination cluster that still holds data:
Using target restore version 123
Backup Description
URL: blobstore://object-store.example
Restorable: true
Partitioned logs: false
Restoring backup to version: 123
ERROR: Attempted to restore into a non-empty destination database
Fatal Error: Attempted to restore into a non-empty destination database
The content of the destination cluster is inspected through fdbcli from any FoundationDB pod:
kubectl -n simplyblock exec -it simplyblock-fdb-cluster-storage-1 -- fdbcli
fdb> getrange "" \xff
Danger
Clearing the keyspace destroys all control plane state of the destination cluster and cannot be undone. It is only performed when the data is known to be expendable, such as on a cluster created for the restore.
fdb> writemode on; clearrange "" \xff