Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(s3): add s3 support for backup storage #70

Merged
merged 5 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ COPY backup.sh /usr/local/bin/backup.sh

RUN microdnf update -y && rm -rf /var/cache/yum
RUN microdnf install findutils -y && microdnf clean all
RUN curl -O https://dl.min.io/client/mc/release/linux-amd64/mc.rpm \
&& rpm -ih mc.rpm \
&& rm mc.rpm

CMD ["/usr/local/bin/backup.sh"]
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ oc edit -n etcd-backup cm/backup-config
```

The following options are used:
- `OCP_BACKUP_S3`: Use S3 to store etcd-backup snapshots
- `OCP_BACKUP_S3_NAME`: MinIO client host alias name
- `OCP_BACKUP_S3_HOST`: S3 host endpoint (with scheme)
- `OCP_BACKUP_S3_BUCKET`: S3 bucket name
- `OCP_BACKUP_S3_ACCESS_KEY`: access key to access S3 bucket
- `OCP_BACKUP_S3_SECRET_KEY`: secret key to access S3 bucket
- `OCP_BACKUP_SUBDIR`: Sub directory on PVC that should be used to store the backup. If it does not exist it will be created.
- `OCP_BACKUP_DIRNAME`: Directory name for a single backup. This is a format string used by
[`date`](https://man7.org/linux/man-pages/man1/date.1.html)
Expand All @@ -70,6 +76,8 @@ The following options are used:
- `OCP_BACKUP_KEEP_COUNT`: Number of backups to keep. Only used if `backup.expiretype` is set to `count`
- `OCP_BACKUP_UMASK`: Umask used inside the script to set restrictive permission on written files, as they contain sensitive information.

Note that the storage type is exclusive. This means it is either S3 or PVC. In case of using S3 we do not manage the retention within the backup script. We suggest using a rentention policy on the S3 bucket itself. This can be done thanks to an objects expiration configuration as described in the object lifecycle management [documentation](https://min.io/docs/minio/linux/administration/object-management/object-lifecycle-management.html#object-expiration).

Changing the schedule be done in the CronJob directly, with `spec.schedule`:
```
oc edit -n etcd-backup cronjob/etcd-backup
Expand Down
6 changes: 6 additions & 0 deletions backup-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ apiVersion: v1
metadata:
name: backup-config
data:
OCP_BACKUP_S3: "false"
OCP_BACKUP_S3_NAME: "minio"
OCP_BACKUP_S3_HOST: "http://minio.local:9000"
OCP_BACKUP_S3_BUCKET: "etcd-backup"
OCP_BACKUP_S3_ACCESS_KEY: "randomaccesskey"
OCP_BACKUP_S3_SECRET_KEY: "secretkey"
OCP_BACKUP_SUBDIR: "/"
OCP_BACKUP_DIRNAME: "+etcd-backup-%FT%T%:z"
OCP_BACKUP_EXPIRE_TYPE: "days"
Expand Down
103 changes: 63 additions & 40 deletions backup.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/bin/bash

################################################################################
# backup.sh OpenShift etcd backup script
################################################################################
#
# Copyright (C) 2021 Adfinis AG
# Copyright (C) 2024 Adfinis AG
# https://adfinis.com
# [email protected]
#
Expand All @@ -26,53 +27,75 @@
#
# Authors:
# Cyrill von Wattenwyl <[email protected]>

# Valentin Maillot <[email protected]>

set -xeuo pipefail

# set proper umask
umask "${OCP_BACKUP_UMASK}"
# check storage type
if [ "${OCP_BACKUP_S3}" = "true" ]; then
# prepare & push backup to S3

# validate expire type
case "${OCP_BACKUP_EXPIRE_TYPE}" in
days|count|never) ;;
*) echo "backup.expiretype needs to be one of: days,count,never"; exit 1 ;;
esac
# update CA trust
update-ca-trust

# validate expire numbers
if [ "${OCP_BACKUP_EXPIRE_TYPE}" = "days" ]; then
case "${OCP_BACKUP_KEEP_DAYS}" in
''|*[!0-9]*) echo "backup.expiredays needs to be a valid number"; exit 1 ;;
*) ;;
esac
elif [ "${OCP_BACKUP_EXPIRE_TYPE}" = "count" ]; then
case "${OCP_BACKUP_KEEP_COUNT}" in
''|*[!0-9]*) echo "backup.expirecount needs to be a valid number"; exit 1 ;;
*) ;;
esac
fi
# configure mcli assuming the bucket already exists
bash +o history
mcli alias set "${OCP_BACKUP_S3_NAME}" "${OCP_BACKUP_S3_HOST}" "${OCP_BACKUP_S3_ACCESS_KEY}" "${OCP_BACKUP_S3_SECRET_KEY}"
bash -o history

# create backup to temporary location
chroot /host /usr/local/bin/cluster-backup.sh /var/tmp/etcd-backup

# move files to S3 and delete temporary files
mcli mv /host/var/tmp/etcd-backup/* "${OCP_BACKUP_S3_NAME}"/"${OCP_BACKUP_S3_BUCKET}"
rm -rv /host/var/tmp/etcd-backup
vmaillot marked this conversation as resolved.
Show resolved Hide resolved
else
# prepare, run and copy backup

# set proper umask
umask "${OCP_BACKUP_UMASK}"

# validate expire type
case "${OCP_BACKUP_EXPIRE_TYPE}" in
days|count|never) ;;
*) echo "backup.expiretype needs to be one of: days,count,never"; exit 1 ;;
esac

# validate expire numbers
if [ "${OCP_BACKUP_EXPIRE_TYPE}" = "days" ]; then
case "${OCP_BACKUP_KEEP_DAYS}" in
''|*[!0-9]*) echo "backup.expiredays needs to be a valid number"; exit 1 ;;
*) ;;
esac
elif [ "${OCP_BACKUP_EXPIRE_TYPE}" = "count" ]; then
case "${OCP_BACKUP_KEEP_COUNT}" in
''|*[!0-9]*) echo "backup.expirecount needs to be a valid number"; exit 1 ;;
*) ;;
esac
fi

# make dirname and cleanup paths
BACKUP_FOLDER="$( date "${OCP_BACKUP_DIRNAME}")" || { echo "Invalid backup.dirname" && exit 1; }
BACKUP_PATH="$( realpath -m "${OCP_BACKUP_SUBDIR}/${BACKUP_FOLDER}" )"
BACKUP_PATH_POD="$( realpath -m "/backup/${BACKUP_PATH}" )"
BACKUP_ROOTPATH="$( realpath -m "/backup/${OCP_BACKUP_SUBDIR}" )"
# make dirname and cleanup paths
BACKUP_FOLDER="$( date "${OCP_BACKUP_DIRNAME}")" || { echo "Invalid backup.dirname" && exit 1; }
BACKUP_PATH="$( realpath -m "${OCP_BACKUP_SUBDIR}/${BACKUP_FOLDER}" )"
BACKUP_PATH_POD="$( realpath -m "/backup/${BACKUP_PATH}" )"
BACKUP_ROOTPATH="$( realpath -m "/backup/${OCP_BACKUP_SUBDIR}" )"

# make nescesary directorys
mkdir -p "/host/var/tmp/etcd-backup"
mkdir -p "${BACKUP_PATH_POD}"
# make necessary directories
mkdir -p "/host/var/tmp/etcd-backup"
mkdir -p "${BACKUP_PATH_POD}"

# create backup to temporary location
chroot /host /usr/local/bin/cluster-backup.sh /var/tmp/etcd-backup
# create backup to temporary location
chroot /host /usr/local/bin/cluster-backup.sh /var/tmp/etcd-backup

# move files to pvc and delete temporary files
mv /host/var/tmp/etcd-backup/* "${BACKUP_PATH_POD}"
rm -rv /host/var/tmp/etcd-backup
# move files to PVC and delete temporary files
mv /host/var/tmp/etcd-backup/* "${BACKUP_PATH_POD}"
rm -rv /host/var/tmp/etcd-backup

# expire backup
if [ "${OCP_BACKUP_EXPIRE_TYPE}" = "days" ]; then
find "${BACKUP_ROOTPATH}" -mindepth 1 -maxdepth 1 -type d -mtime "+${OCP_BACKUP_KEEP_DAYS}" -exec rm -rv {} +
elif [ "${OCP_BACKUP_EXPIRE_TYPE}" = "count" ]; then
# shellcheck disable=SC3040,SC2012
ls -1tp "${BACKUP_ROOTPATH}" | awk "NR>${OCP_BACKUP_KEEP_COUNT}" | xargs -I{} rm -rv "${BACKUP_ROOTPATH}/{}"
# expire backup
if [ "${OCP_BACKUP_EXPIRE_TYPE}" = "days" ]; then
find "${BACKUP_ROOTPATH}" -mindepth 1 -maxdepth 1 -type d -mtime "+${OCP_BACKUP_KEEP_DAYS}" -exec rm -rv {} +
elif [ "${OCP_BACKUP_EXPIRE_TYPE}" = "count" ]; then
# shellcheck disable=SC3040,SC2012
ls -1tp "${BACKUP_ROOTPATH}" | awk "NR>${OCP_BACKUP_KEEP_COUNT}" | xargs -I{} rm -rv "${BACKUP_ROOTPATH}/{}"
fi
fi
Loading