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

[pull] master from loomchild:master #1

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
dcf3580
Add LICENSE.txt
Oct 5, 2017
4d42b32
Create LICENSE
loomchild Oct 5, 2017
ea9e965
Remove old invalid LICENSE.txt
Oct 5, 2017
91f4149
Allow backing-up and restoring from stdin
loomchild Jan 14, 2018
3b59c8e
Update README to add info about stdin/stdout
loomchild Jan 14, 2018
026832a
Update README
loomchild Jan 14, 2018
21d4035
Advise Docker for Windows users against involving stdin/stdout
damianb Jan 14, 2019
a72c805
Merge pull request #7 from damianb/patch-1
loomchild Jan 15, 2019
ca82688
mention stidin/stdout in usage
loomchild Feb 9, 2019
222b9b1
write errors to stderr to show them on redirect
loomchild Feb 10, 2019
3b77acf
avoid backing-up empty volumes to avoid typos
loomchild Feb 10, 2019
f12f586
add misc section to README
loomchild Apr 13, 2019
0c3fddb
fix formatting
loomchild Apr 13, 2019
82d3800
exclude files from backup
loomchild Apr 13, 2019
9c38e05
allow aborting the operation
loomchild Apr 13, 2019
5669150
update README
loomchild Apr 13, 2019
f5e0a59
reorganize README
loomchild Apr 13, 2019
c385834
improve README
loomchild Apr 13, 2019
dc84645
update LICENSE year
loomchild Apr 13, 2019
102b6ba
choose compression algorithm or no algorithm
loomchild Apr 13, 2019
5efdf1f
improve Windows README warning
loomchild Jun 2, 2019
7794551
Add a new use case to the README
lhw Jun 14, 2019
18ee374
Clarify note on cpu/traffic trade-off
lhw Jun 19, 2019
f28bae8
Merge pull request #17 from lhw/lhw-readme-copy
loomchild Jun 19, 2019
01a5fdb
uniform note syntax
loomchild Jun 19, 2019
872720b
Add xz compression (#18)
kronenpj Sep 12, 2019
c7eaf88
use GNU tar
loomchild Jan 11, 2020
189c389
add verbose flag
loomchild Jan 11, 2020
d048439
handle signals via dumb init (Ctrl-C et al)
loomchild Jan 12, 2020
f8b07e8
Update README.md
loomchild Feb 18, 2021
0cec0d7
add zstd (#36)
ksurl Mar 14, 2021
f62b9a7
add zstd to usage
loomchild Mar 14, 2021
7e8b6b2
pass additional args to Tar
loomchild Mar 20, 2021
41074d2
avoid overwriting data when restoring
loomchild Mar 20, 2021
3bb7e18
remove unnecessary 1 second delay
loomchild Mar 20, 2021
8f24efc
added info about restoring labels
loomchild Mar 20, 2021
e63597e
formatting
loomchild Mar 20, 2021
e09c1a7
mention --log-driver none
loomchild May 26, 2021
3d7b8d3
improve README
loomchild May 26, 2021
a3b2d9f
add workflow for multiarch & ghcr support (#40)
azrikahar Aug 7, 2021
89a50cb
hardcode username (already used in tags)
loomchild Aug 7, 2021
4c9a91a
release on every push
loomchild Aug 7, 2021
c5a7dcb
add pbzip2
loomchild Aug 7, 2021
faa7828
Revert "add pbzip2"
loomchild Aug 7, 2021
124377e
Add ghcr comment in README
loomchild Aug 7, 2021
9195dd9
README formatting
loomchild Aug 7, 2021
eacf96f
Update README.md
loomchild Aug 7, 2021
0c12c44
add pigz
loomchild Aug 9, 2021
5c41e87
schedule build every 1st day of the month
loomchild Nov 9, 2021
8b478fd
replace cats by pipes
loomchild Jun 2, 2022
83bff02
use bash shell, adaptive zstd
loomchild Oct 9, 2022
fdffb03
make stdin/out syntax default, - optional
loomchild Oct 9, 2022
6a4b21f
disable zstd adapt option (performance)
loomchild Dec 17, 2022
d31abfb
Create FUNDING.yml
loomchild Sep 15, 2023
4d7158e
mention Podman
loomchild Jan 27, 2024
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
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: loomchild
43 changes: 43 additions & 0 deletions .github/workflows/publish-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: publish-image

on:
push:
branches:
- 'master'
schedule:
- cron: '0 4 1 * *'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Set up QEMU
uses: docker/setup-qemu-action@v1

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1

- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: loomchild
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: loomchild
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v2
with:
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
loomchild/volume-backup:latest
ghcr.io/loomchild/volume-backup:latest
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
FROM alpine

RUN apk update && apk add --no-cache dumb-init bash xz tar pigz zstd

COPY volume-backup.sh /

ENTRYPOINT [ "/bin/sh", "/volume-backup.sh" ]
ENTRYPOINT [ "/usr/bin/dumb-init", "--", "/volume-backup.sh" ]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 - 2019 Jarek Lipski

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
93 changes: 86 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,110 @@
# volume-backup

An utility to backup and restore [docker volumes](https://docs.docker.com/engine/reference/commandline/volume/).
An utility to backup and restore [Docker volumes](https://docs.docker.com/storage/volumes/). For more info, read my article on [Medium](https://medium.com/@jareklipski/backup-restore-docker-named-volumes-350397b8e362).

**Note**: Make sure no container is using the volume before backup or restore, otherwise your data might be damaged.
It works just as well with [Podman](https://podman.io/) volumes, just prefix each command with `podman` instead of `docker`.

**Note**: Make sure no container is using the volume before backup or restore, otherwise your data might be damaged. See [Miscellaneous](#miscellaneous) for instructions.

**Note**: When using docker-compose, make sure to backup and restore volume labels. See [Miscellaneous](#miscellaneous) for more information.

## Backup

Syntax:

docker run -v [volume-name]:/volume --rm --log-driver none loomchild/volume-backup backup > [archive-path]

For example:

docker run -v some_volume:/volume --rm --log-driver none loomchild/volume-backup backup > some_archive.tar.bz2

will archive volume named `some_volume` to `some_archive.tar.bz2` archive file.

**Note**: `--log-driver none` option is necessary to avoid storing an entire backup in a temporary stdout JSON file. More info in [Docker logging documentation](https://docs.docker.com/config/containers/logging/configure/) and in [this issue](https://github.com/loomchild/volume-backup/issues/39).

**WARNING**: This method should not be used under PowerShell on Windows as no usable backup will be generated.

### Backup to a file (deprecated)

Syntax:

docker run -v [volume-name]:/volume -v [output-dir]:/backup --rm loomchild/volume-backup backup [archive-name]

For example:

docker run -v some_volume:/volume -v /tmp:/backup --rm loomchild/volume-backup backup archive1
docker run -v some_volume:/volume -v /tmp:/backup --rm loomchild/volume-backup backup some_archive

will archive volume named `some_volume` to `/tmp/archive.tar.bz2` archive file.
will archive volume named `some_volume` to `/tmp/some_archive.tar.bz2` archive file.

## Restore

**Note**: This operation will delete all contents of the volume
Syntax:

docker run -i -v [volume-name]:/volume --rm loomchild/volume-backup restore < [archive-path]

For example:

docker run -i -v some_volume:/volume --rm loomchild/volume-backup restore < some_archive.tar.bz2

will clean and restore volume named `some_volume` from `some_archive.tar.bz2` archive file.

**Note**: Don't forget the `-i` switch for interactive operation.
**Note** Restore will fail if the target volume is not empty (use `-f` flag to override).

### Restore from a file (deprecated)

Syntax:

docker run -v [volume-name]:/volume -v [output-dir]:/backup --rm loomchild/volume-backup restore [archive-name]

For example:

docker run -v some_volume:/volume -v /tmp:/backup --rm loomchild/volume-backup restore archive1
docker run -v some_volume:/volume -v /tmp:/backup --rm loomchild/volume-backup restore some_archive

will clean and restore volume named `some_volume` from `/tmp/some_archive.tar.bz2` archive file.

## Miscellaneous

1. Upgrade / update volume-backup
```
docker pull loomchild/volume-backup
```

1. volume-backup is also available from GitHub Container Registry (ghcr.io), to avoid DockerHub usage limits:
```
docker pull ghcr.io/loomchild/volume-backup
```
**Note**: you'll need to write `ghcr.io/loomchild/volume-backup` instead of just `loomchild/volume-backup` when running the utility.

1. Find all containers using a volume (to stop them before backing-up)
```
docker ps -a --filter volume=[volume-name]
```

1. Exclude some files from the backup and send the archive to stdout
```
docker run -v [volume-name]:/volume --rm --log-driver none loomchild/volume-backup backup -e [excluded-glob] > [archive-path]
```

1. Use different compression algorithm for better performance
```
docker run -v [volume-name]:/volume --rm --log-driver none loomchild/volume-backup backup -c pigz > [archive-path]
```

1. Show simple progress indicator using verbose `-v` flag (works both for backup and restore)
```
docker run -v [volume-name]:/volume --rm --log-driver none loomchild/volume-backup backup -v > [archive-path]
```

1. Pass additional arguments to the Tar utility using `-x` option
```
docker run -v [volume-name]:/volume --rm --log-driver none loomchild/volume-backup backup -x --verbose > [archive-path]
```

1. Directly migrate the volume to a new host
```
docker run -v [volume-name]:/volume --rm --log-driver none loomchild/volume-backup backup | ssh [receiver] docker run -i -v [volume-name]:/volume --rm loomchild/volume-backup restore
```
**Note**: In case there are no traffic limitations between the hosts you can trade CPU time for bandwidth by turning off compression via `-c none` option.

will clean and restore volume named `some_volume` from `/tmp/archive.tar.bz2` archive file.
1. Volume labels are not backed-up or restored automatically, but they might be required for your application to work (e.g. when using `docker-compose`). If you need to preserve them, create a label backup file as follows: `docker inspect [volume-name] -f "{{json .Labels}}" > labels.json`. When restoring your data, target volume needs to be created manually with labels before launching the restore script: `docker volume create --label "label1" --label "label2" [volume-name]`.
138 changes: 121 additions & 17 deletions volume-backup.sh
Original file line number Diff line number Diff line change
@@ -1,37 +1,137 @@
#!/bin/sh
#!/bin/bash

usage() {
echo "Usage: volume-backup <backup|restore> <archive>"
exit
>&2 echo "Usage: volume-backup <backup|restore> [options]. Reads from stdin and writes to stdout. Can also read/write files (deprecated)."
>&2 echo ""
>&2 echo "Options:"
>&2 echo " -c <algorithm> chooose compression algorithm: bz2 (default), gz, xz, pigz, zstd and 0 (none)"
>&2 echo " -e <glob> exclude files or directories (only for backup operation)"
>&2 echo " -f force overwrite even if target volume is not empty during restore"
>&2 echo " -x <args> pass additional arguments to the Tar utility"
>&2 echo " -v verbose"
}

backup() {
mkdir -p `dirname /backup/$ARCHIVE`
tar -cjf /backup/$ARCHIVE -C /volume ./
if [ -z "$(ls -A /volume)" ]; then
>&2 echo "Volume is empty or missing, check if you specified a correct name"
exit 1
fi

if ! [ "$ARCHIVE" == "-" ]; then
mkdir -p `dirname /backup/$ARCHIVE`
fi

tar -C /volume "${TAROPTS[@]}" -cf $ARCHIVE_PATH ./
}

restore() {
if ! [ -e /backup/$ARCHIVE ]; then
echo "Archive file $ARCHIVE does not exist"
if ! [ "$ARCHIVE" == "-" ]; then
if ! [ -e $ARCHIVE_PATH ]; then
>&2 echo "Archive file $ARCHIVE does not exist"
exit 1
fi
fi


if ! [ -z "$(ls -A /volume)" -o -n "$FORCE" ]; then
>&2 echo "Target volume is not empty, aborting; use -f to override"
exit 1
fi

rm -rf /volume/* /volume/..?* /volume/.[!.]*
tar -C /volume/ -xjf /backup/$ARCHIVE
tar -C /volume/ "${TAROPTS[@]}" -xf $ARCHIVE_PATH
}

# Needed because sometimes pty is not ready when executing docker-compose run
# See https://github.com/docker/compose/pull/4738 for more details
# TODO: remove after above pull request or equivalent is merged
sleep 1
OPERATION=$1

if [ $# -ne 2 ]; then
usage
fi
TAROPTS=()
COMPRESSION="bz2"
FORCE=""

OPERATION=$1
OPTIND=2

while getopts "h?vfc:e:x:" OPTION; do
case "$OPTION" in
h|\?)
usage
exit 0
;;
c)
if [ -z "$OPTARG" ]; then
usage
exit 1
fi
COMPRESSION=$OPTARG
;;
e)
if [ -z "$OPTARG" -o "$OPERATION" != "backup" ]; then
usage
exit 1
fi
TAROPTS+=(--exclude $OPTARG)
;;
f)
if [ "$OPERATION" != "restore" ]; then
usage
exit 1
fi
FORCE=1
;;
v)
TAROPTS+=(--checkpoint=.1000)
EOLN=1
;;
x)
if [ -z "$OPTARG" ]; then
usage
exit 1
fi
# Note: it doesn't support nested quotes, e.g. -x '-I "zstd -10"'
OPTARR=($OPTARG)
TAROPTS=(${TAROPTS[@]} ${OPTARR[@]})
;;
esac
done

shift $((OPTIND - 1))

case "$COMPRESSION" in
xz)
TAROPTS+=(-J)
EXTENSION=.tar.xz
;;
bz2)
TAROPTS+=(-j)
EXTENSION=.tar.bz2
;;
gz)
TAROPTS+=(-z)
EXTENSION=.tar.gz
;;
pigz)
TAROPTS+=(-I pigz)
EXTENSION=.tar.gz
;;
zstd)
TAROPTS+=(-I zstd)
EXTENSION=.tar.zstd
;;
none|0)
EXTENSION=.tar
;;
*)
usage
exit 1
;;
esac

ARCHIVE=${2%%.tar.bz2}.tar.bz2
if [ -z "$1" ] || [ "$1" == "-" ]; then
ARCHIVE="-"
ARCHIVE_PATH=$ARCHIVE
else
ARCHIVE=${1%%$EXTENSION}$EXTENSION
ARCHIVE_PATH=/backup/$ARCHIVE
fi

case "$OPERATION" in
"backup" )
Expand All @@ -44,3 +144,7 @@ restore
usage
;;
esac

if ! [ -z "$EOLN" ]; then
>&2 echo
fi