O que set -e e exec “$ @” fazem para scripts de docker entrypoint?

95

Percebi que muitos scripts entrypoint.sh para docker fazem algo assim:

#!/bin/bash
set -e

... code ...

exec "$@"

Para que servem set -ee exec "$@"para?

Nathan
fonte
2
Consulte BashFAQ # 105 sobre: ​​porque set -eé considerado muito mais sujeito a erros do que o tratamento de erros escrito à mão. (Se estiver com pressa, pule a analogia no topo para os exercícios abaixo).
Charles Duffy

Respostas:

71

Basicamente, ele pega quaisquer argumentos de linha de comando passados entrypoint.she os executa como um comando. A intenção é basicamente "Faça tudo neste script .sh, então no mesmo shell execute o comando que o usuário passa na linha de comando".

Vejo:

Mateus
fonte
1
Observe também que exec "$@"isso substituirá o processo em execução pelo novo processo gerado para os argumentos passados. Importante para a sinalização do Docker: stackoverflow.com/a/32261019/99717
Hawkeye Parker
35

set -edefine uma opção do shell para sair imediatamente se qualquer comando executado sair com um código de saída diferente de zero. O script retornará com o código de saída do comando com falha. Na página de manual do bash:

conjunto -e:

Saia imediatamente se um pipeline (que pode consistir em um único comando simples), uma lista ou um comando composto (consulte SHELL GRAMMAR acima), sair com um status diferente de zero. O shell não fecha se o comando que falha fizer parte da lista de comandos imediatamente após a palavra-chave while ou until, parte do teste após as palavras reservadas if ou elif, parte de qualquer comando executado em um && ou || list, exceto o comando após o && ou || final, qualquer comando em um pipeline exceto o último, ou se o valor de retorno do comando estiver sendo invertido com!. Se um comando composto diferente de um subshell retornar um status diferente de zero porque um comando falhou enquanto -e estava sendo ignorado, o shell não sai. Um trap em ERR, se definido, é executado antes que o shell saia.

Se um comando composto ou função shell é executado em um contexto onde -e está sendo ignorado, nenhum dos comandos executados dentro do comando composto ou corpo da função será afetado pela configuração -e, mesmo se -e for definido e um comando retornar um status de falha. Se um comando composto ou função shell definir -e durante a execução em um contexto onde -e for ignorado, essa configuração não terá nenhum efeito até que o comando composto ou o comando que contém a chamada de função seja concluído.


exec "$@"é normalmente usado para fazer do ponto de entrada uma passagem que executa o comando docker. Ele irá substituir o shell em execução atual pelo comando que "$@"está apontando para. Por padrão, essa variável aponta para os argumentos da linha de comando.

Se você tiver uma imagem com um entrypoint apontando para entrypoint.sh e executar seu contêiner como docker run my_image server start, isso se traduzirá em execução entrypoint.sh server startno contêiner. Na linha exec entrypoint.sh, o shell em execução como pid 1 se substituirá pelo comando server start.

Isso é crítico para o tratamento do sinal. Sem usar exec, o server startno exemplo acima seria executado como outro pid e, depois de sair, você retornaria ao seu script de shell. Com um shell em pid 1, um SIGTERM será ignorado por padrão. Isso significa que o sinal de parada normal que docker stopenvia para o seu contêiner nunca seria recebido pelo serverprocesso. Após 10 segundos (por padrão), docker stopdesistiria do desligamento normal e enviaria um SIGKILL que forçará seu aplicativo a sair, mas com possível perda de dados ou conexões de rede fechadas, que os desenvolvedores de aplicativos poderiam ter codificado se tivessem recebido o sinal. Isso também significa que seu contêiner sempre levará 10 segundos para parar.

Observe que com comandos de shell como shifte set --, você pode alterar o valor de "$@". Por exemplo, aqui está uma pequena parte de um script que remove o /bin/sh -c "..."do comando que pode aparecer se você usar a sintaxe do shell do docker para CMD:

# convert `/bin/sh -c "server start"` to `server start`
if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then
  shift 2
  eval "set -- $1"
fi

....

exec "$@"
BMitch
fonte
1
Veja a testespecificação POSIX , que marca -aobsoleta. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]é a substituição correta (não há necessidade de x"$1"hackery ao usar apenas a sintaxe não obsoleta).
Charles Duffy
Além disso, shift 2; set -- $1não é o mesmo que evalanalisar a string. Considere /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"', se você deseja um caso de teste concreto, e veja que o Bash não analisa aspas ao converter uma string em argumentos .
Charles Duffy
@CharlesDuffy obrigado pela dica sobre a opção obsoleta, tenho certeza que cometerei esse erro novamente, velhos hábitos são difíceis de morrer. Com o eval, acredito que ainda quero espelhar o comportamento de /bin/sh -cteria na string, mas, por favor, me diga se estou faltando alguma coisa.
BMitch
30

set -e - saia do script se algum comando falhar (valor diferente de zero)

exec "$@"- redirecionará variáveis ​​de entrada, veja mais aqui

agilob
fonte
"Irá redirecionar as variáveis ​​de entrada"? Eh? execcertamente tem um modo de uso em que está realizando redirecionamentos, mas este não é esse modo.
Charles Duffy