3

I would like to make a rsync backup of a Docker volume on a remote host.

This method should have the following advantages:

  • rsync files with user and owner permissions that are not granted to the backup host
  • does not require additional port/s
  • rsync any kind of docker volume

This should let me rsync any volume without needing to use root on either the source or destination machine. Although it is a bit involved, I think I'm close to coming up with a robust solution that will be very easy to use.

The idea is to simply use rsync over ssh but instead of letting rsync invoke ssh directly, wrap the ssh command in a script that will:

  1. ssh into the destination host (just like rsync does)
  2. start a small alpine container mounting the volume with rsync source data
  3. pass rsync's command into that new container

The goal is to keep the stdin and stdout streams in-tact so the [sender] and [receiver] rsync process can talk.

This is what I have. I think I'm unsuccessful in keeping the stdin and stderr in-tact.

# prepare the remote host docker run -it alpine apk add rsync docker commit `docker ps -q -l` alpine-rsync 

On the local machine (or backup server) ./ssh-rdocker

#!/bin/sh DOCKER_VOLUME=${1?-docker volume}; shift 1 # example rsync parameters # -l debian ovh rsync --server --sender -nlogDtpre.iLsfxC . /data if [ "$1" != "-l" ] then echo Call this script from rsync exit 1 fi shift 1; # -l user=$1; shift 1 host=$1; shift 1 # Run rsync's command in a remote docker container set -o xtrace # only for debugging ssh -l $user $host sh - << SH set -o xtrace # only for debugging docker run -i --rm -v $DOCKER_VOLUME:/data:ro alpine-rsync sh - << RS set -o xtrace # only for debugging eval "$@" RS SH 

And the dry-run .. Even when the set -o xtrace messages are removed, same results. I'll leave them on for documentation purposes.

$ rsync -a --dry-run -e './ssh-rdocker synapse_files' debian@ovh:/data ./dest + ssh -l debian ovh sh - + docker run -i --rm -v synapse_files:/data:ro alpine-rsync sh - + eval 'rsync --server --sender -nlogDtpre.iLsfxC . /data' + rsync --server --sender -nlogDtpre.iLsfxC . /data rsync: connection unexpectedly closed (0 bytes received so far) [sender] rsync error: error in rsync protocol data stream (code 12) at io.c(226) [sender=3.1.3] rsync: connection unexpectedly closed (0 bytes received so far) [Receiver] rsync error: error in rsync protocol data stream (code 12) at io.c(235) [Receiver=3.1.2] 

This is an alternative way to wrap everything:

# [...] same as ./ssh-rdocker from above, until: # Run rsync's command in a remote docker container ssh -l $user $host "exec \$SHELL -c \"docker run --rm -v $DOCKER_VOLUME:/data:ro alpine-rsync sh -c '$@' \" " 

Which appears to suffer from the same issue:

$ rsync -a --dry-run -e './ssh-rdocker synapse_files' debian@ovh:/data ./dest rsync: connection unexpectedly closed (0 bytes received so far) [sender] rsync error: error in rsync protocol data stream (code 12) at io.c(226) [sender=3.1.3] rsync: connection unexpectedly closed (0 bytes received so far) [Receiver] rsync error: error in rsync protocol data stream (code 12) at io.c(235) [Receiver=3.1.2] 

What do you think, am I'm I loosing the link between stdin / stdout in the process chain? I must be getting stderr back because I here from both rsync processes.

Once this is fixed, the final step is to wrap the local side in an alpine container too so that the files may be received and written to a local volume with any owner or group permission without error (omitted for brevity).

2 Answers 2

2

Here is IMHO a somewhat more elegant solution:

  1. build a docker image based on alpine with ENTRYPOINT set to "rsync", Dockerfile like this:
FROM alpine:latest RUN apk add --no-cache rsync ENTRYPOINT ["rsync"] 

I called it alpine-rsync.

  1. pull that image on remote server

  2. Now you can invoke rsync with less escaping, with --rsync-path="docker run -v $DOCKER_VOLUME:/data -i alpine-rsync" like this:

rsync -avP --rsync-path="docker run -v $DOCKER_VOLUME:/data -i alpine-rsync" remotehost:/data/ . 
1
  • That’s just perfect! I knew about rsync-path but did not realize it could work to stream data from within a container. More people should know about this, it’s an excellent way to backup a named volume! Commented Aug 14, 2023 at 14:42
0

Only 1 case will work:

$ echo 1 | sh - <<SH cat SH $ echo 1 | exec sh -c "docker run --rm alpine sh -c \"cat\" " $ echo 1 | exec sh -c "docker run --rm -i alpine sh -c \"cat\" " 1 

So, the single-line docker run command just needed -i (interactive):

# Run rsync's command in a remote docker container ssh -l $user $host "exec \$SHELL -c \"docker run --rm -i -v $DOCKER_VOLUME:/data:ro alpine-rsync sh -c '$@' \" " 

Unfortunately it appears that the example with complex escaping is necessary.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.