Executar comandos automaticamente por SSH em muitos servidores

46

Há uma lista de endereços IP em um arquivo .txt, por exemplo:

1.1.1.1
2.2.2.2
3.3.3.3

Por trás de cada endereço IP, há um servidor e em cada servidor existe um sshd em execução na porta 22. Nem todos os servidores estão na known_hostslista (no meu PC, Ubuntu 10.04 LTS / bash).

Como posso executar comandos nesses servidores e coletar a saída?

Idealmente, eu gostaria de executar os comandos em paralelo em todos os servidores.

Vou usar autenticação de chave pública em todos os servidores.

Aqui estão algumas armadilhas em potencial:

  • O ssh solicita que eu coloque a chave ssh dos servidores no meu known_hostsarquivo.
  • Os comandos fornecidos podem retornar um código de saída diferente de zero, indicando que a saída é potencialmente inválida. Eu preciso reconhecer isso.
  • Uma conexão pode falhar ao ser estabelecida com um determinado servidor, por exemplo, devido a um erro de rede.
  • Deve haver um tempo limite, caso o comando seja executado por mais tempo do que o esperado ou o servidor fique inativo durante a execução do comando.

Os servidores são AIX / ksh (mas acho que isso realmente não importa.

LanceBaynes
fonte
1
Eu acho que não é uma duplicata, porque o link que você menciona nem contém SSH.
precisa saber é o seguinte
4
Se você não tiver feito isso, configure servidores ssh em todas as máquinas, faça um par de chaves pública / privada na máquina da qual trabalha e copie a chave pública nas contas do servidor para evitar mais problemas com a senha. Isso se aplica à minha resposta e também à do @ recatada.
Anthon

Respostas:

14

Supondo que você não consiga instalar o pssh ou outros, você pode fazer algo semelhante a:

tmpdir=${TMPDIR:-/tmp}/pssh.$$
mkdir -p $tmpdir
count=0
while IFS= read -r userhost; do
    ssh -n -o BatchMode=yes ${userhost} 'uname -a' > ${tmpdir}/${userhost} 2>&1 &
    count=`expr $count + 1`
done < userhost.lst
while [ $count -gt 0 ]; do
    wait $pids
    count=`expr $count - 1`
done
echo "Output for hosts are in $tmpdir"
Arcege
fonte
1
o que exatamente espera fazer neste script? ty!
precisa saber é o seguinte
o que acontece se uma chave de servidor não estiver no meu arquivo know_hosts?
precisa saber é o seguinte
5
colocar scripts em segundo plano cria processos filhos. Quando um processo filho termina, o slot e os recursos do processo permanecem no sistema até o processo pai terminar ou o processo pai 'espera' pelo filho. Esses processos "terminados por ainda presentes" são chamados de processos "zumbis". É um bom comportamento limpar após procesos filhos e recuperar recursos.
Arcege 19/08/11
1
Se não for conhecido, isso pode estragar tudo, mas você pode adicionar -o StrictHostKeyChecking=nopara evitar isso. No entanto, é melhor verificar todos os servidores a partir de uma linha de comando primeiro, para que as chaves do host possam ser adicionadas.
Arcege 19/08/11
1
Como mencionei, depois que o programa ssh é colocado em segundo plano e depois que sai, os recursos ainda são mantidos. O waitcomando recupera esses recursos, incluindo o código de retorno do processo (como os processos foram encerrados). Então, se mais tarde no programa, você colocar outro processo, digamos uma compactação, em segundo plano e precisar esperar por ela, sem esse loop, a espera recuperará um dos programas ssh concluídos, não a compactação - que ainda pode estar correndo. Você obteria um status de retorno no processo filho errado. É bom limpar depois de si mesmo.
Arcege 28/08/11
61

Existem várias ferramentas disponíveis que permitem efetuar login e executar uma série de comandos em várias máquinas ao mesmo tempo. Aqui estão alguns:

Caleb
fonte
1
Você pode adicionar pdsh à lista.
Riccardo Murri
1
Achei clusterssh bastante intuitivos de usar. Apenas meus 2 centavos ...
josinalvo
1
Eu uso pssh frequentemente. Funciona muito bem, embora eu gostaria de poder dizer que certos comandos remotos terão um código de saída diferente de zero, e isso não significa um erro. Isso é puramente cosmético.
Anthony Clark
1
@AnthonyClark, você pode acrescentar algo como "|| true" a esses comandos.
exic
16

Se você gosta mais de scripts Python do que bashscripts, o Fabric pode ser a ferramenta para você.

Na página inicial do Fabric :

O Fabric é uma biblioteca e ferramenta de linha de comando Python (2.5 ou superior) para otimizar o uso do SSH para tarefas de implantação de aplicativos ou administração de sistemas.

Ele fornece um conjunto básico de operações para a execução de comandos locais ou remotos do shell (normalmente ou via sudo) e upload / download de arquivos, além de funcionalidade auxiliar, como solicitar ao usuário em execução a entrada ou interromper a execução.

O uso típico envolve a criação de um módulo Python contendo uma ou mais funções e, em seguida, executá-las por meio da ferramenta de linha de comando fab.

Riccardo Murri
fonte
Fabric v1 foi incrível. Infelizmente, o Fabric v2 removeu a maioria dos recursos que o tornavam útil para este caso de uso - atualmente não é recomendado (junho de 2018).
Meekohi
11

Eu uso o GNU paralelo para isso, mais especificamente você pode usar esta receita:

parallel --tag --nonall --slf your.txt command

Com your.txtsendo o arquivo com o IP do servidor de endereços / nomes.

Anthon
fonte
Não há qualquer outra maneira usando apenas ssh Desde que eu estou usando meus servidores da empresa não quero para instalar pacotes adicionais
Özzesh
Claro, eu costumava fazer isso antes de sshexistir também, mas você precisa de alguma maneira de fazer login nos outros computadores e essas maneiras costumavam ser menos seguras (como rsh). Você não descreve o que está usando agora para ir de máquina em máquina ( telnet?, rsh?).
Anthon
1
@ Özzesh sim apenas no controlador
Anthon
1
@ Özzesh ver se a sua razão para não instalar GNU Parallel é coberto em oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html
Ole Tange
1
@OleTange Acabei de perceber quem comentou minha resposta% -). Obrigado por este excelente software.
Anthon
8

Configuração muito básica:

for host in $(cat hosts.txt); do ssh "$host" "$command" >"output.$host"; done

Autenticar com nome / senha não é realmente uma boa ideia. Você deve configurar uma chave privada para isso:

ssh-keygen && for host in $(cat hosts.txt); do ssh-copy-id $host; done
michas
fonte
1
este é o que eu tenho procurado !!!!! Obrigado michas
Özzesh
o script acima funciona bem para mim, mas depois de executar em 10 servidores, o script não responde. Como posso sair do servidor ssh ao qual estou conectado?
Zzzzesh
Você não precisa fazer logout explicitamente. Este "script" será executado apenas ssh $host $commandpara cada host. Tente executar esses comandos manualmente para descobrir o que está acontecendo.
michas 27/05
4

Eu sugiro Ansible.cc . É um gerenciador de configuração e despachante de comando.

Tom
fonte
2

Eu acho que você está procurando pssh e as versões paralelas relacionadas do usual scp, rsync, etc.

tiojamil
fonte
Este é um voto a menos de ser excluído, mas esta resposta posterior está em +10. Faz todo o sentido
Michael Mrozek
@MichaelMrozek É pior do que você imagina. O segundo dos dois VTDs é meu em um acidente com um clique feliz. Eu tenho essa guia aberta por alguns dias com a intenção de sinalizar ou executar ping para reverter meu VTD se ele foi excluído. Talvez você possa virar agora para limpar os votos.
Caleb
@Caleb corrigiu
Michael Mrozek
2

Criei uma ferramenta de código aberto chamada Overcast para facilitar esse tipo de coisa.

Primeiro você define seus servidores:

overcast import vm.01 --ip 1.1.1.1 --ssh-key /path/to/key
overcast import vm.02 --ip 2.2.2.2 --ssh-key /path/to/key

Em seguida, você pode executar vários comandos e arquivos de script entre eles, sequencialmente ou em paralelo, da seguinte maneira:

overcast run vm.* uptime "free -m" /path/to/script --parallel
Andrew Childs
fonte
2

O projeto Hypertable adicionou recentemente uma ferramenta ssh de vários hosts. Essa ferramenta é criada com libssh e estabelece conexões e emite comandos de forma assíncrona e paralela para máximo paralelismo. Consulte Ferramenta SSH de vários hosts para obter a documentação completa. Para executar um comando em um conjunto de hosts, execute-o da seguinte maneira:

$ ht ssh 1.1.1.1,2.2.2.2,3.3.3.3 uptime

Você também pode especificar um nome de host ou padrão de IP, por exemplo:

$ ht ssh 1.1.1.[1-99] uptime
$ ht ssh host[00-99] uptime

Ele também suporta uma --random-start-delay <millis>opção que atrasará o início do comando em cada host por um intervalo aleatório entre 0 e <millis>milissegundos. Essa opção pode ser usada para evitar problemas de rebanho trovejante quando o comando em execução acessa um recurso central.

Doug judd
fonte
2

Eu desenvolvi o collectnode Muito simples e eficaz para executar tarefas em vários servidores (janelas incluídas)

Como usar o CollectNode:

  1. Crie a lista de servidores para trabalhar:

    # cat hosts.file
    server1
    server2
    server3
    server4
    server5
    
  2. Execute o CollectNode passando a lista de saques:

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User'
    
  3. Opcionalmente, é possível filtrar os resultados, por exemplo, este comando exibe apenas o servidor em que a condição é realizada.

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User' --where="command contain User"
    

https://collectnode.com/5-tasks-collectnode-can-help-managing-servers/

fvidalmolina
fonte
1
Parece que você é o desenvolvedor do CollectNode. Nesse caso, você deve divulgar que na resposta ou isso é apenas spam.
Muru
desculpe, não era minha intenção, resposta modificada para ser mais específica.
fvidalmolina
1

Apenas um alerta para uma pergunta muito boa:

A melhor solução que encontrei é, não surpreendentemente, o tmux.

Você pode fazer o Ctrl-B: configurar painéis de sincronização no tmux para obter resultados incríveis. Você deve ter todas as suas conexões ssh abertas, em diferentes painéis de 1 janela do Tmux para isso.

Mikhail Krutov
fonte
0

Talvez algo assim funcione, para executar o comando em vários hosts? suponha que todos os hosts estejam configurados em .ssh / config para login sem senha.

$ < hosts.txt xargs -I {} ssh {} command

Y0NG
fonte
0

Crie um arquivo / etc / sxx / hosts

preencher assim:

[grp_ips]
1.1.1.1
2.2.2.2
3.3.3.3

compartilhe a chave ssh em todas as máquinas.

Instale o sxx do pacote:

https://github.com/ericcurtin/sxx/releases

Em seguida, execute o comando da seguinte maneira:

sxx username@grp_ips "whatever bash command"
ericcurtina
fonte
Onde está escrita a saída? Como são tratados os status de saída diferentes de zero? Por favor, não responda nos comentários; edite sua resposta para torná-la mais clara e completa.
G-Man diz 'Reinstate Monica'
0

Use o Paramiko http://www.paramiko.org/ e o paralelismo baseado em thread https://docs.python.org/3/library/threading.html . O código abaixo permite executar vários comandos em cada servidor em paralelo!

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
ssh.connect(hostname, port, username, password)
t = threading.Thread(target=tasks[index], args=(ssh, box_ip,))
t.start()

Nota: repita as instruções acima para cada servidor.

Sharma
fonte
0

Eu acho que "esperar" é o que você precisa.
Muitas pessoas nem sabem que existe. É um programa baseado em tcl que fará perguntas e possíveis respostas em seu nome. Dê uma olhada em https://wiki.tcl-lang.org/page/Expect

Clemente
fonte