Fabric: Os scripts de inicialização freqüentemente falham ao iniciar seus daemons

Criado em 19 ago. 2011  ·  19Comentários  ·  Fonte: fabric/fabric

Descrição

Recebi vários relatórios sobre isso no IRC, bem como um comentário no # 350, e agora um tópico da lista de discussão .

Ainda não há uma causa clara e, embora tenha sido relatado várias vezes, não creio que seja um problema constante ou ouviríamos muito mais sobre ele. Em alguns testes muito limitados do meu lado até agora, posso recriar o problema talvez 30-50% do tempo - mas é reproduzível.

O sintoma é simplesmente que os scripts de estilo init responsáveis ​​por iniciar daemons e retornar imediatamente retornarão OK, código de retorno 0 e mensagem de status de "sucesso" impressa em stdout - mas não irão realmente girar o daemon em questão.

Meu teste pessoal foi feito por meio do mestre mais recente visando uma VM Ubuntu 10.04 (Lucid) e o script de inicialização do pacote Apache2 de estoque.


Enviado originalmente por Jeff Forcier ( bitprophet ) em 2011-07-23 às 19:25 EDT

Relações

  • Relacionado a # 350: o tecido desliga algum comando remoto (para programa daemon)
Bug Docs Wart

Comentários muito úteis

Acabei de enfrentar esse problema.
Tive uma situação em que não consigo usar tty = False porque executo o comando com sudo.
Adicionar >& /dev/null < /dev/null & bem, mas o processo não foi iniciado.

Resolvi o problema de adicionar um sleep após a linha de execução de comando: nohup java -jar text.jar & sleep 5; exit 0

Todos 19 comentários

Jeff Forcier ( bitprophet ) postou:


Instrumentou o script de inicialização que estou testando e tudo parece funcionar da mesma maneira (ou seja, cenários de sucesso real ou falsos), o que implica que o problema está dentro da chamada apachectl que o próprio script faz.

Começando a pensar sobre qual poderia ser a causa do nosso lado:

  • Como é semi-aleatório, isso me faz pensar nos problemas anteriores com o subsistema IO atormentado pela condição de corrida. No entanto, eu realmente não consigo pensar em como isso poderia afetar algo no extremo remoto dessa maneira, e as condições da corrida eram todas locais de qualquer maneira.

    • Uma maneira de testar isso seria ver se esse problema surge com Fab 0.9.xe pty = True (para corresponder ao padrão atual em 1.x).

  • Também pode ser apenas relacionado ao pty - não me lembro de ser um problema anterior ao 1.0 e definir pty como True foi uma das principais mudanças no comportamento padrão. Porém, novamente, não consigo ver por que usar o subsistema request-a-pty do SSH faria com que os scripts de inicialização se comportassem dessa maneira.

    • Um teste aqui seria usar ssh -t <hostname> <command> e ver se isso também reproduz o problema.


em 23/07/2011 às 19:45 EDT

Jeff Forcier ( bitprophet ) postou:


apache2ctl também é simplesmente um script Bash wrapper chamando /usr/sbin/apache2 , que é um link simbólico para um executável binário real no local de instalação do Apache mpm-worker. Especificamente, no uso normal de start , ele chama /usr/sbin/apache2 -k start . Como antes, apache2ctl não parece se comportar de maneira diferente nos dois cenários diferentes, re: valor de retorno ou quais seções são executadas.

/usr/sbin/apache2 são relativamente limitados (mesmo no site do Apache), afirmando apenas que você deve usar o apachectl para configurar env vars (o que é preciso - executar apache2 por si só funciona bem obviamente, com erros sobre esses vars não serem definidos.

Examinando a saída de env pouco antes de apache2ctl 's invocação de apache2 rendimentos apenas alguns itens: usuário, grupo localização pidfile e linguagem. Isso não muda entre situações de sucesso e fracasso. Eu esperava que houvesse algo nas várias origens e configurações de env var nos invólucros que mudasse às vezes, mas não.


Até agora, isso não está indo a lugar nenhum útil. É hora de testar as ideias acima (pty, ssh) para ver o que muda.


em 23/07/2011 às 20:46 EDT

Jeff Forcier ( bitprophet ) postou:


Com pty=False , parece funcionar muito melhor (como está implícito no comentário de Max em # 350). Com a configuração padrão True, eu estava vendo falhas cerca de 5/10 vezes, às vezes um pouco mais ou menos. Com False, acabei de executá-lo cerca de 15 vezes seguidas sem nenhuma falha. Não é um estatístico, mas parece muito bom para mim.

Executar ssh manualmente produz resultados semelhantes: ssh -t <host> sudo /etc/init.d/apache2 start irá falhar silenciosamente ao iniciar o Apache aproximadamente 50% das vezes. O mesmo com -T (não forçar pty) e começa 100% do tempo.

Portanto, isso não é culpa do Fabric; é algo mais profundo onde esses scripts de inicialização se comportam mal quando um pseudo-tty de estilo SSH está em jogo.


Indo um pouco mais fundo por curiosidade, mas parece que a "solução" aqui é um novo FAQ declarando o uso de pty=False quando este problema for encontrado.


em 2011-07-23 às 08:59 pm EDT

Jeff Forcier ( bitprophet ) postou:


Sim, não encontrando nada que explique esse comportamento, infelizmente. Dadas as descobertas acima, acho que um FAQ é definitivamente o caminho a seguir.


em 2011-07-23 às 10:35 pm EDT

Hugo Garza (hiro2k) postou:


Ughh, encontrei isso ontem, gostaria de ter visto esse bug, felizmente tentei definir pty = False e funcionou bem. Obrigado pela explicação, pelo menos não é culpa dos tecidos. Agora você realmente está me perguntando por que isso falha.


em 02/08/2011 às 13h27 EDT

Tem certeza de que este não é apenas um problema de script bash também? Quero dizer, com o tópico da minha lista de discussão. Eles eram apenas scripts bash que iniciaram java e weblogic.

FWIW, estou tendo esse comportamento horrível em praticamente todas as máquinas Ubuntu que inicio no EC2.

Também é reproduzível com tarefas iniciadas por meio de uma tela destacada screen -d -m someBackgroundTask .

Devo mencionar que geralmente pty=False resolve o problema, mas já vi casos em que esse não era o caso.

@yuvadm - nos casos em que pty = False não resolve o problema, o problema ainda pode ser recriado usando um comando ssh regular (como mencionado acima)? Pelo que vi é um problema de SSH e não de Fabric, mas seria bom saber se há alguma situação em que não corresponda.

Esse é um ângulo interessante para verificar, eu voltarei a você nesse ponto ...

Eu reproduzi este problema. O cliente é Ubuntu 10.04.3 LTS, o servidor é "Ubuntu 8.04.4 LTS (servidor)".
O cliente SSH é "OpenSSH_5.3p1 Debian-3ubuntu7, OpenSSL 0.9.8k 25 Mar 2009", o servidor ssh é "OpenSSH_4.7p1 Debian-8ubuntu1, OpenSSL 0.9.8g 19 Out 2007". O tecido é "1.3.3 final".

O problema está 100% com pty = True e desaparece com pty = False.

Conectando-se a outros servidores, o problema nem sempre está presente quando pty = True.

No meu caso, para teste, estou executando um comando muito simples: "nohup sleep 100> / tmp / xxx 2> & 1

Eu fui mordido por isso, apenas no EC2 como parece (eu não vi no meu Linode, mas não tenho 100% de certeza). Definir pty = False parece corrigir isso.

Acabei de enfrentar esse problema.
Tive uma situação em que não consigo usar tty = False porque executo o comando com sudo.
Adicionar >& /dev/null < /dev/null & bem, mas o processo não foi iniciado.

Resolvi o problema de adicionar um sleep após a linha de execução de comando: nohup java -jar text.jar & sleep 5; exit 0

Obrigado spodgruskiy,

Suas dicas funcionam para mim.
Eu tentei escrever fab tp start a strom cluster com os seguintes comandos.

  1. run ('nohup ./bin/storm nimbus> & / dev / null </ dev / null &', pty = False)
  2. run ('nohup ./bin/storm nimbus> & / dev / null </ dev / null &')
  3. run ("screen -d -m './bin/storm nimbus'", pty = False)
  4. run ("|| screen -d -m './bin/storm nimbus'")

Mas nenhum deles funciona, o nimbus nem mesmo começou. Eu não entendo o que aconteceu.
Enfim, obrigado.

1 para o truque do sono

precisava trabalhar em sistemas com requisitos

sudo ('iniciar o serviço; dormir 0,5') e está tudo bem!

Onde você está usando 'sudo ()' e o sistema remoto tem RequireTty habilitado para acesso sudo, você pode usar 'set -m; serviçostart 'para evitar que o SIGHUP seja enviado para o processo iniciado pelo script de inicialização.

Consulte http://stackoverflow.com/a/14866774 para uma explicação mais detalhada sobre bash interativo versus não interativo e como isso afeta o controle de tarefas.

Estou curioso, qual é o problema do SSH aqui?

pty = false funciona para mim

Não é realmente um problema de SSH, é mais o comportamento sutil em torno dos modos não interativos / interativos do BASH e da propagação de sinal para grupos de processos.

O que se segue é baseado em http://stackoverflow.com/questions/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 e http: //www.itp.uzh.ch/~dpotter/howto/daemonize , com algumas suposições não totalmente validadas, mas os testes sobre como isso funciona parecem confirmar.

pty / tty = false

O shell bash lançado conecta-se ao stdout / stderr / stdin do processo iniciado e é mantido em execução até que não haja nada conectado aos soquetes e seus filhos tenham saído. Um bom processo deamon garantirá que ele não espere que seus filhos saiam, bifurcam um processo filho e depois saem. Quando neste modo, nenhum SIGHUP será enviado ao processo filho por SSH. Eu acredito que isso funcionará corretamente para a maioria dos scripts que executam um processo que lida com a própria desamonização e não precisa ser colocado em segundo plano. Onde os scripts de inicialização usam '&' para um processo em segundo plano, é provável que o principal problema seja se o processo em segundo plano alguma vez tenta ler stdin, uma vez que isso irá disparar um SIGHUP se a sessão tiver sido encerrada.

pty / tty = true *

Se o script de inicialização tiver como pano de fundo o processo iniciado, o shell BASH pai retornará um código de saída para a conexão SSH, que por sua vez parecerá sair imediatamente, pois não está esperando que um processo filho termine e não está bloqueado no stdout / stderr / stdin. Isso fará com que um SIGHUP seja enviado ao grupo de processos do shell bash pai, que, uma vez que o controle do job está desabilitado no modo não interativo no bash, incluirá os processos filhos recém-iniciados. Onde um processo daemon inicia explicitamente uma nova sessão de processo ao bifurcar ou no processo bifurcado, então ele ou seus filhos não receberão o SIGHUP da saída do processo pai BASH. Observe que isso é diferente de trabalhos suspensos que verão um SIGTERM.

Eu suspeito que os problemas em torno disso só funcionar às vezes tem a ver com uma leve condição de corrida. Se você olhar para a abordagem padrão para desamonizar - http://www.itp.uzh.ch/~dpotter/howto/daemonize , você verá que no código a nova sessão é criada pelo processo bifurcado que pode não ser executado antes que o pai saia, resultando assim no comportamento aleatório de sucesso / falha mencionado acima. Uma instrução sleep permitirá que o processo bifurcado crie uma nova sessão, e é por isso que funciona em alguns casos.

pty / tty = true e o controle de tarefas está explicitamente habilitado no bash

O SSH não se conecta ao stdout / stderr / stdin do shell bash ou a qualquer processo filho iniciado, o que significa que ele sairá assim que o shell bash pai começar a executar os comandos solicitados. Neste caso, com o controle de tarefa habilitado explicitamente, quaisquer processos iniciados pelo shell bash com '&' em segundo plano serão colocados em uma sessão separada imediatamente e não receberão o sinal SIGHUP quando o processo pai para a sessão BASH sair ( Conexão SSH neste caso).

O que é necessário para consertar

Acho que as soluções precisam apenas ser mencionadas explicitamente na documentação de operações run / sudo como um caso especial ao trabalhar com processos / serviços em segundo plano. Basicamente, use 'pty = false' ou, onde isso não for possível, habilite explicitamente o controle de tarefas como o primeiro comando e o comportamento será correto.

Como mencionei aqui fabrickit (um invólucro de libs de tecido) https://github.com/HyukjinKwon/fabrickit/commit/cceb8bfb8f960a3ac41b24c64b8358bd6e7a0366

Você pode iniciar um programa com absoluta facilidade como um daemon, sem configurações ou ajustes específicos.
De qualquer forma, isso é um tipo de execução do Shell e, portanto, deve haver uma maneira de fazer o que o Shell pode fazer.

Experimente isto:

run("sh -c '((nohup %s > /dev/null 2> /dev/null) & )'" % cmd, pty=False)

Tentei fazer isso e funciona perfeitamente bem, mesmo que não implemente programação adicional para ser executado como um daemon (até mesmo um programa escrevendo 'Hello' em um loop while funciona bem).

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

supriyopaul picture supriyopaul  ·  4Comentários

bitprophet picture bitprophet  ·  6Comentários

bitprophet picture bitprophet  ·  4Comentários

26huitailang picture 26huitailang  ·  3Comentários

yuvadm picture yuvadm  ·  5Comentários