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.



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"

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:


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.


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.


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

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.


2

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


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

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.


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/


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.


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


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"

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.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.