Em vez de um loop for, você pode executar os comandos em paralelo e, em seguida, coletar a saída sequencialmente na ordem desejada. Escrevi o seguinte script Ruby e usei-o por vários anos para instalações massivas de pacotes, mudanças rápidas na configuração e outras tarefas. Acelera muito as coisas:
Script: 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
Observações Diversas
O script acima depende de um padrão de nomenclatura padrão para os hosts. É node01 node02 ... node99 . Se todos os hosts tiverem nomes diferentes, você poderá criar aliases em / etc / hosts que sejam uniformes.
Como você tem mais servidores que eu, você precisaria ajustar meu script para usar algo como: n001 n002 ... n100 .
Depois de instalar um pacote, execute uma verificação. Eu uso Debian, mas em um sistema CentOS / RedHat seria algo como on-all-nodes-run yum info <package-name>
Eu uso on-all-nodes-run várias vezes por mês, mas em algum momento um nó inevitavelmente ficará inativo e acabará desatualizado. Então, além de on-all-nodes-run
, eu re-imagem os nós quando há chance de reiniciar (SystemImager, possivelmente KickStart, ...). O clsuter inteiro é recriado algumas vezes no pré-ano e sempre que um nó com falha de data é reiniciado.