docker系列 使用docker基于syncthing实现多点文件夹同步之详细教程
本文最后更新于 294 天前,其中的信息可能已经有所发展或是发生改变,如有失效可到评论区留言。

前言

其实,咋一想的话,文件夹同步这个需求,网上解决方案貌似很多,搜索了半天,结合自己的使用经验,我简单的把这些沾边的解决方案分为3类:
1、单APP类方案
以sync folders为代表,局域网范围的win、macos系统可用,使用简单,缺点是只能局域网范围使用,且只支持win和macos,讲道理,还是非常好用的:

image.png

2、网盘类解决方案
以nextcloud为代表:
image.png

这类个人网盘类应用,往往需要先部署server端,然后其他各个需要同步数据的节点通过安装client端连接server端来使用,优点是可以跨广域网使用,缺点是client端只能桌面系统,且server端部署需要公网IP地址,同时client同步的速度受限于client和server端之间的连接速度(可以通过为server端部署CDN的方式来解决速度问题)。
3、基于第3方存储类备份同步方案

以rclone、duplicati为代表,这类方案将需要备份或者同步的文件都存放在第3方存储上,然后各个节点都部署应用,通过访问第3方存储来实现备份或者同步文件的目的:例如rclone 支持 40 多种云端存储,从普通的网盘(OneDrive、Google Drive、Dropbox 等)到云端对象储存(Amazon S3、阿里云OSS等)再到各种传输协议(FTP、SFTP、WebDav)。

在这3类方案中,第3种方案的适应性最广,以rclone为例:既可以支持跨广域网,又能够同时支持桌面系统和cli界面,不过麻烦的是需要使用第3方存储来作为中转(或者有公网IP可以自建FTP、SFTP、WebDav),并且本质上这类方案主要的目的是备份本地数据到云存储或者把云存储上的数据拉回本地,其主要目的其实还是是备份和恢复,虽然可以通过alist之类的方法将云盘数据挂载到本地(rclone自身就支持挂载),但是这个和传统意义上的文件夹数据同步的需求还是不一样的。

那如果我仅仅就想简单的跨广域网在不同系统之间(macos、linux、win)定时同步几个目录,不想折腾其他有的没的,有没有办法呢?

还是有,那就是本篇文章要介绍的基于网络本身的专业同步工具:syncthing。

syncthing实现原理

syncthing其实只是一个不需要安装的可执行程序,它不需要像nextcloud那样提前部署server端,也不需要像rclone一样借助第3方存储,只需要在各个需要同步数据的设备上直接运行syncthing,然后简单设置一下就行了。

同样都是可执行程序的方式,syncthing和前面提到的sync folders相比适用性如何呢?这要看需要同步的网络环境是局域网范围还是广域网范围,并且使用端是桌面端还是cli端了。
1、局域网环境
1.1、纯桌面端
这种情况下,讲道理,如果需要文件夹同步的节点都是桌面端,我觉得sync folders貌似更好使,这种情况下syncthing没太大优势。
1.2、桌面端、CLI端混杂
这种情况下,就可以使用syncthing了:可以在所有端都部署syncthing;也可以桌面端部署sync folders,CLI端部署syncthing,最后拿一个端同时部署sync folders和syncthing,就可以全部打通,不过这种方式需要注意同步的方向问题:比如可以设置一台CLI端syncthing为仅发送,其他CLI端的syncthing为仅接收,然后通过同时部署sync folders和syncthing的端将内容同步到所有桌面端去(sync folders也可以通过设置同步类型来实现只发送或者只接收的效果)。
2、广域网环境
这种情况下,不管是桌面端还是CLI端,直接全部部署syncthing就行了。

为什么syncthing能够不借助第3方直接实现跨广域网同步呢?这其实是依赖于syncthing的发现服务器和中继服务器。

syncthing的"设置"-"连接"的界面如下:

image.png

启用全局发现功能以后,在跨广域网时就能提供stun服务帮助用户进行NAT穿透。


上图中提到的到"全局发现"和"启用中继"这2个选项,包含两个重要的功能:syncthing的连接通告服务和中继服务。
1、连接通告服务:
连接通告服务的作用是在一个syncthing端点上主动添加另一个syncthing端点时,另一个端点会收到连接通告服务发来的通知,询问是否接受,如果这个端点选择接受,两个端点就会成功的相互添加对方为远程设备。
2、中继服务:
中继服务其实包含了2个独立的部分:stun服务和turn服务。stun服务会收到双方发来的信息(网卡IP、监听端口等),当然,这个信息一般都不能直接使用(可能是内网信息),需要stun服务结合自己收到syncthing的数据包的真实源地址和端口一起来判断两个端点所处位置前的NAT类型(NAT1、2、3、4),判断能否打洞,如果能成功打洞,双方就能直接根据stun提供的信息进行点对点连接,这种同步文件的速度就会比较快;而如果不能打洞,就只能交给turn服务器全权处理了,这种同步文件的速度就会比较慢,取决于中继服务器给每个用户分配的带宽(具体速度还要除以2)以及使用的人数多少。

因为syncthing本来在网上就部署了公用的发现服务器和中继服务器,所以我们部署的syncthing才能在广域网上直接使用,只不过,使用的体验取决我们本身的NAT类型、我们部署的syncthing端和发现服务器以及中继服务器的通信效果等(默认提供的发现服务器和中继服务器都是国外的,国内使用的体验肯定好不到哪里去~)。


顺便提一下,在syncthing的高级设置里其实是可以看到stun相关的设置的,Stun Server还可以直接设置为你自己搭建的stun服务器:

image.png

这是因为NAT穿透其实就是基于stun服务(stun的原理以及如何搭建自己的stun服务器可以参见我另一篇文章:docker系列 使用docker基于coturn搭建自己的stun/turn服务器),所以要想取得最好的效果,而你又不怕折腾,可以使用自己搭建的stun服务器、自己搭建的发现服务器、自己搭建的中继服务器。。这个我后面的章节会单独讲。

部署syncthing

直接使用syncthing的可执行程序

github上的下载链接为:https://github.com/syncthing/syncthing/releases

其实,讲道理,syncthing在linux上就是一个可执行文件,下载后赋予执行权限,然后直接运行就好了,不一定非要折腾docker,还不会遇到啥权限问题,只是需要注意,最好使用一个非root的一般权限账号来运行。

我部署的方式还是选择docker,原因只是因为统一到docker上方便管理和记忆:毕竟年纪大了,我怕我以后记不住到底部署了多少脚本。。。

使用docker方式搭建syncthing

在宿主机上创建需要映射到容器内部的目录

mkdir -p /docker/syncthing/config #用于存放syncthing配置文件
mkdir -p /docker/syncthing/data #用于存放需要同步的数据

搭建syncthing

docker run格式的命令如下:

docker run --name syncthing  -d --restart=always \
  --hostname=syncthing #可选项 \
  -e PUID=1000 -e PGID=1000 \ #可选项,如果docker访问挂载的目录出现权限问题的时候可以采用,在宿主机里的使用id username命令来获取PUID和PGID
  -e TZ=Asia/Shanghai \ #指定时区
  -p 8384:8384 \ # 管理gui的端口,请根据自己实际环境情况指定
  -p 22000:22000/tcp \ #指定宿主机上tcp的监听端口,请根据自己实际情况修改,最好不变
  -p 22000:22000/udp \ #指定宿主机上udp的监听端口,请根据自己实际环境修改,最好不变
  -p 21027:21027/udp \ #发现协议使用的端口,请根据自己实际环境修改,最好不变
  -v /docker/syncthing/config:/config \ #挂载宿主机上的指定目录到容器内部特定路径,这里是配置文件所在目录
  -v /docker/syncthing/data:/data1 \ #挂载宿主机上的指定目录到容器内部特定路径,这里主要是需要同步的数据所在的目录,可以指定多个,比如data2,data3等,也可以直接将宿主机上原有的需要同步的目录直接映射过来,不过需要注意权限问题,比如755改成777,否则可能会同步不了,不要问我怎么知道的。
  lscr.io/linuxserver/syncthing:latest

注:请自行删掉#及其后面的注释内容。

其实,如果主要是局域网内使用且需要使用局域网主动发现,并且8384 tcp 、22000 tcp/udp 、21027 udp这几个端口又没有使用的话,可以直接用host类型部署(注意:这种部署方式linux下有效,macos下是无效的),docker run格式命令如下:

docker run --name syncthing  -d --restart=always --net=host \
  --hostname=syncthing \
  -e TZ=Asia/Shanghai \
  -v /docker/syncthing/config:/config \
  -v /docker/syncthing/data:/data1 \
  lscr.io/linuxserver/syncthing:latest

依次以docker方式创建3个syncthing节点:syncthing-macmini、syncthing-intermini,syncthing-tc。syncthing-macmini部署在我的m1 macmini 8g乞丐版上,采用-p映射端口方式部署(docker在macos上不支持host方式部署);syncthing-intermini部署在我的13代i5 cpu的高档mini主机上,位于和syncthing-macmin同一个局域网网段,采用host方式部署(为了后面的试验);syncthing-tc部署在腾讯云轻量服务器上,和syncthing-macmini一样,采用-p映射端口的方式部署(因为就算以host方式部署也没用)。

配置syncthing

初始化

使用http://宿主机ip:8384访问syncthing-macmini,初次访问会弹出如下询问,这个大家随意选择,是或否都行:

image.png

进入界面之后首先需要创建管理员用户名密码:
image.png

image.png

设置完成后会弹出登录认证页面,使用刚才创建的用户名密码登录:
image.png

然后进入正式的配置页面:
image.png

同理初始化syncthing-intermini和syncthing-tc。

注:初始化所有节点的时候先不用添加同步文件夹,后面一起设置。

添加远程设备

在syncthing-macmini端开始添加其他两个节点。

添加syncthing-intermini节点

直接点击远程设备部分红框中的"添加远程设备":

image.png

因为syncthing-intermini是采用host方式部署的,所以在下图中可以直接从附近的设备中看到:
image.png


如果不是采用host方式部署,则无法在附近的设备中看到,所以需要单独去syncthing-intermini上复制设备id:

image.png

image.png


image.png

image.png

然后登录到syncthing-intermini节点上,可以看到有来自syncthing-macmini的添加请求:
image.png

点击添加设备以后会出现syncthing-macmini的具体信息,这个时候,直接点击右下角保存即可:
image.png

然后可以看到syncthing-intermini的远程设备已经有了syncthing-macmini:
image.png

然后我们可以看到syncthing-macmini上也已经成功添加了syncthing-intermini的远程设备:

image.png

上图中一大堆地址,是因为我们在macmini上添加intermini时候,地址列表我们选择了默认的dynamic,所以是通过默认的公网上的stun服务器和中继服务器,一起来判断有哪些连接的方式,导致下面这么一大堆的选择,有些可用,有些不可用。其实对于同一个局域网内的设备而言,没必要整这么复杂,所以我们可以直接在syncthing-macmini上的远程设备中,修改syncthing-intermini的地址列表,将默认的dynamic修改为tcp://intermini局域网IP:22000,如下图:
image.png

然后可以看到,远程设备中,syncthing-intermini的地址已经变了:
image.png

而同时,syncthing-intermini中,远程设备syncthing-macmini的地址也变了:
image.png

添加syncthing-tc节点

同理添加syncthing-tc节点,只不过因为这是腾讯云轻量服务器上的节点,如果需要使用公网IP连接的话,需要提前在控制台的防火墙里打开22000 tcp/udp、8384 tcp、21027 udp这些端口:

image.png

image.png

至此,在syncthing-macmini上已经成功添加其他两个节点:
image.png

添加同步文件夹

在主节点上先添加同步文件夹

假设我们需要同步的内容位于syncthing-macmini容器内/data1目录,那么我们需要先在主节点syncthing-macmini上添加:

image.png

image.png

image.png

image.png

image.png

image.png

如果前面勾选了增加忽略模式,就会出现如下界面:
image.png

随后同步文件夹就成功添加了:
image.png

注:syncthing会在添加的同步文件夹里新建一个名为".stfolder"的目录,如果因为权限问题无法添加这个目录,会在web页面上提示无法创建这个文件夹。大家看到这种报错就要知道出现了权限问题:如果是docker环境,就要考虑使用-e PUID= -e PGID=的参数指定合理的宿主机真实用户权限,或者把宿主机上映射到容器内部的目录权限从755改为777;如果是直接运行syncthing执行文件的方式,可以直接使用修改目录权限的方式。

将主站上的同步文件夹共享给其他节点

image.png

因为我前面在创建文件夹的时候已经设置好了版本控制、忽略模式、高级等选择,所以这里直接在共享里选择2个远程设备然后直接保存即可,如下图:
image.png

然后在其他两个节点上会分辨收到来自syncthing-macmini的共享文件夹请求:
image.png

image.png

点击红框中的"添加"后,会进入添加同步文件夹的选项:
image.png

image.png

image.png

同理在syncthing-tc节点上也完成一样的步骤,最终完成后可以在syncthing-macmini节点上看到同步情况:
image.png

注:同步速度取决于syncthing节点之间能否选择最优的路径,如果没有选择最优路径,就可能出现明明是同一个局域网内,走内网传输最快,却偏偏去走最慢的中继服务器,这是因为syncthing之间对彼此的位置判断错误,这种情况在docker部署方式中很常见,而如果是linux系统且以host方式部署,那么在同一个内网网段里正确识别的几率就非常高了。不过其实没关系,只要按照我们前面讲过的方法,在每个节点的远程设备里的地址列表里手动指定正确的地址即可。

进阶使用1:自建发现服务器和中继服务器

理论上,只要我们部署syncthing是联网的环境,一般都能连上互联网上的公用的syncthing发现服务器和中继服务器,不过不排除有一些特殊的环境,比如纯内网环境,或者运营商网络限制导致连不上公用发现服务器和中继服务器,这个时候如果我们有条件(有公网IPv4的家庭宽带、有固定公网IP的云主机、或者纯内网环境我们有可控的部署环境),是可以自建发现服务器和中继服务器的,这里我不准备多讲,就直接把docker命令贴出来,大家有兴趣可以自己研究。
发现服务器docker run格式命令:

docker run --name syncthing_discovery_server  -d --restart=always \
   -e PUID=1000 -e PGID=1000 \ #和前面一样,也是可选项
   -p 8443:8443 \
   -v /docker/syncthing/discosrv:/var/stdiscosrv \
   syncthing/discosrv:latest

中继服务器docker run格式命令:

docker run --name syncthing_relay_server  -d --restart=always \
   -e PUID=1000 -e PGID=1000 \
   -e pools="" \ #这里很重要,如果不加这个,你搭建的中继服务器默认会直接发布到网上公用中继服务器的列表中
   -p 22067:22067 \
   -v /docker/strelaysrv:/var/strelaysrv \
   syncthing/relaysrv:latest

上面的发现服务器和中继服务器的命令和镜像都是官方提供的,分成2个独立的docker,网上也有人把这2个合为一个docker,命令如下:

docker create  \
   --name=syncthing-relay-discosrv \
   -p 22067:22067 \
   -p 22070:22070  \
   -p 8443:8443  \
   --restart unless-stopped  \
   johngong/syncthing-relay-discosrv:latest

我没试过,大家有兴趣可以试试。


自建的发现服务器和中继服务器的设备ID在对应docker的日志中可以查到,使用docker log 容器名字,例如,我搭建的发现服务器设备ID:

image.png

中继服务器的设备ID:
image.png

syncthing在"设置"-"连接"的界面,将原来的default改为对应的发现服务器和中继服务器地址,也可以保留default,将中继服务器和发现服务器地址分别写成:"default,relay://"和"default,https://":
image.png

注:如果是纯内网环境,哪怕不是一个网段,也只需要建立发现服务器即可,用不上中继服务器,只不过可能需要在"远程设备"-"高级"-"地址列表"里手动使用"tcp://对方ip:22000"进行添加。

进阶使用2:直接配合虚拟组网使用

以tailscale实现的虚拟组网为例,在syncthing-macmini的远程设备syncthing-tc的地址列表里直接使用tailscale的地址:

image.png

这种方式的好处是腾讯云服务器上的防火墙端口都不用开,因为tailscale是直接通过wireguard vpn进入设备内核,不走传统的tcp协议。如果所有的节点都部署了tailscale,则相互直接可以直接使用对方的tailscale地址进行添加即可,根本就不需要中继服务器。

后话

如果仅仅是从同步的角度来讲,syncthing的确是最方便的:不需要部署server端,不需要依靠第3方存储,也同时支持gui和cli,实际使用起来也非常简单的。

我看了一下网友遇到的各种问题,要么是权限问题、要么是不理解发现服务器和中继服务器的工作机制,没有优化配置(地址列表手动修改对端IP)而导致的速度缓慢问题。其实如果进行了正确的配置,syncthing用起来还是非常爽的(像我,内网通信就走内网IP,广域网通信就走tailscale的IP)。

我现在的3个节点:syncthing-macmini实际上是wordpress的主站、syncthing-intermini是内网中wordpress主站的热备站,而syncthing-tc是腾讯云主机上部署的主站的镜像站点,现在达到的效果是主站设置了每周一次的自动备份到本地目录(/docker/wordpress/html/wp-content/wpvividbackups):

image.png

syncthing检测到主站的WPvivid完成了定期备份后,会自动同步到热备站和镜像站的WPvivid插件的相同路径下,然后只需要在热备站和镜像站的WPvivid插件里点击下方红框中扫描的按键:
image.png

主站同步过来的备份就会出现:
image.png

然后直接点击还原即可更新为最近一次主站备份时候的内容,这总比手动上传备份然后还原的技术逼格更高一点吧,虽然时间差不了多少。

有这个需求也是没办法,因为WPvivid计划任务备份到远程特点站点的时候,只能选择一个站点(我现在有热备站和镜像站点2个,以后可能更多),并且只能是FTP或者SFTP的方式,最蛋痛的是在远程站点上扫描并还原的时候,要求输入FTP或者SFTP的信息(IP、端口、用户名及密码),好烦,关键我经常忘记。。。现在有了syncthing之后,这个痛点总算解决了,心里舒坦了。

博客内容均系原创,转载请注明出处!更多博客文章,可以移步至网站地图了解。博客的RSS地址为:https://blog.tangwudi.com/feed,欢迎订阅;如有需要,可以加入Telegram群一起讨论问题。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
       
error:
zh_CN
春节
快乐