많은 팀과 마찬가지로 현재 집에서 일하는 사람들이 있습니다. 이러한 원격 클라이언트는 방화벽 뒤에 있으며(우리가 제어할 수 없음) 고정 IP 주소가 없습니다. 즉, SSH를 통해 이러한 클라이언트에 직접 액세스할 수 없습니다. 그러나 클라이언트는 SSH를 통해 우리 서버에 액세스할 수 있습니다. (다른 이유로 인해 강화된 SSH는 이미 모든 클라이언트와 서버에 설정되어 있습니다.)
우리의 요구 사항은 각 클라이언트에서 동기화된 파일 세트(여러 디렉터리에 있음)를 유지하고 이를 효율적으로 수행하는 것입니다. 저는 각 클라이언트가 rsync
NN초마다 명령을 실행하지 않도록 노력하고 있습니다. 서버의 관련 파일이 변경되면 클라이언트에 알리는 것이 좋습니다.
또한 우리의 구현에서는 SSH, rsync, inotify 도구, bash 또는 Python(및 awk, cut 등과 같은 도구)만 사용할 수 있습니다. 특히 NextCloud, OwnCloud, SyncThing, SeaFile 등은 사용할 수 없습니다.
서버에서 열려 있는 유일한 수신 포트는 SSH용이며, 유지 관리하거나 업데이트하려는 유일한 패키지는 배포 저장소의 핵심 패키지입니다.
아이디어는 각 클라이언트가 서버에 대한 역방향 SSH 터널을 설정하도록 하는 것입니다. 그러면 서버는 다음과 같은 스크립트를 실행할 수 있습니다.
#!/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
예를 들어, 너무 많은 진술을 사용해야 하는 것 같습니다.
편집: 다음은 roaima의 훌륭한 질문과 의견에 대한 답변입니다.
파일 서버의 스크립트는 루트로 실행됩니다. 클라이언트의 스크립트는 그렇지 않습니다.
& 7. 이것은 내 netstat 명령의 샘플 출력입니다.
netstat -Wpetl
tcp 0 0 localhost.localdomain:22222 0.0.0.0:* LISTEN myuser 42137 8381/sshd: myuser
"경쟁 조건이 있습니다..." - 감사합니다. 지금은 이 문제를 무시해 보겠습니다.
"질문이 빠졌네요..." - 다시 한 번 감사드립니다. 나는 이것이 클라이언트 측에서 쉽게 해결될 수 있다고 믿습니다. 이는 사용자가 로그인할 때 실행되는 클라이언트 스크립트입니다.
#!/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
.
- 이것은 서버 스크립트의 현재 버전입니다:
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
- "전송을 시도하는 동안 연결이 끊어지면 다른 사람을 차단하지 않도록 클라이언트의 각 ssh/rsync에 대해 시간 초과를 설정하는 것을 고려해야 합니다."
이것은 훌륭한 조언입니다. 그러나 일부 유효한 rsync
업데이트는 실행하는 데 평균보다 훨씬 오래 걸릴 수 있습니다. 일반적이고 필요한 긴 rsync
업데이트를 처리하는 동시에 업데이트 중에 클라이언트 연결이 끊어지는 드문 경우를 처리하는 적절한 방법을 제안할 수 있습니까?
저는 매우 간단한 방법으로 시간 초과와 (대부분) 경쟁 조건을 해결하는 아이디어를 가지고 있습니다. 첫째, 각 사용자 로그인 시 초기 클라이언트 측 동기화는 장기 실행 업데이트 작업을 처리해야 합니다. 따라서 서버 측 동기화 작업 시간은 오른쪽 꼬리가 그렇게 길지 않습니다. 제한시간 매개변수와 절전 시간을 최적화하고 다음 방법을 사용할 수 있습니다.
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
.
답변1
몇 가지 생각
귀하의 스크립트는 (아마도) 루트로 실행 중이므로
netstat -Wpet
작동하고sudo -u ${user}
작업이 단순화됩니다.예를 들어 역방향 연결을 사용하면
ssh -R 20202:localhost:22 centralserver
라인에서 포트와 사용자 조합을 얻을 수 없습니다netstat | grep | grep | cut ...
.netstat -Wpet | grep "ESTABLISHED" | grep sshd: tcp 0 36 centralserver:ssh client:37226 ESTABLISHED root 238622975 15198/sshd: roaima
따라서 스크립트에 가능한 변경 사항을 효과적으로 테스트할 수 없습니다. 여기서 무엇을 볼 것으로 예상하시나요?
경쟁 조건이 있으므로
inotifywait
완료 후 두 번째 파일이 변경되면 다른 파일이 변경되기 전에 해당 파일이 모든 대상 시스템에 전파되지 않을 수 있습니다.이 문제에 대한 해결책은 단일 인스턴스에서 이벤트를 수신하고
inotifywait
각 이벤트에 대해 일련의 전송을 실행하는 것일 수 있습니다.rsync
그러나 업데이트 빈도에 따라 클라이언트의 네트워크 연결이 포화될 수 있습니다.일련의 변경 후에 연결하는 클라이언트는 다음까지 해당 변경 사항을 수신하지 못하기 때문에 누락 문제가 있습니다.다음파일이 변경됩니다. 업데이트가 매우 중요하다면 연결하자마자 클라이언트 사본을 업데이트할 수 있는 방법을 고려해야 합니다.
ssh
rsync
전송을 시도하는 동안 연결이 끊어지면 다른 사람을 차단하지 않도록 클라이언트별 시간 초과를 고려해야 합니다.이와 같은 코드 조각이 있으면 명령문을 변수 조작( 및 연산자)
bash
으로 바꿀 수 있습니다 .cut
%
#
/
while read -r proto recvq sendq localaddrport foreignaddrport state user inode pidprogram name do localaddr="${localaddrport%:*}" localport="${localaddrport#*:}" foreignaddr="${foreignaddrport%:*}" foreignport="${foreignaddrport#*:}" pid="${pidprogram%/*}" program="${pidprogram#*/}"; program="${program%:}" echo "Foreign address = $foreignaddr and port = $foreignport" echo "PID = $pid, program = $program" echo "Name = $name" done < <(netstat -Wpet | grep '\<localhost.localdomain:.*\<ESTABLISHED\>.*/sshd:')
netstat
명령의 예상 출력을 볼 수 있는 경우awk
라인 처리를 단순화하는 데 사용할 수 있습니다.