防止在LVM快照期间访问服务器(Git / ssh)

如果在LVM快照时正在进行Git操作,则存储库可以(并且将)以损坏的状态进行快照。 (这已经讨论了很多http://www.reddit.com/r/programming/comments/1ax0oa/how_kdes_1500_git_repositories_almost_were_lost/ )

问题是如何正确解决这个问题。 Git访问是通过SSH(带密钥)通过git-shell到linux机器。 停止访问每晚20分钟这样的事情对我们部门来说不是问题,但恐怕魔鬼在细节中。

我到目前为止所做的是让我觉得我正在重新发明一些我不知道的轮子。 从一个cron工作:

#!/bin/bash # 0. # poll during 20 min for ongoing git usage to stop countdown=$((60*20)) while pgrep -u git >/dev/null ; do sleep 1 countdown=$((countdown-1)) if [ $countdown -eq 0 ] ; then break fi done #1 #disable login to the git user by setting the shell to /bin/nologin chsh -s /bin/nologin git #2 # # wait again for up to 20 min for all processes to complete # (we *may* have just missed it between step 1 and 2) # countdown=$((60*20)) while pgrep -u git >/dev/null ; do sleep 1 countdown=$((countdown-1)) if [ $countdown -eq 0 ] ; then break fi done #3 # kill too slow git sessions (This is actually safe) if pgrep -u git >/dev/null ; then killall -u git sleep 30 fi if pgrep -u git >/dev/null ; then killall -9 -u git sleep 10 fi if pgrep -u git >/dev/null ; then echo Failed to kill stale git $(pgrep -u git) fi #4 # make the lvm snapshot ... #5 # change back the shell chsh -s /usr/bin/git-shell git 

我渴望了解是否有更多的标准解决scheme,或者我的解决scheme是否有缺陷。

有关这种方法的东西感觉太过于手动。 我也不喜欢考虑像死去的进程这样的angular落案例。 另外,服务器可能会在脚本期间停机,所以我将不得不将shell重新设置为git-shell来修复(通过cron或启动时)。

我认为正确的方法是使用更合适的备份策略。 为什么你会使用LVM快照,当你可以使用git自己备份?

Simle,未经testing的例子

 #!/bin/sh cd /backups/git for repo in $(ssh repo_host ls /srv/git); do if [ ! -e $repo ]; then git clone --mirror repo_host:/srv/git/$repo else (cd $repo; git fetch origin) fi done 

为什么不阻止这段时间的任何sshlogin? 添加到sshd_config:

#DenyGroups <a supplementary group for all git users>

然后在备份cronjob的开始:

 sed -i -e 's/^#DenyGroups/DenyGroups/' sshd_config kill -HUP /var/run/sshd.pid 

并在完成时反转。 对于当前login的用户,我不知道其他选项,但是杀死他们的会话类似于你已经做的。 或等到他们注销。

我不知道这个标准化的解决scheme,你的方法对我来说是合理的。 几点注意事项:

  1. 我会更进一步,阻止所有非root用户login,因为您不希望用户在LVM操作运行时login并执行存储操作。 幸运的是,如果/etc/pam.d中的PAMconfiguration包含pam_nologin.so ,那么使用/etc/nologin就非常简单了。 许多发行版,但你会想testing。 man pam_nologin的细节。

  2. 使用pkill而不是pgrep + killall。 它使用与pgrep相同的进程匹配和返回代码逻辑。

  3. 您正在redirectSTDOUT,但不是STDERR。 我使用的一个技巧是将命令块封装在{}括号中,并redirect括号的输出。 请记住,这些括号需要返回或; 如果你正在做一个class轮,最后一个命令后。


#3的例子:

 { echo foo echo bar >&2 # output bar to STDERR } >/dev/null 2>&1