Search code examples
kubernetesarangodbdatabase-backups

How to create automatic arangodb cluster backups in a Kubernetes Cluster?


I'm trying to get automatic backups to work for my arangodb cluster deployment. I'm trying to follow the documentation but I think I have messed it up somehow.

Here is my database-config.yaml:

apiVersion: "database.arangodb.com/v1alpha"
kind: "ArangoDeployment"
metadata:
  name: "arangodb-cluster"
spec:
  mode: Cluster 
  agents: 
    count: 3
    args:
      - --log.level=debug
  dbservers: 
    count: 3
  coordinators:
    count: 3

---
apiVersion: "backup.arangodb.com/v1alpha"
kind: "ArangoBackup"
metadata:
  name: "arangodb-backup"
  namespace: default
spec:
  policyName: "arangodb-backup-policy"
  deployment:
    name: "arangodb-backup-deployment"
  upload:
    repositoryURL: "https://s3.filebase.com/buffer"
    credentialsSecretName: "backup-secret"
---
apiVersion: "backup.arangodb.com/v1alpha"
kind: "ArangoBackupPolicy"
metadata:
  name: "arangodb-backup-policy"
spec:
  schedule: "*/2 * * * *"
template:
  upload:
      repositoryURL: "https://s3.filebase.com/myBucket"
      credentialsSecretName: "backup-secret"
---
apiVersion: v1
kind: Secret
metadata:
  name: backup-secret
data:
   token: mybase64EnodedJSONToken
type: Opaque

Ideally I would find some data in my bucket, but it's empty. I think it might be either:

  1. The bucket size is to small (But that seems rather unrealistic, because that is a test deployment with only one document and 4 collections, so it shouldn't be that big)
  2. The service I'm using simply is not supported 2.1 The service I'm using is wrongly configured
  3. I missunderstood something in the documentation

My decoded json token looks like this (I generated it with rclones cli):

{
"Filebase": {
    "access_key_id": "myID",
    "acl": "private",
    "endpoint": "https://s3.filebase.com",
    "env_auth": "false",
    "provider": "Other",
    "secret_access_key": "myAccessKey",
    "type": "s3"
}

} My encoded one looks (somewhat) like this (Just placed it here in case I encoded the json token the wrong way):

ewogICAgIkZpbGViYXNlIXXXXXXX...X==

And it's: 301 bytes long

What I tried: I tried to get some more insides on what is happening, but I lack the experience to do it propperly, also I tried to add some stuff from the documentation but to no avail.

And as a final notice, the bucket is set to private on the filebase.com dashboard, I'm using the free tier there and the 2min on the cronjob timer are just for testing.

EDIT: It seems like that custom the backup pod is a pro feature of the db and one needs to build his own pod for this if one wants to have a backup.


Solution

  • This is how I solved it (credits to the offical arangodb github for the first part of the script).
    What is the script doing?
    We are creating a cronjob which will run every 14 days. Then we spin up a pod which will use the arangodump tool to dump (in this case) the whole database.
    By passing it data like the database url,password, user name and save it on a volume under temp/dump.
    Afterwards we create another pod which uses the minio cli tool, which allows to interact with any of the major object storage providers.
    We first set an mc alias for gcloud with the access key and secret, you can replace this with any other s3 compatible provider url. Aftwerwards we will mirror the /temp/dump to the cloud bucket (in this case qute, replace this with your own bucket name!) in a folder with the most date of the backup. $() can be used to execute shell commands and use the return value, just for anybody not knowing that.

    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name:  backup-job
    spec:
      schedule: "0 0 */14 * *" #Runs the job at every 14 days
      jobTemplate:
        spec:
          template:
            metadata:
              name:  backup-job
            spec:
              initContainers:
                - name: dump-create
                  image: "arangodb:3.7.3"
                  args:
                    - "arangodump"
                    - "--server.endpoint=$(ENDPOINT)"
                    - "--server.username=$(USERNAME)"
                    - "--server.password=$(PASSWORD)"
                    - "--server.database=MY-DATABASE"
                    - "--output-directory=/tmp/dump"
                    - "--overwrite"
                  volumeMounts:
                    - name: dump
                      mountPath: /tmp/dump
                  env:
                  - name: "PASSWORD"
                    valueFrom:
                      secretKeyRef:
                        name: signing-secret
                        key: root-password
                  
                  - name: "USERNAME"
                    valueFrom:
                      configMapKeyRef:
                        name: signing-config
                        key: "admin-user"
                  
                  - name: "ENDPOINT"
                    valueFrom:
                      configMapKeyRef:
                        name: signing-config
                        key: db-url
    
              restartPolicy: OnFailure
    
    
              containers:
                - name: db-dump-upload
                  image: "minio/mc"
                  imagePullPolicy: IfNotPresent
                  command: ["/bin/sh","-c"]
                  args: ["mc alias set gcs https://storage.googleapis.com $ACCESSKEY $SECRETKEY; mc mirror /tmp/dump gcs/qute/$(date -I)"] #no () for env variables!!!!
                  volumeMounts:
                    - name: dump
                      mountPath: /tmp/dump
    
                  env:
                  - name: SECRETKEY
                    valueFrom:
                      secretKeyRef:
                        name: backup-secret
                        key: secret
                       
                  - name: ACCESSKEY
                    valueFrom:
                      secretKeyRef:
                        name: backup-secret
                        key: access-key
              volumes:
                - name: dump
                  emptyDir: {}