通过 ssh 使用 Rsync 同步到 Docker 挂载卷

通过 ssh 使用 Rsync 同步到 Docker 挂载卷

我想要备份rsync远程主机上的 Docker 卷。

这种方法应该有以下优点:

  • rsync 文件userowner未授予备份主机的权限
  • 不需要额外的端口
  • rsync 任何类型的 docker 卷

这样我就可以 rsync 任何卷,而无需在源计算机或目标计算机上使用 root 权限。虽然有点复杂,但我认为我即将找到一个非常易于使用的强大解决方案。

这个想法是简单地通过 ssh 使用 rsync,但不是让 rsync 直接调用 ssh,而是将 ssh 命令包装在一个脚本中,该脚本将:

  1. ssh 进入目标主机(就像 rsync 一样)
  2. 启动一个小型 Alpine 容器,使用 rsync 源数据安装卷
  3. 将 rsync 的命令传递到新容器中

目标是保持 stdin 和 stdout 流完好无损,以便 [发送方] 和 [接收方] rsync 进程可以通信。

这就是我所拥有的。我认为我无法保持 stdin 和 stderr 完好无损。

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

在本地机器(或备份服务器)上 ./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

而且dry-run……即使set -o xtrace删除了消息,结果也是一样的。为了便于记录,我会保留它们。

$ 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]

这是包装所有内容的另一种方法:

# [...] 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 '$@' \" "

它似乎面临着同样的问题:

$ 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]

您觉得呢,我是否丢失了进程链中 stdin / stdout 之间的链接?我肯定恢复了 stderr,因为我从两个 rsync 进程中都看到过。

一旦解决了这个问题,最后一步就是将本地端也包装在高山容器中,以便可以接收文件并将其写入具有任何所有者或组权限的本地卷而不会出现错误(为简洁起见省略)。

答案1

我认为这是一个更优雅的解决方案:

  1. 基于 alpine 构建 docker 镜像将 ENTRYPOINT 设置为“rsync”,Dockerfile 如下:
FROM alpine:latest
RUN apk add --no-cache rsync
ENTRYPOINT ["rsync"]

我将其命名为 alpine-rsync。

  1. 将该图像拉至远程服务器

  2. 现在,您可以使用 --rsync-path="docker run -v $DOCKER_VOLUME:/data -i alpine-rsync" 来调用 rsync,减少转义,如下所示:

rsync -avP --rsync-path="docker run -v $DOCKER_VOLUME:/data -i alpine-rsync" remotehost:/data/ .

答案2

仅 1 种情况有效:

$ 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

docker run因此,只需要单行命令-iinteractive):

# 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 '$@' \" "

不幸的是,看起来带有复杂转义的示例是必要的。

相关内容