feat: add minecraft backup integration

This commit is contained in:
Michael Reichenbach 2020-11-16 11:33:00 +01:00
parent b0650c0425
commit db0e7799e0
3 changed files with 237 additions and 4 deletions

View File

@ -1,11 +1,82 @@
FROM restic/restic:0.9.6
FROM alpine AS builder
RUN apk update && apk add python3 dcron mariadb-client postgresql-client
RUN mkdir -p /opt
ARG IMAGE_ARCH=amd64
ARG RCON_CLI_VERSION=1.4.4
ADD https://github.com/itzg/rcon-cli/releases/download/${RCON_CLI_VERSION}/rcon-cli_${RCON_CLI_VERSION}_linux_${IMAGE_ARCH}.tar.gz /tmp/rcon-cli.tar.gz
RUN tar x -f /tmp/rcon-cli.tar.gz -C /opt/ && \
chmod +x /opt/rcon-cli
ARG RESTIC_VERSION=0.9.5
ADD https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_linux_${IMAGE_ARCH}.bz2 /tmp/restic.bz2
RUN bunzip2 /tmp/restic.bz2 && \
mv /tmp/restic /opt/restic && \
chmod +x /opt/restic
ARG DEMOTER_VERSION=0.1.0
ADD https://github.com/itzg/entrypoint-demoter/releases/download/${DEMOTER_VERSION}/entrypoint-demoter_${DEMOTER_VERSION}_linux_${IMAGE_ARCH}.tar.gz /tmp/entrypoint-demoter.tar.gz
RUN tar x -f /tmp/entrypoint-demoter.tar.gz -C /opt/ && \
chmod +x /opt/entrypoint-demoter
ARG RCLONE_VERSION=1.49.5
ADD https://downloads.rclone.org/v${RCLONE_VERSION}/rclone-v${RCLONE_VERSION}-linux-${IMAGE_ARCH}.zip /tmp/rclone.zip
RUN mkdir -p /tmp/rclone && \
unzip /tmp/rclone.zip -d /tmp/rclone && \
mv /tmp/rclone/rclone-v${RCLONE_VERSION}-linux-${IMAGE_ARCH}/rclone /opt/rclone && \
chmod +x /opt/rclone
FROM alpine
RUN apk -U --no-cache add \
bash \
coreutils \
openssh-client \
python3 \
dcron \
mariadb-client \
postgresql-client
COPY --from=builder /opt/rcon-cli /opt/rcon-cli
RUN ln -s /opt/rcon-cli /usr/bin
COPY --from=builder /opt/restic /opt/restic
RUN ln -s /opt/restic /usr/bin
COPY --from=builder /opt/entrypoint-demoter /opt/entrypoint-demoter
RUN ln -s /opt/entrypoint-demoter /usr/bin
COPY --from=builder /opt/rclone /opt/rclone
RUN ln -s /opt/rclone /usr/bin
# install rcb python app
ADD . /restic-compose-backup
WORKDIR /restic-compose-backup
RUN pip3 install -U pip setuptools wheel && pip3 install -e .
ENV XDG_CACHE_HOME=/cache
# end install
ADD backup.sh /backup.sh
RUN chmod +x ./backup.sh
ENTRYPOINT []
CMD ["./entrypoint.sh"]
CMD ["./entrypoint.sh"]

162
src/backup.sh Normal file
View File

@ -0,0 +1,162 @@
#!/bin/bash
set -euo pipefail
if [ "${DEBUG:-false}" == "true" ]; then
set -x
fi
: "${RCON_HOST:=localhost}"
: "${RCON_PORT:=25575}"
: "${RCON_PASSWORD:=minecraft}"
export RCON_HOST
export RCON_PORT
export RCON_PASSWORD
###############
## common ##
## functions ##
###############
is_elem_in_array() {
# $1 = element
# All remaining arguments are array to search for the element in
if [ "$#" -lt 2 ]; then
log INTERNALERROR "Wrong number of arguments passed to is_elem_in_array function"
return 2
fi
local element="${1}"
shift
local e
for e; do
if [ "${element}" == "${e}" ]; then
return 0
fi
done
return 1
}
log() {
if [ "$#" -lt 1 ]; then
log INTERNALERROR "Wrong number of arguments passed to log function"
return 2
fi
local level="${1}"
shift
local valid_levels=(
"INFO"
"WARN"
"ERROR"
"INTERNALERROR"
)
if ! is_elem_in_array "${level}" "${valid_levels[@]}"; then
log INTERNALERROR "Log level ${level} is not a valid level."
return 2
fi
(
# If any arguments are passed besides log level
if [ "$#" -ge 1 ]; then
# then use them as log message(s)
<<<"${*}" cat -
else
# otherwise read log messages from standard input
cat -
fi
if [ "${level}" == "INTERNALERROR" ]; then
echo "Please report this: https://github.com/itzg/docker-mc-backup/issues"
fi
) | awk -v level="${level}" '{ printf("%s %s %s\n", strftime("%FT%T%z"), level, $0); fflush(); }'
} >&2
retry() {
if [ "$#" -lt 3 ]; then
log INTERNALERROR "Wrong number of arguments passed to retry function"
return 1
fi
# How many times should we retry?
# Value smaller than zero means infinitely
local retries="${1}"
# Time to sleep between retries
local interval="${2}"
readonly retries interval
shift 2
if (( retries < 0 )); then
local retries_msg="infinite"
else
local retries_msg="${retries}"
fi
local i=-1 # -1 since we will increment it before printing
while (( retries >= ++i )) || [ "${retries_msg}" != "${retries}" ]; do
# Send SIGINT after 5 minutes. If it doesn't shut down in 30 seconds, kill it.
if output="$(timeout --signal=SIGINT --kill-after=30s 5m "${@}" 2>&1 | tr '\n' '\t')"; then
log INFO "Command executed successfully ${*}"
return 0
else
log ERROR "Unable to execute ${*} - try ${i}/${retries_msg}. Retrying in ${interval}"
if [ -n "${output}" ]; then
log ERROR "Failure reason: ${output}"
fi
fi
# shellcheck disable=SC2086
sleep ${interval}
done
return 2
}
is_function() {
if [ "${#}" -ne 1 ]; then
log INTERNALERROR "is_function expects 1 argument, received ${#}"
fi
name="${1}"
[ "$(type -t "${name}")" == "function" ]
}
call_if_function_exists() {
if [ "${#}" -lt 1 ]; then
log INTERNALERROR "call_if_function_exists expects at least 1 argument, received ${#}"
return 2
fi
function_name="${1}"
if is_function "${function_name}"; then
eval "${@}"
else
log INTERNALERROR "${function_name} is not a valid function!"
return 2
fi
}
##########
## main ##
##########
log INFO "waiting for rcon readiness..."
# 20 times, 10 second delay
retry 20 10s rcon-cli save-on
if retry 5 10s rcon-cli save-off; then
# No matter what we were doing, from now on if the script crashes
# or gets shut down, we want to make sure saving is on
trap 'retry 5 5s rcon-cli save-on' EXIT
retry 5 10s rcon-cli save-all
retry 5 10s sync
rcb backup
retry 20 10s rcon-cli save-on
# Remove our exit trap now
trap EXIT
else
log ERROR "Unable to turn saving off. Is the server running?"
exit 1
fi
if (( PRUNE_BACKUPS_DAYS > 0 )); then
rcb cleanup
fi

View File

@ -1,2 +1,2 @@
10 2 * * * source /env.sh && rcb backup > /proc/1/fd/1
10 2 * * * source /env.sh && /backup.sh > /proc/1/fd/1