Skip to content

Commit f27007a

Browse files
committed
feat: backup-qdrant-collection-aliases
1 parent 902ae4b commit f27007a

4 files changed

Lines changed: 109 additions & 12 deletions

File tree

qdrant-backup-restore/.env.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ export QDRANT_S3_ENDPOINT_URL="http://minio.default.svc.cluster.local:9000" # up
88
export QDRANT_RESTORE_HOSTS="http://localhost:6334" # update to target restore host(s) (for restore only otherwise leave as empty string).
99
export GET_PEERS_FROM_CLUSTER_INFO="false" # only enable for kubernetes cluster deployment with qdrant cluster.enabled option set as true.
1010
export MC_CONFIG_DIR="mc" # controls where mc S3 client store its configurations (for restore or get_snap_s3 only).
11+
export BACKUP_COLLECTION_ALIASES_ON_S3="false" # enable to backup collection aliases to s3 bucket.
12+
export QDRANT_COLLECTION_ALIASES_STABLE_FILE="collection_aliases" # override the stable version of collection_aliases file to restore.

qdrant-backup-restore/README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ Create a `.env` file based on `.env.sample` with the following variables:
6363
| `QDRANT_RESTORE_HOSTS` | Comma-separated list of destination Qdrant hosts set as `""` | `""` |
6464
| `GET_PEERS_FROM_CLUSTER_INFO` | Auto-discover peers from Qdrant cluster info endpoint (only for Kubernetes) | `false` |
6565

66+
if `BACKUP_COLLECTION_ALIASES_ON_S3` is `true` include the S3 credentials. When `true` ensure S3 credentials are set i.e. `QDRANT_S3_SECRET_ACCESS_KEY`, `QDRANT_S3_SECRET_ACCESS_KEY`, `QDRANT_S3_ENDPOINT_URL`, `QDRANT_S3_BUCKET_NAME` (use same bucket name on qdrant configuration).
67+
68+
#### Required Variables For Optional Collection Aliases Backup
69+
| Variable | Description | Default |
70+
|----------|-------------|---------|
71+
| `QDRANT_SOURCE_HOSTS` | Comma-separated list of source Qdrant hosts | `http://localhost:6333` |
72+
| `QDRANT_RESTORE_HOSTS` | Comma-separated list of destination Qdrant hosts set as `""` | `""` |
73+
| `QDRANT_S3_ENDPOINT_URL` | S3-compatible storage endpoint URL | `http://minio:9000` |
74+
| `QDRANT_S3_ACCESS_KEY_ID` | S3 access key ID | `your-access-key` |
75+
| `QDRANT_S3_SECRET_ACCESS_KEY` | S3 secret access key | `your-secret-key` |
76+
| `QDRANT_S3_BUCKET_NAME` | S3 bucket name where snapshots are stored | `bucket-name` |
77+
| `BACKUP_COLLECTION_ALIASES_ON_S3` | set `true` to toggle backing up collection aliases on S3 | `false` |
78+
6679
#### Required Variables For Restore
6780

6881
| Variable | Description | Default |
@@ -308,10 +321,10 @@ source .env.dest
308321
- `QDRANT_API_KEY` - set your Qdrant api key if it exists otherwise leave as is.
309322
- `QDRANT_SOURCE_HOSTS` - set your Qdrant source host. if you are connecting to your a qdrant cluster deployed on kubernetes use port forwarding. Ensure **all** the pods/containers can be reached locally. Add these comma seperated hosts in this config .e.g `"http://qdrant-source-1:6333,http://qdrant-source-1:6334"`. This is required only for the backup process. In Kubernetes, service/peer discovery is done automatically by enabling `GET_PEERS_FROM_CLUSTER_INFO`.
310323
- `QDRANT_RESTORE_HOSTS` - set your Qdrant target restore host **(for restore only)** set as `""` when backing up.
311-
- `QDRANT_S3_ENDPOINT_URL` - set it to your s3 endpoint url **(for restore only)**.
312-
- `QDRANT_S3_ACCESS_KEY_ID` - set it to your s3 access key id credentials **(for restore only)**.
313-
- `QDRANT_S3_SECRET_ACCESS_KEY`- set it to your s3 secret access key credentials **(for restore only)**.
314-
- `QDRANT_S3_BUCKET_NAME`- set it to your s3 bucket name **(for restore only)**.
324+
- `QDRANT_S3_ENDPOINT_URL` - set it to your s3 endpoint url.
325+
- `QDRANT_S3_ACCESS_KEY_ID` - set it to your s3 access key id credentials.
326+
- `QDRANT_S3_SECRET_ACCESS_KEY`- set it to your s3 secret access key credentials.
327+
- `QDRANT_S3_BUCKET_NAME`- set it to your s3 bucket name.
315328
- `GET_PEERS_FROM_CLUSTER_INFO`- leave as is (`false`) for non-cluster usecases.
316329
- Run below to make the environment variables available.
317330

qdrant-backup-restore/k8s/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,29 @@ Update the following environment varibles in your copy of `backup-cronjob.yaml`
120120
5. `CURL_TIMEOUT` is set at `3000` seconds. This is the max time curl will wait for request to complete. Its increased in scenarios where backup takes a while.
121121
6. `QDRANT_S3_LINK_EXPIRY_DURATION` is set at `3600`. This is the duration that an s3 presigned url will be active. The url is used during the recovery process.
122122
7. `QDRANT_WAIT_ON_TASK` is set as `true`. This configuation make backup process synchronous meaning 'wait for snapshot process to finish successfully before moving on'. Its used during backup and recovery.
123+
8. `BACKUP_COLLECTION_ALIASES_ON_S3` is set as `false`. This configuration is used to toggle backup of collection aliases to S3. The collection_aliases are versioned by the timestamp. When `true` ensure S3 credentials are set;
124+
````yaml
125+
env:
126+
- name: QDRANT__STORAGE__SNAPSHOTS_CONFIG__S3_CONFIG__ACCESS_KEY
127+
valueFrom:
128+
secretKeyRef:
129+
name: <your-qdrant-kubernetes-secret-name>
130+
key: QDRANT_S3_ACCESS_KEY_ID
131+
- name: QDRANT__STORAGE__SNAPSHOTS_CONFIG__S3_CONFIG__SECRET_KEY
132+
valueFrom:
133+
secretKeyRef:
134+
name: <your-qdrant-kubernetes-secret-name>
135+
key: QDRANT_S3_SECRET_ACCESS_KEY
136+
- name: QDRANT__STORAGE__SNAPSHOTS_CONFIG__S3_CONFIG__BUCKET
137+
valueFrom:
138+
secretKeyRef:
139+
name: <your-qdrant-kubernetes-secret-name>
140+
key: QDRANT_S3_BUCKET_NAME
141+
- name: QDRANT__STORAGE__SNAPSHOTS_CONFIG__S3_CONFIG__ENDPOINT_URL
142+
value: "<your-s3-endpoint-url>"
143+
- name: QDRANT__STORAGE__SNAPSHOTS_CONFIG__SNAPSHOTS_STORAGE
144+
value: "s3"
145+
````
123146

124147
Deploy the job!
125148

@@ -148,6 +171,8 @@ Update the following environment varibles accordingly;
148171
7. `QDRANT_WAIT_ON_TASK` is set as `true`. This configuation make restoration process synchronous meaning 'wait for snapshot process to finish successfully before moving on'. Its used during backup and recovery.
149172
8. `QDRANT_SNAPSHOT_DATETIME_FILTER` is empty. Setting this filters out snapshot/backups belonging to a certain date and time using glob pattern matching. e.g `"2026-01-29"` = all snapshots in 29th January 2026, `2026-01` = all backups in January 2026.
150173
9. `MC_CONFIG_DIR` is `mc`. This overrides the default storage location ($HOME) for mc s3 client configurations. Essential in set ups that use stricter securityContext configuration like `readOnlyRootFilesystem: true`.
174+
10. `BACKUP_COLLECTION_ALIASES_ON_S3` is `false`. When this is set to `true` during restoration it will fetch the lastest `collection_alias` from S3.
175+
11. `QDRANT_COLLECTION_ALIASES_STABLE_FILE` is `collection_aliases`. This configuration is used to override the stable version of collection_aliases file to restore. e.g. `collection_aliases-2026-04-30_18-31-04`. The file has to exist on s3.
151176

152177
Deploy the job!
153178

qdrant-backup-restore/qdrant_backup_recovery.sh

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ QDRANT_FAILED_RECOVERY_FILE="failed_snapshot_recovery"
77
QDRANT_SNAPSHOT_RECOVERY_HISTORY_FILE="snapshot_recovery_history"
88
QDRANT_ALIAS_RECOVERY_HISTORY_FILE="alias_recovery_history"
99
QDRANT_COLLECTION_ALIASES="collection_aliases"
10+
BACKUP_COLLECTION_ALIASES_ON_S3=${BACKUP_COLLECTION_ALIASES_ON_S3:-false}
11+
QDRANT_COLLECTION_ALIASES_BACKUP_FOLDER="collection_aliases_store"
1012
QDRANT_WAIT_ON_TASK=${QDRANT_WAIT_ON_TASK:-true}
1113
CURL_TIMEOUT="${CURL_TIMEOUT:-1800}"
1214
QDRANT_S3_ALIAS="qdrant_s3_snaphost"
1315
QDRANT_S3_LINK_EXPIRY_DURATION="${QDRANT_S3_LINK_EXPIRY_DURATION:-3600s}"
1416
QDRANT_HTTP_PORT="${QDRANT_HTTP_PORT:-6333}"
17+
QDRANT_COLLECTION_ALIASES_STABLE_FILE="${QDRANT_COLLECTION_ALIASES_STABLE_FILE:-collection_aliases}"
1518

1619
declare -a peer_uri_map;
1720
# printf wrapper helper
@@ -496,6 +499,8 @@ get_collection_aliases() {
496499
exit 1
497500
fi
498501

502+
: > "$QDRANT_COLLECTION_ALIASES"
503+
499504
local colla_length=0
500505
colla_length=$(jq -c '(.result.aliases // []) | length' <<< "$result")
501506

@@ -510,14 +515,41 @@ get_collection_aliases() {
510515
done <<< "$_result"
511516
fi
512517

518+
if [ "$BACKUP_COLLECTION_ALIASES_ON_S3" = "true" ]; then
519+
520+
setup_s3_storage
521+
522+
local ts
523+
ts=$(date '+%Y-%m-%d_%H-%M-%S')
524+
525+
local base_path="$QDRANT_S3_ALIAS/$QDRANT_S3_BUCKET_NAME/$QDRANT_COLLECTION_ALIASES_BACKUP_FOLDER"
526+
527+
local versioned_dest="$base_path/${QDRANT_COLLECTION_ALIASES}-$ts"
528+
local stable_dest="$base_path/${QDRANT_COLLECTION_ALIASES}"
529+
530+
_printf "backing up collection aliases to s3 bucket %s\n" "$QDRANT_S3_BUCKET_NAME"
531+
532+
if ! mc cp "$QDRANT_COLLECTION_ALIASES" "$versioned_dest"; then
533+
_printf "failed to upload versioned collection aliases backup to %s\n" "$QDRANT_S3_BUCKET_NAME"
534+
exit 1
535+
fi
536+
537+
if ! mc cp "$versioned_dest" "$stable_dest"; then
538+
_printf "failed to update collection aliases stable backup pointer in %s\n" "$QDRANT_S3_BUCKET_NAME"
539+
exit 1
540+
fi
541+
542+
_printf "successfully backed up collection aliases to s3 bucket %s\n" "$QDRANT_S3_BUCKET_NAME"
543+
fi
544+
513545
_printf "%s file updated,found %d collection alias(es)!\n" "$QDRANT_COLLECTION_ALIASES" "$colla_length"
514546
}
515547

516548
# restores collection alias to a qdrant node and appends progress to $QDRANT_ALIAS_RECOVERY_HISTORY_FILE
517549
recover_collection_alias() {
518-
local host="${source_hosts[0]}"
519550
local collection_name="$1"
520551
local alias_name="$2"
552+
local host="$3"
521553
local status=""
522554
local result=""
523555

@@ -540,7 +572,7 @@ recover_collection_alias() {
540572

541573
if [ "$status" != "ok" ]; then
542574
((failed_recovered_colla_count=failed_recovered_colla_count+1))
543-
_printf "[%s] failed to fetch collection alias %s:%s, got this instead %s\n" "$host" "$collection_name" "$alias_name" "${result//[[:space:]]/}"
575+
_printf "[%s] failed to restore collection alias %s:%s, got this instead %s\n" "$host" "$collection_name" "$alias_name" "${result//[[:space:]]/}"
544576
return
545577
fi
546578

@@ -550,6 +582,22 @@ recover_collection_alias() {
550582

551583
# restores collection aliases to a qdrant node and appends progress to $QDRANT_ALIAS_RECOVERY_HISTORY_FILE
552584
recover_collection_aliases() {
585+
586+
local host="${restore_hosts[0]}"
587+
588+
589+
if [ "$BACKUP_COLLECTION_ALIASES_ON_S3" = "true" ]; then
590+
591+
setup_s3_storage
592+
593+
if mc cp "$QDRANT_S3_ALIAS/$QDRANT_S3_BUCKET_NAME/$QDRANT_COLLECTION_ALIASES_BACKUP_FOLDER/$QDRANT_COLLECTION_ALIASES_STABLE_FILE" "$QDRANT_COLLECTION_ALIASES"; then
594+
_printf "collection aliases restored from s3 bucket %s\n" "$QDRANT_S3_BUCKET_NAME"
595+
else
596+
_printf "failed to restore collection aliases file (%s) from s3 bucket %s\n" "$QDRANT_COLLECTION_ALIASES_STABLE_FILE" "$QDRANT_S3_BUCKET_NAME"
597+
exit 1
598+
fi
599+
fi
600+
553601
if [[ ! -s "$QDRANT_COLLECTION_ALIASES" ]]; then
554602
get_collection_aliases
555603
fi
@@ -562,8 +610,7 @@ recover_collection_aliases() {
562610
colla_count=$(wc -l < $QDRANT_COLLECTION_ALIASES)
563611
recovered_colla_count=0
564612
failed_recovered_colla_count=0
565-
566-
local host="${restore_hosts[0]}"
613+
colla_skipped_count=0
567614

568615
touch $QDRANT_ALIAS_RECOVERY_HISTORY_FILE
569616

@@ -577,12 +624,13 @@ recover_collection_aliases() {
577624

578625
if [ "$history_count" -gt 0 ]; then
579626
_printf "[%s] collection alias %s:%s already recovered, skipping!\n" "$host" "$collection_name" "$alias_name"
627+
((colla_skipped_count=colla_skipped_count+1))
580628
continue
581629
fi
582-
recover_collection_alias "$collection_name" "$alias_name"
630+
recover_collection_alias "$collection_name" "$alias_name" "$host"
583631
done < $QDRANT_COLLECTION_ALIASES
584632

585-
_printf "recovery summary: %d/%d collection aliases recovered, %d failed.\n" "$recovered_colla_count" "$colla_count" "$failed_recovered_colla_count"
633+
_printf "recovery summary: %d/%d collection aliases recovered, %d failed, %d skipped.\n" "$recovered_colla_count" "$colla_count" "$failed_recovered_colla_count" "$colla_skipped_count"
586634

587635
colla_count=0
588636
recovered_colla_count=0
@@ -686,9 +734,9 @@ Environment variables:
686734
QDRANT_S3_SECRET_ACCESS_KEY - S3 secret access key (for S3 operations)
687735
QDRANT_S3_BUCKET_NAME - S3 bucket name (for S3 operations)
688736
GET_PEERS_FROM_CLUSTER_INFO - Set to "true" to auto-discover peers
689-
CURL_TIMEOUT - Curl timeout in seconds (default: 300)
737+
CURL_TIMEOUT - Curl timeout in seconds (default: 1800)
690738
QDRANT_WAIT_ON_TASK - Waits for async tasks to finish
691-
QDRANT_SNAPSHOT_DATETIME_FILTER - Specify the datea and time filter for snapshots to be fetched and/or restored, format YYYY-mm-dd, e,g "2026-01-29-11-44", default value is empty so it will fetch every snapshot!!
739+
QDRANT_SNAPSHOT_DATETIME_FILTER - Specify the date and time filter for snapshots to be fetched and/or restored, format YYYY-mm-dd, e,g "2026-01-29-11-44", default value is empty so it will fetch every snapshot!!
692740
Examples:
693741
$0 get_snap
694742
$0 recover_snap
@@ -738,11 +786,20 @@ run() {
738786
local DATETIME="${QDRANT_SNAPSHOT_DATETIME_FILTER:-}"
739787
generate_snapshot_file_from_s3 "$DATETIME"
740788
elif [ "$command" = "create_snap" ] || [ "$command" = "create_snapshot" ]; then
789+
# create collection snapshots
741790
create_collection_snapshot
791+
792+
# backup collection aliases to s3 bucket
793+
get_collection_aliases
794+
742795
elif [ "$command" = "recover_snap" ]; then
743796
setup_s3_storage
744797
local DATETIME="${QDRANT_SNAPSHOT_DATETIME_FILTER:-}"
745798
recover_collection_snapshots "$DATETIME"
799+
800+
# restore collection aliases from s3 bucket
801+
recover_collection_aliases
802+
746803
elif [ "$command" = "get_colla" ] || [ "$command" = "get_collection_alias" ]; then
747804
get_collection_aliases
748805
elif [ "$command" = "recover_colla" ] || [ "$command" = "recover_collection_alias" ]; then

0 commit comments

Comments
 (0)