首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >高效地将多个客户端(防火墙后面)同步到服务器。

高效地将多个客户端(防火墙后面)同步到服务器。
EN

Unix & Linux用户
提问于 2020-09-08 04:11:21
回答 1查看 262关注 0票数 0

就像很多球队一样,我们现在有很多人在家工作。这些远程客户端位于防火墙后面(我们不控制防火墙),而且它们没有静态IP地址。简而言之,我们不能直接将SSH带入这些客户端。但是,客户端可以将SSH放入我们的服务器。(由于其他原因,已在所有客户端和服务器上设置了硬化SSH。)

我们的要求是在每个客户端上保持一组文件(在几个不同的目录中)保持同步,并有效地做到这一点。我试图避免让每个客户端每秒钟运行一个rsync命令。当服务器上的任何相关文件被更改时,最好通知客户端。

此外,我们的实现只能使用SSH、rsync、inotify工具以及bash或Python (以及awk、cut等工具)。具体来说,我们不能使用NextCloud、OwnCloud、SyncThing、SeaFile等。

服务器上唯一打开的传入端口是用于SSH的,我们希望维护或更新的唯一包是发行版存储库中的核心包。

我们的想法是让每个客户端建立一个指向服务器的反向SSH隧道。然后服务器可以运行这样的脚本:

代码语言:javascript
复制
#!/bin/bash
while true; do
    inotifywait -r -e modify,attrib,close_write,move,create,delete /path/to/source/folder
    for port_user in "$(netstat -Wpet | grep "ESTABLISHED" | grep 'localhost.localdomain:' | grep 'sshd:' | cut -d ':' -f2-3 | cut -d ' ' -f1,4)"; do
        uport=$(echo $port_user | cut -d ' ' -f1)
        uu=$(echo $port_user | cut -d ' ' -f2)
        sudo -u $uu rsync -avz -e "ssh -p $uport -i /home/$uu/.ssh/id_ed25519"  /path/to/source/folder $uu@localhost:/path/to/destination/folder
    done
done

我在寻求反馈。首先,上面的bash脚本可以改进或清理吗?例如,我似乎不得不使用太多的cut语句。

EDIT:以下是对roaima的优秀问题和评论的答复。

  1. 文件服务器上的脚本作为root运行。客户端上的脚本不是。
  2. & 7.这是netstat命令的示例输出。
代码语言:javascript
复制
netstat -Wpetl
tcp 0 0 localhost.localdomain:22222 0.0.0.0:* LISTEN  myuser 42137  8381/sshd: myuser
  1. “你有比赛条件.”-谢谢我们暂时不理会这个问题。
  2. “你有遗漏的问题.”-再次谢谢你。我相信这在客户端是很容易补救的。下面是将在用户登录时启动的客户端脚本:
代码语言:javascript
复制
#!/bin/bash

synchost=sync.example.com
syncpath="path/to/sync/folder"
uu=$(logname)
uport=222222 #hard code per client device
# initial sync upon connecting:
rsync -avzz -e "ssh -i /home/$uu/.ssh/id_ed25519"  /"$syncpath"/ $uu@$synchost:/"$syncpath"
# loop until script is stopped when user logs out
while true; do
    inotifywait -r -e modify,attrib,close_write,move,create,delete /"$syncpath"
    rsync -avzz -e "ssh -i /home/$uu/.ssh/id_ed25519"  /"$syncpath"/ $uu@$synchost:/"$syncpath"
done

还有一个随需应变脚本,用户可以在任何时候运行强制同步.这是上面没有while循环的脚本。

  1. 以下是服务器脚本的当前版本:
代码语言:javascript
复制
syncpath="path/to/sync/folder"
while true; do
    inotifywait -r -e modify,attrib,close_write,move,create,delete /"$syncpath"
    netstat -Wpetl | grep "LISTEN" | grep 'localhost.localdomain:' | grep 'sshd:' | while read proto rq sq local remote state uu inode prog
    do
        uport=${local#*:}
        sudo -u $uu rsync -avzz -e "ssh -p $uport -i /home/$uu/.ssh/id_ed25519"  /"$syncpath"/ $uu@localhost:/"$syncpath"
    done
done
  1. “您应该考虑每个ssh/rsync到客户端的超时,这样如果它们在尝试传输时断开连接,那么最终不会阻塞其他所有人”。

这是个好建议。但是,一些有效的rsync更新可能运行的时间比平均时间长得多。您能否建议一种适当的方法来处理正常和必要的长rsync更新,同时也处理更新期间客户端断开连接的罕见情况?

我有一个想法,一种方法,可以解决超时,以及(大部分)比赛条件,以非常非常简单的方式。首先,每个用户登录时的初始客户端同步应该负责长期运行的更新操作。因此,服务器端同步操作时间不会有如此长的右尾。我们可以优化超时参数和睡眠时间,并使用如下方法:

代码语言:javascript
复制
syncpath="path/to/sync/folder"
while true; do
    inotifywait -r -e modify,attrib,close_write,move,create,delete /"$syncpath"
    netstat -Wpetl | grep "LISTEN" | grep 'localhost.localdomain:' | grep 'sshd:' | while read proto rq sq local remote state uu inode prog
    do
        uport=${local#*:}
        timeout 300s sudo -u $uu rsync -avzz -e "ssh -p $uport -i /home/$uu/.ssh/id_ed25519"  /"$syncpath"/ $uu@localhost:/"$syncpath"
    done

    sleep 90

    netstat -Wpetl | grep "LISTEN" | grep 'localhost.localdomain:' | grep 'sshd:' | while read proto rq sq local remote state uu inode prog
    do
        uport=${local#*:}
        timeout 900s sudo -u $uu rsync -avzz -e "ssh -p $uport -i /home/$uu/.ssh/id_ed25519"  /"$syncpath"/ $uu@localhost:/"$syncpath"
    done
done

最后一条评论。为rsync命令显示的参数不是最终的。建议是值得赞赏的,但我们也打算花费一些时间来评估rsync命令的所有选项。

EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2020-09-08 08:51:51

许多想法

  1. 您的脚本(大概)是以root形式运行的,这样就可以运行netstat -Wpet并简化sudo -u ${user}操作。
  2. 使用反向连接(如ssh -R 20202:localhost:22 centralserver ),我无法从netstat | grep | grep | cut ...行获得端口和用户组合。netstat -Wpet \ grep“已建立”grep sshd: tcp 036中央服务器:ssh客户端:37226已建立的根238622975 15198/sshd: roaima,因此我无法有效地测试对脚本的可能更改。你想在这里看到什么?
  3. 您有一个争用条件,因此如果在inotifywait完成后更改了第二个文件,则在另一个文件被更改之前,它可能不会传播到所有目标系统。解决方法可能是侦听单个inotifywait实例中的事件,并在每个事件上运行rsync传输集。但是,取决于更新的频率,这可能会使客户端的网络连接饱和。
  4. 您有一个遗漏问题,因为在一组更改之后连接的客户端将在下一个文件更改之前不会接收到这些更改。如果更新是非常关键的,那么您需要考虑某种方法来立即更新客户端副本。
  5. 您应该考虑每个ssh/rsync到客户端的超时,以便如果它们在尝试传输时断开连接,那么最终不会阻塞其他所有人
  6. 给定这样的bash代码片段,您可以用变量操作(%#/操作符)替换cut语句,同时读取-r proto recvq sendq localaddrport状态用户inode pidprogram do localaddr="${localaddrport%:*}“localport="${localaddrport#*:}”${ foreignaddrport %:*}“foreignport="${foreignaddrport#*:}”pid="${pidprogram%/*}“program=”${pidprogram##*}“program=”;<(netstat -Wpet _ grep '\.*/sshd:') )> program="${program%:}“回声外部地址= $foreignaddr和端口= $foreignport”echo "PID = $pid,Program= $program“echo”名称=$name
  7. 如果我们可以看到您的netstat命令的预期输出,则可以使用awk简化行处理。
票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/608380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档