¿Qué hacen set -e y exec “$ @” para los scripts de punto de entrada de Docker?

90

He notado que muchos scripts entrypoint.sh para Docker hacen algo como esto:

#!/bin/bash
set -e

... code ...

exec "$@"

¿Para qué son set -ey exec "$@"para qué?

Nathan
fuente
2
Consulte BashFAQ # 105 re: why set -ese considera mucho más propenso a errores que el manejo de errores escritos a mano. (Si tiene prisa, omita la analogía en la parte superior de los ejercicios a continuación).
Charles Duffy

Respuestas:

70

Básicamente, toma los argumentos de la línea de comandos que se le pasan entrypoint.shy los ejecuta como un comando. La intención es básicamente "Hacer todo en este script .sh, luego en el mismo shell ejecutar el comando que el usuario pasa en la línea de comandos".

Ver:

Mateo
fuente
1
Tenga en cuenta también que exec "$@"reemplazará el proceso actualmente en ejecución con el nuevo proceso generado para los argumentos pasados. Importante para la señalización de Docker: stackoverflow.com/a/32261019/99717
Hawkeye Parker
34

set -eestablece una opción de shell para salir inmediatamente si algún comando que se está ejecutando sale con un código de salida distinto de cero. El script volverá con el código de salida del comando que falla. Desde la página de manual de bash:

set -e:

Salga inmediatamente si una canalización (que puede consistir en un solo comando simple), una lista o un comando compuesto (ver SHELL GRAMMAR arriba), sale con un estado distinto de cero. El shell no sale si el comando que falla es parte de la lista de comandos inmediatamente después de una palabra clave while o until, parte de la prueba que sigue a las palabras reservadas if o elif, parte de cualquier comando ejecutado en && o || lista excepto el comando que sigue al final && o ||, cualquier comando en una canalización excepto el último, o si el valor de retorno del comando se invierte con!. Si un comando compuesto que no sea un subshell devuelve un estado distinto de cero porque un comando falló mientras se ignoraba -e, el shell no se cierra. Una trampa en ERR, si se establece, se ejecuta antes de que salga el shell.

Si un comando compuesto o una función de shell se ejecuta en un contexto donde se ignora -e, ninguno de los comandos ejecutados dentro del comando compuesto o el cuerpo de la función se verá afectado por la configuración de -e, incluso si -e está establecido y un comando devuelve un estado de falla. Si un comando compuesto o una función de shell establece -e mientras se ejecuta en un contexto donde se ignora -e, esa configuración no tendrá ningún efecto hasta que se complete el comando compuesto o el comando que contiene la llamada a la función.


exec "$@"se usa generalmente para hacer que el punto de entrada sea un paso que luego ejecuta el comando docker. Reemplazará el shell en ejecución actual con el comando al que "$@"apunta. De forma predeterminada, esa variable apunta a los argumentos de la línea de comandos.

Si tiene una imagen con un punto de entrada que apunta a entrypoint.sh y ejecuta su contenedor como docker run my_image server start, eso se traducirá en ejecutarse entrypoint.sh server starten el contenedor. En la línea ejecutiva entrypoint.sh, el shell que se ejecuta como pid 1 se reemplazará por el comando server start.

Esto es fundamental para el manejo de señales. Sin usarlo exec, el server startdel ejemplo anterior se ejecutaría como otro pid y, después de salir, volvería a su script de shell. Con un shell en pid 1, un SIGTERM se ignorará por defecto. Eso significa que docker stopel serverproceso nunca recibiría la elegante señal de parada que envía a su contenedor . Después de 10 segundos (por defecto), docker stoprenunciaría al cierre ordenado y enviaría un SIGKILL que obligará a su aplicación a salir, pero con una posible pérdida de datos o conexiones de red cerradas, que los desarrolladores de la aplicación podrían haber codificado si recibieron la señal. También significa que su contenedor siempre tardará 10 segundos en detenerse.

Tenga en cuenta que con comandos de shell como shifty set --, puede cambiar el valor de "$@". Por ejemplo, aquí hay una pequeña parte de un script que elimina el /bin/sh -c "..."del comando que puede aparecer si usa la sintaxis de shell de 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
fuente
1
Consulte la testespecificación POSIX , que marca -aobsolescencia. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]es el reemplazo correcto (no hay necesidad de x"$1"piratería cuando se usa solo la sintaxis no obsoleta).
Charles Duffy
Además, shift 2; set -- $1no es en absoluto lo mismo que cómo evalanalizará la cadena. Considere /bin/sh -c 'printf "%s\n" "hello world" "goodbye world"', si desea un caso de prueba concreto y vea que Bash no analiza las comillas al convertir una cadena en argumentos .
Charles Duffy
@CharlesDuffy, gracias por el consejo sobre la opción obsoleta, estoy seguro de que volveré a cometer este error, los viejos hábitos son difíciles de morir. Con el eval, creo que todavía quiero que refleje el comportamiento /bin/sh -cque tendría en la cadena, pero avíseme si me falta algo.
BMitch
30

set -e - salir del script si falla algún comando (valor distinto de cero)

exec "$@"- redireccionará las variables de entrada, vea más aquí

agilob
fuente
"¿Redirigirá las variables de entrada"? ¿Eh? execciertamente tiene un modo de uso en el que realiza redirecciones, pero este no es ese modo.
Charles Duffy