Pregunta SIGTERM no llega a la secuencia de comandos del nodo cuando Docker lo ejecuta con `/ bin / sh -c`


Cuando mi Dockerfile termina con

CMD node .

Docker ejecuta ese contenedor con el comando /bin/sh -c "node ." en lugar de simplemente node . (Lo sé, podría hacer eso con CMD ["node", "."])

Pensé que este comportamiento es realmente bueno, ya que significa que dentro del contenedor PID1 es /bin/sh y no mi humilde script de nodo.

Si entiendo correctamente PID1 es responsable de cosechar procesos de zombis huérfanos, y realmente no quiero ser responsable de eso ... Así que si /bin/sh Podría hacer eso, eso sería bueno. (De hecho, pensé que esta es la razón por la cual Docker reescribe mi CMD)

El problema es que cuando envío un SIGTERM al contenedor (comenzado con /bin/sh -c "node ."), ya sea a través de docker-composer stop o docker-composer kill -s SIGTERM, la señal no llega a mi node proceso y por lo tanto se mata con fuerza cada vez que con una SIGKILL después del período de gracia de 10 segundos. No está bien.

¿Hay alguna manera de que alguien administre mis zombies y que mi instancia de nodo reciba las señales enviadas por el acoplador?


5
2017-12-23 18:52


origen


Respuestas:


Hay herramientas diseñadas para resolver este problema:

Creo que si solo tiene un solo proceso, todo lo que necesita hacer es manejar la señal explícitamente con un controlador de señal, lo que bash no hace por usted.

Utilizando el ["node", "."] sintaxis, podrías usar https://nodejs.org/api/process.html#process_signal_events y solo haz que salga de SIGTERM. Creo que eso sería suficiente.

O usando un script bash que puedes usar trap "exit 0" TERM

También podría utilizar un supervisor de procesos como http://skarnet.org/software/s6/


3
2017-12-23 23:40



Creo que debes entender los roles de ENTRYPOINT y CMDy usa el ENTRYPOINT(forma de ejecutivo) forma en su Dockerfile.

ENTRYPOINT, que especifica el ejecutable de inicio del contenedor, es la parte central de un contenedor Docker. Cada contenedor DEBE tener un punto de entrada para decidir por dónde empezar. Por defecto, el valor es /bin/bash -c. Además, todo configurado por CMD se adjuntaría a ENTRYPOINT como argumentos.

Por lo tanto, si no pudo especificar ENTRYPOINT en tus Dockerfile, el punto de entrada real sería /bin/bash -c {your_command_in_CMD}que desafortunadamente NO pasar señales

ENTRYPOINT tiene dos formas: formulario ejecutivo y forma de concha

  • formulario ejecutivo: ENTRYPOINT ["ejecutable", "param1", "param2"]
  • formulario de shell: comando param1 param2

Como el Docker de referencia señalado: se recomienda la forma ejecutiva, y la forma de shell tiene la desventaja de que mando es ejecutado por /bin/bash -c, que podría no funcionar bien con señales:

los forma de concha previene cualquier CMD o run los argumentos de la línea de comando no se utilizan, pero tiene la desventaja de que su ENTRYPOINT se iniciará como un subcomando de /bin/sh -c, que no pasa señales. Esto significa que el ejecutable no será el contenedor PID 1 - y no lo hará recibir señales Unix - por lo que su ejecutable no recibirá una SIGTERM de docker stop <container>.


6
2017-12-24 01:57



Mi solución para el problema PID1:

El Dockerfile termina con:

ENTRYPOINT ["/bin/bash", "-c"]

O deje ENTRYPOINT completamente fuera de su archivo Docker. El valor predeterminado es /bin/sh -c.

Que corro con este script de shell, que tiene el nombre de archivo de node y tiene chmod +x:

#!/bin/bash

docker run --rm -it -p 8083:80 -v $HOME/node/work/:/root/node/:rw node_node "echo pid1 > /dev/null && node $@"

El truco es "echo pid1 > /dev/null && node $@" cual es el comando $@ es un script de shell para aceptar la entrada del usuario desde la línea de comandos.

echo atrapará PID1 y enviará la salida a /dev/null.

Por ejemplo ./node -v devolverá la versión de Node.js dentro del contenedor en ejecución.

Ejecución de un servidor web con ./node /root/node/hello-world.js comando, CTRL + C funcionará de nuevo.

aquí es mi entorno de desarrollo Dockerised Node.js.

EDITAR:

Idea totalmente loca, pero añade esto. node Nombrado script bash al $ PATH. Entonces, en el host, puede escribir node -v en lugar de ./node -v. Y ejecuta el nodo en un contenedor Docker que se ve como si estuviera instalado en el host. :)


0
2017-12-27 17:54