脚本在50台服务器上运行。 我如何确保只有一个执行特定的步骤?

我有一些工作需要在50多台服务器上完成。 第一步是将一些源代码的更新版本签出到一个共享目录(假设所有共享驱动器都已安装)。 其次是在每个服务器上执行一些工作。

我宁愿让这两个脚本在每台服务器上运行。 所有50多台服务器都是从一张磁盘映像中克隆出来的,对我来说,定制它们是不现实的。

当50个服务器运行第一个脚本时,我只想要第一个脚本尝试运行它来实际运行它。 其他我想简单地退出。 实际运行脚本的服务器应该更新共享目录,然后退出。 之后,第二个脚本将运行并根据第一台服务器获取的更新代码在所有服务器上执行该工作。

什么是最好的方法来做到这一点? 我可以可靠地让第一个脚本运行在一台服务器上,并创build一个文件,或者作为某种types的“信号灯”或“locking”,使其他服务器远离?

更复杂的是,我正在考虑让每个服务器上的相同cron文件运行脚本,这意味着所有脚本都可以同时运行,假设所有的时钟都是相同的。

我希望这些将从bash脚本运行。 这是否有道理?

编辑:更新的基础上的问题:

我们不希望每个服务器都试图检出它们自己的这些文件副本 – 它们在一个多GB的源代码库中,并且有50个以上的代码同时签出对于我们的源代码pipe理服务器来说是很困难的(而且不可扩展到100多台服务器)。

在50多台服务器上添加一个cronjob并不是什么大问题,但是用自己的configuration添加另一台定制的服务器是很困难的。 我们已经克隆了50台服务器 – 维护一台单独的服务器只是为了检查50多台服务器的最新源代码,看起来很浪费,而且会增加更多的开销,而不仅仅是将脚本添加到我们当前的服务器上。

三种解决scheme

  1. 手动运行“结帐”步骤,或者在其中一台服务器上单独运行一个脚本。 这似乎是最好的方法 – 否则你可能会遇到竞争条件。
  2. 如果您愿意接受竞争条件的机会,那么当第一个脚本运行时,您当然可以尝试创build特定的带date标记的文件。 或者,如果date足够可靠,则可以尝试检查签出文件的最后修改date。
  3. 如果自定义是非常严格的,那么让每个虚拟机都自己创build文件副本,而不是尝试使用共享卷。

其中每一个都有权衡,但是你还没有真正清楚为什么要这样devise解决scheme。

如果没有大量的工程来提供networking,那么networking就没有真正的primefaces性,工程越复杂,工程就越复杂。

有很多折衷考虑。 这个答案让你在工作完成一半时不知道该怎么做。

NFSv3在新的内核中支持一个primefaceslocking机制(很好,很老实的) http://nfs.sourceforge.net/#faq_d10 。 因此,理论上可以通过以下方式实现信号量的某种机制。

  1. 已完成的文件已存在于主机上。 (这是仅用于脚本2的信号)
  2. 使用O_EXCL打开主机上的“获取”文件。
  3. 将“完成”重命名为“done.old”。
  4. 在这里做你的特殊工作。
  5. 使用O_EXCL在主机上打开“完成的文件”。
  6. 取消关联“done.old”。
  7. 取消链接“获取”

下面是一些模板shell脚本的东西,试图这个。

 #!/bin/bash # WARNING: This is a cricital line! NEVER EDIT THIS set -e -o noclobber BASEPATH=/tmp cd "${BASEPATH}" # 1. A done file exists on the host already (this is a signal for script 2 only) # 2. Open an 'acquire' file on the host using `O_EXCL`. echo > 'acquire' # 3. Rename 'done' to 'done.old'. mv 'done' 'done.old' 2>/dev/null || : # 4. Do your special work here. echo "How much wood could a woodchuck chuck if a woodchuck could chuck wood?" # 5. Open a 'done' file using O_EXCL echo > 'done' # 6. Unlink 'done.old'. unlink 'done.old' || : # 7. Unlink 'acquire'. unlink 'acquire' 

其中最重要的一条是set -e -o noclobber两个目的的“一个set -e -o noclobber

  • 它确保任何命令失败脚本退出。
  • 脚本不会覆盖文件(使O_EXCL打开)。

set标准,最重要的function部分是echo > acquire ,它将自动打开获取文件。 如果失败(因为有其他人,即使TWO一次打开,只有一个会赢), set-e选项确保我们退出脚本。

不应该有两个脚本并行运行。 然而,这个脚本并没有提供一个接一个地运行两个脚本的解决scheme(在当前的forms下这是允许的)。 我想最好的办法是将“完成”文件改为一个有时间戳的命名文件,在stream程开始之前查找存在的文件。 因此,这假定其“安全”依赖于时间作为媒介来确定代码危害的安全性。

我提到这不是具体的。 目前这为您提供了两个进程不能同时声明文件的保证。 正如所提到的更多的修改,以便它不能开始存在的“完成”文件是必要的。

其他不包括的内容是:

  • 如果这个过程开始但是没有完成呢?
  • 如果共享目录在如何处理这个问题之前或中途不可用。
  • 如果主持人在第4步花太长的时间去做“安全”的东西,那么下一次运行的时候又会如何呢? 我们应该使用旧的实例一旦完成或新的实例?

为了解决这些问题,需要一个“击剑”机制(大量更换基础设施)来真正保证重新获得另一台主机的locking是安全的。

我可以build议以下,

提名一个服务器作为复制代码存储库。 然后,您可以以任何时间间隔更新该存储库。 其余的服务器可以testing是否存在本地存储库,然后rsync从指定的服务器上的文件。 这些信息可以存储在共享文件服务器空间中。 这将是很容易自动化,应该相当健壮。

另一个激进的解决scheme – >将使用BitTorrent同步。 存储库服务器将被读/写,而其他服务器将具有只读共享。 可能会更快,因为networking负载将在服务器之间共享。 可以通过configuration文件设置btsync,并且linux客户端运行良好。

编辑:你可以跳过激进解决scheme的存储库服务器,并坚持使用btsync。

干杯! 🙂

丹尼尔

您将不得不使用某种locking文件(在做任何事情之前)显示第一个脚本的所有者和时间运行。 当其他人试图执行脚本时,它应该查找locking文件,然后退出。 脚本结束时(如果运行)删除所述locking文件。