Skip to content

Commit

Permalink
Adds docker image and associated scripts.
Browse files Browse the repository at this point in the history
  • Loading branch information
pierreozoux committed Mar 10, 2019
1 parent d7c6399 commit 2ae2bcf
Show file tree
Hide file tree
Showing 5 changed files with 370 additions and 0 deletions.
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM debian:stretch

ENV LANG=C.UTF-8

COPY ./borg.exe /usr/bin/borg
COPY ./scripts/docker/borgbackup /usr/bin/
COPY ./scripts/docker/borgserver /usr/bin/

ENTRYPOINT ["/usr/bin/borg"]
190 changes: 190 additions & 0 deletions scripts/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Borg Docker Image

Docker image with [BorgBackup](https://borgbackup.readthedocs.io/en/stable/) client utility and sshfs support. Borg is a deduplicating backup program supporting compresion and encryption. It's very efficient and doesn't need regular full backups while still supporting data pruning.

## Quick start

First, pull the image to keep it up to date. Then create and run the borg backup container. In this quick start, the `/etc` and `/home` directories from the host are bind mounted to the container as read only. These are the directories which will be backed up. The backed up data will be stored in the `borg-repo` Docker volume, and the data will be protected with the `my-secret-pw` password. If the host is using SELinux, the `--security-opt label:disable` flag must be used, because we don't want to relabel the `/etc` and `/home` directories while we want the container to have access to them. After the backup is done, data will be pruned according to the default policy and checked for errors. Borg is running in a verbose mode within the container, so the detailed output from backup will be printed. At the end, the container is deleted. This is done by separate `docker rm` command, because the `--rm` option to the `docker run` would remove also the Docker volumes, and we don't want that. Deleting the container and pulling the image from registry every time keeps the container fresh every time the backup is run.

```
docker pull borgbackup/borg
docker run \
-e BORG_REPO=/borg/repo \
-e BORG_PASSPHRASE=my-secret-pw \
-e BACKUP_DIRS=/borg/data \
-e EXCLUDE='*/.cache*;*.tmp;/borg/data/etc/shadow' \
-e COMPRESSION=lz4 \
-e PRUNE=1 \
-v borg-cache:/root/.cache/borg \
-v borg-repo:/borg/repo \
-v /etc:/borg/data/etc:ro \
-v /home:/borg/data/home:ro \
--security-opt label:disable \
--entrypoint=/usr/bin/borgbackup \
--name borg-backup \
borgbackup/borg
docker rm borg-backup
```

### Server side

To start a borg server:
- generate an ssh-key
- choose where to store ssh details
- choose where to store backup data

and run the following command:

```
docker run \
-e SSH_KEY=... \
-v /path/to/ssh/folder:/etc/ssh \
-v /path/to/local/folder:/backups \
--entrypoint=/usr/bin/borgserver \
borgbackup/borg
```

## More examples

Backup docker volumes to remote location (Borg must be running in server mode in that remote location):
```
docker run \
-e BORG_REPO='user@hostname:/path/to/repo' \
-e ARCHIVE=wordpress-$(date +%Y-%m-%d) \
-e BORG_PASSPHRASE=my-secret-pw \
-e BACKUP_DIRS=/borg/data \
-e COMPRESSION=lz4 \
-e PRUNE=1 \
-v borg-cache:/root/.cache/borg \
-v mariadb-data:/borg/data/mariadb:ro \
-v worpdress-data:/borg/data/wordpress:ro \
--entrypoint=/usr/bin/borgbackup \
--name borg-backup \
borgbackup/borg
```

Using sshfs (in case when the Borg is not installed on the remote location):
```
docker run \
-e SSHFS='user@hostname:/path/to/repo' \
-e SSHFS_PASSWORD=my-ssh-password \
-e BORG_PASSPHRASE=my-secret-pw \
-e BACKUP_DIRS=/borg/data \
-e COMPRESSION=lz4 \
-e PRUNE=1 \
-v borg-cache:/root/.cache/borg \
-v mariadb-data:/borg/data/mariadb:ro \
-v worpdress-data:/borg/data/wordpress:ro \
--cap-add SYS_ADMIN --device /dev/fuse --security-opt label:disable \
--entrypoint=/usr/bin/borgbackup \
--name borg-backup \
borgbackup/borg
```

Using sshfs with ssh key authentification:
```
docker run \
-e SSHFS='user@hostname:/path/to/repo' \
-e SSHFS_IDENTITY_FILE=/root/ssh-key/key \
-e SSHFS_GEN_IDENTITY_FILE=1 \
-e BORG_PASSPHRASE=my-secret-pw \
-e BACKUP_DIRS=/borg/data \
-e COMPRESSION=lz4 \
-e PRUNE=1 \
-v borg-cache:/root/.cache/borg \
-v borg-ssh-key:/root/ssh-key \
-v mariadb-data:/borg/data/mariadb:ro \
-v worpdress-data:/borg/data/wordpress:ro \
--cap-add SYS_ADMIN --device /dev/fuse --security-opt label:disable \
--entrypoint=/usr/bin/borgbackup \
--name borg-backup \
borgbackup/borg
```

Restoring files from specific day to folder on host:
```
docker run \
-e BORG_REPO='user@hostname:/path/to/repo' \
-e ARCHIVE=wordpress-2016-05-25 \
-e BORG_PASSPHRASE=my-secret-pw \
-e EXTRACT_TO=/borg/restore \
-e EXTRACT_WHAT=only/this/file \
-v borg-cache:/root/.cache/borg \
-v /opt/restore:/borg/restore \
--security-opt label:disable \
--entrypoint=/usr/bin/borgbackup \
--name borg-backup \
borgbackup/borg
```

Running custom borg command:
```
docker run \
-e BORG_REPO='user@hostname:/path/to/repo' \
-e BORG_PASSPHRASE=my-secret-pw \
-e BORG_PARAMS='list ::2016-05-26' \
-v borg-cache:/root/.cache/borg \
--entrypoint=/usr/bin/borgbackup \
--name borg-backup \
borgbackup/borg
```

## Environment variables

Description of all accepted environment variables follows.

### Core variables

**BORG_REPO** - repository location

**ARCHIVE** - archive parameter for Borg repository. If empty, defaults to `"${HOSTNAME}_$(date +%Y-%m-%d)"`. For more info see [Borg documentation](https://borgbackup.readthedocs.io/en/stable/usage.html)

**BACKUP_DIRS** - directories to back up

**EXCLUDE** - paths/patterns to exclude from backup. Paths must be separated by `;`. For example: `-e EXCLUDE='/my path/one;/path two;*.tmp'`

**BORG_PARAMS** - run custom borg command inside of the container. If this variable is set, default commands are not executed, only the one specified in *BORG_PARAMS*. For example `list` or `list ::2016-05-26`. In both examples, repo is not specified, because borg understands the `BORG_REPO` env var and uses it by default

**BORG_SKIP_CHECK** - set to `1` if you want to skip the `borg check` command at the end of the backup

**SSH_KEY** - set the ssh key when you start this image in server mode

### Compression

**COMPRESSION** - compression to use. Defaults to none. [More info](https://borgbackup.readthedocs.io/en/stable/usage.html#borg-create)

### Encryption

**BORG_PASSPHRASE** - `repokey` mode password to encrypt the backed up data. Defaults to none. Only the `repokey` mode encryption is supported by this Docker image. [More info](https://borgbackup.readthedocs.io/en/stable/usage.html#borg-init)

### Extracting (restoring) files

**EXTRACT_TO** - directory where to extract (restore) borg archive. If this variable is set, default commands are not executed, only the extraction is done. Repo and archive are specified with *BORG_REPO* and *ARCHIVE* variables. [More info](https://borgbackup.readthedocs.io/en/stable/usage.html#borg-extract)

**EXTRACT_WHAT** - subset of files and directories which should be extracted

### Pruning

**PRUNE** - if set, prune the repository after backup. Empty by default. [More info](https://borgbackup.readthedocs.io/en/stable/usage.html#borg-prune)

**PRUNE_PREFIX** - filter data to prune by prefix of the archive. Empty by default - prune all data

**KEEP_DAILY** - keep specified number of daily backups. Defaults to 7

**KEEP_WEEKLY** - keep specified number of weekly backups. Defaults to 4

**KEEP_MONTHLY** - keep specified number of monthly backups. Defaults to 6

### SSHFS

**SSHFS** - sshfs destination in form of `user@host:/path`. When using sshfs, container needs special permissions: `--cap-add SYS_ADMIN --device /dev/fuse` and if using SELinux: `--security-opt label:disable` or apparmor: `--security-opt apparmor:unconfined`

**SSHFS_PASSWORD** - password for ssh authentication

**SSHFS_IDENTITY_FILE** - path to ssh key

**SSHFS_GEN_IDENTITY_FILE** - if set, generates ssh key pair if *SSHFS_IDENTITY_FILE* is set, but the key file doesn't exist. 4096 bits long rsa key will be generated. After generating the key, the public part of the key is printed to stdout and the container stops, so you have the chance to configure the server part before running first backup

# Contributor

The backup script comes from the great work of [pschiffe](https://github.com/pschiffe).
133 changes: 133 additions & 0 deletions scripts/docker/borgbackup
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#!/bin/bash

set -euo pipefail

function echoerr {
cat <<< "$@" 1>&2;
}

function quit {
if [ -n "${SSHFS:-}" ]; then
fusermount -u "$BORG_REPO"
fi

if [ -n "${1:-}" ]; then
exit "$1"
fi

exit 0
}

if [ -n "${SSHFS:-}" ]; then
if [ -n "${SSHFS_IDENTITY_FILE:-}" ]; then
if [ ! -f "$SSHFS_IDENTITY_FILE" ] && [ -n "${SSHFS_GEN_IDENTITY_FILE:-}" ]; then
ssh-keygen -t rsa -b 4096 -N '' -f "$SSHFS_IDENTITY_FILE"
cat "${SSHFS_IDENTITY_FILE}.pub"
exit 0
fi
SSHFS_IDENTITY_FILE="-o IdentityFile=${SSHFS_IDENTITY_FILE}"
else
SSHFS_IDENTITY_FILE=''
fi
if [ -n "${SSHFS_PASSWORD:-}" ]; then
SSHFS_PASSWORD="echo ${SSHFS_PASSWORD} |"
SSHFS_PASSWORD_OPT='-o password_stdin'
else
SSHFS_PASSWORD=''
SSHFS_PASSWORD_OPT=''
fi
mkdir -p /mnt/sshfs
eval "${SSHFS_PASSWORD} sshfs -o StrictHostKeyChecking=no ${SSHFS} /mnt/sshfs ${SSHFS_IDENTITY_FILE} ${SSHFS_PASSWORD_OPT}"
BORG_REPO=/mnt/sshfs
fi

if [ -z "${BORG_REPO:-}" ]; then
echoerr 'Variable $BORG_REPO is required. Please set it to the repository location.'
quit 1
fi

# Borg just needs this
export BORG_REPO

if [ -z "${BORG_PASSPHRASE:-}" ]; then
INIT_ENCRYPTION='--encryption=none'
echoerr 'Not using encryption. If you want to encrypt your files, set $BORG_PASSPHRASE variable.'
else
INIT_ENCRYPTION='--encryption=repokey'
fi

DEFAULT_ARCHIVE="${HOSTNAME}_$(date +%Y-%m-%d)"
ARCHIVE="${ARCHIVE:-$DEFAULT_ARCHIVE}"

if [ -n "${EXTRACT_TO:-}" ]; then
mkdir -p "$EXTRACT_TO"
cd "$EXTRACT_TO"
borg extract -v --list --show-rc ::"$ARCHIVE" ${EXTRACT_WHAT:-}
quit
fi

if [ -n "${BORG_PARAMS:-}" ]; then
borg $BORG_PARAMS
quit
fi

if [ -z "${BACKUP_DIRS:-}" ]; then
echoerr 'Variable $BACKUP_DIRS is required. Please fill it with directories you would like to backup.'
quit 1
fi

# If the $BORG_REPO is a local path and the directory is empty, init it
if [ "${BORG_REPO:0:1}" == '/' ] && [ ! "$(ls -A $BORG_REPO)" ]; then
INIT_REPO=1
fi

if [ -n "${INIT_REPO:-}" ]; then
borg init -v --show-rc $INIT_ENCRYPTION
fi

if [ -n "${COMPRESSION:-}" ]; then
COMPRESSION="--compression=${COMPRESSION}"
else
COMPRESSION=''
fi

if [ -n "${EXCLUDE:-}" ]; then
OLD_IFS=$IFS
IFS=';'

EXCLUDE_BORG=''
for i in $EXCLUDE; do
EXCLUDE_BORG="${EXCLUDE_BORG} --exclude ${i}"
done

IFS=$OLD_IFS
else
EXCLUDE_BORG=''
fi

borg create -v --stats --show-rc $COMPRESSION $EXCLUDE_BORG ::"$ARCHIVE" $BACKUP_DIRS

if [ -n "${PRUNE:-}" ]; then
if [ -n "${PRUNE_PREFIX:-}" ]; then
PRUNE_PREFIX="--prefix=${PRUNE_PREFIX}"
else
PRUNE_PREFIX=''
fi
if [ -z "${KEEP_DAILY:-}" ]; then
KEEP_DAILY=7
fi
if [ -z "${KEEP_WEEKLY:-}" ]; then
KEEP_WEEKLY=4
fi
if [ -z "${KEEP_MONTHLY:-}" ]; then
KEEP_MONTHLY=6
fi

borg prune -v --stats --show-rc $PRUNE_PREFIX --keep-daily=$KEEP_DAILY --keep-weekly=$KEEP_WEEKLY --keep-monthly=$KEEP_MONTHLY
fi

if [ "${BORG_SKIP_CHECK:-}" != '1' ] && [ "${BORG_SKIP_CHECK:-}" != "true" ]; then
borg check -v --show-rc
fi

quit
23 changes: 23 additions & 0 deletions scripts/docker/borgserver
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash -eux
if [ -n "${SSH_KEY:-}" ]; then
dpkg-reconfigure openssh-server
sed -i \
-e 's/^#PasswordAuthentication yes$/PasswordAuthentication no/g' \
-e 's/^PermitRootLogin without-password$/PermitRootLogin no/g' \
/etc/ssh/sshd_config
if [[ $(ls /etc/ssh-keys/ssh_host_*) ]]; then
echo "Already initialized."
else
echo "Initializing ssh-keys folder..."
cp /etc/ssh/ssh_host_* /etc/ssh-keys
fi
chmod 400 /etc/ssh-keys/ssh_host_*
sed -i 's|/ssh/|/ssh-keys/|' /etc/ssh/sshd_config
sed -i '/^#HostKey/s/^#//' /etc/ssh/sshd_config
sed -e "s#SSH_KEY#${SSH_KEY}#g" /home/borg/authorized_keys.sample > /home/borg/.ssh/authorized_keys
chown borg:borg /home/borg/.ssh/authorized_keys
exec /usr/sbin/sshd -D
else
echo "You need to give an SSH_KEY env variable"
quit
fi
15 changes: 15 additions & 0 deletions scripts/docker/build_and_publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash -eux

echo "Building docker image for borg version ${TAG}..."

vagrant scp stretch64:/vagrant/borg/borg.exe .
docker build --pull -t borgbackup/borg:${TAG} .
docker tag borgbackup/borg:${TAG} borgbackup/borg:latest

echo "Running smoke test..."
docker run borgbackup/borg --version

echo "Login and publishing the docker image..."
docker login
docker push borgbackup/borg:${TAG}
docker push borgbackup/borg:latest

0 comments on commit 2ae2bcf

Please sign in to comment.