我管理着 100 多台服务器,有一些软件包需要更新。目前,我只有一个 shell 脚本,for loop
在所有服务器上运行并执行命令。
有人知道最好的(或更好的)方法来做到这一点吗?
答案1
如果您运行着 100 多台服务器,那么您真的应该研究一下配置管理系统,例如 cfengine、puppet、bcfg2 等。配置良好的系统能够非常轻松地推出常规软件包升级,几乎不需要或根本不需要额外的脚本。
答案2
我所做的是创建我自己的内部 repo(非常简单):
- 创建可访问 Web 的目录
- 将 RPM 放在那里
- 运行“createrepo ./”
- 通过将以下文件添加到您的 /etc/yum.repos.d/ 目录来将您的客户端指向那里:
name=My Repo baseurl=http://path/to/directory/above gpgcheck=0
您现在可以从创建的目录安装 RPM。
请注意,此解决方案没有固有的安全性...它不检查软件包的签名状态。设置 gpg 签名的步骤并不难,详细说明如下:http://mindtrove.info/articles/hosting-a-yum-repository/
答案3
我们有一个与 Aleksandr 类似开发的工具(这里是用 python 编写的,我之前的工作是用 perl 编写的),而且这种方法效果很好。
我见过专为此类事情设计的工具,引起了我的兴趣,达督但我还没有时间开始使用它。它的设计考虑到了可扩展性,因此如果您的环境可能会继续增长,您可能需要看看它。Capistrano 也值得研究。
答案4
您可以并行执行命令,然后按所需的顺序依次收集输出,而无需使用 for 循环。我编写了以下 Ruby 脚本,并将其用于大量软件包安装、快速配置更改和其他任务,已经使用多年。它大大加快了速度:
脚本:on-all-nodes-run
#!/usr/bin/ruby
EXCEPT = []
require "open3"
SSH_OPTIONS = ["-o PreferredAuthentications=hostbased,gssapi,gssapi-with-mic",
"-o ForwardX11=no",
"-o BatchMode=yes",
"-o SetupTimeOut=5",
"-o ServerAliveInterval=5",
"-o ServerAliveCountMax=2"
].join(" ")
SSH = "/usr/bin/ssh #{SSH_OPTIONS}"
MKDIR = "/bin/mkdir"
raise "give this command at least one argument" if ARGV.size < 1
COMMAND = ARGV[0..-1].join(' ')
output_o = {}
output_e = {}
FORMAT = "%Y-%m-%d_%H-%M-%S_#{(rand * 100).to_i}"
IO_CONNECTIONS_TO_REMOTE_PROCESSES = {}
def on_all_nodes(&block)
1.upto(32) do |i|
next if EXCEPT.include? i
node = "node#{i.to_s.rjust(2, '0')}"
block.call(node)
end
end
# Create processes
on_all_nodes do |node|
stdin, stdout, stderr = Open3.popen3("#{SSH} #{node} \"#{COMMAND}\"")
IO_CONNECTIONS_TO_REMOTE_PROCESSES[node] = [stdin, stdout, stderr]
end
has_remote_errors = false
# Collect results
on_all_nodes do |node|
stdin, stdout, stderr = IO_CONNECTIONS_TO_REMOTE_PROCESSES[node]
stdin.close
e_thread = Thread.new do
while line = stderr.gets
line.chomp!
STDERR.puts "#{node} ERROR: #{line}"
has_remote_errors = true
end
end
o_thread = Thread.new do
first = true
while line = stdout.gets
line.chomp!
puts "#{node} : #{line}"
end
end
# Let the threads finish
t1 = nil
t2 = nil
while [t1, t2].include? nil
if t1.nil?
t1 = e_thread.join(0.1) # Gives 1/10 of a second to STDERR
end
if t2.nil?
t2 = o_thread.join(0.1) # Give 1/10 of a second to STDOUT
end
end
end
exit(1) if has_remote_errors
其他备注
上述脚本依赖于主机的标准命名模式。它是节点01节点02...节点99。如果您的主机名称都不同,那么您可以在 /etc/hosts 中创建统一的别名。
因为您的服务器比我的多,所以您需要调整我的脚本以使用类似以下内容:N001 N002 ... N100。
安装软件包后运行检查。我使用 Debian,但在 CentOS/RedHat 系统上,它会是这样的on-all-nodes-run yum info <package-name>
我用在所有节点上运行每个月几次,但某个节点不可避免地会宕机,最终会过期。因此,最重要的是,on-all-nodes-run
当有机会重新启动时,我会重新映像节点(SystemImager,可能是 KickStart,...)。整个集群每年都会重新映像几次,每次发生故障的过期节点都会重新启动。