Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Curso de Docker

Curso de Docker

Guido Vilariño

Guido Vilariño

Deteniendo contenedores correctamente: SHELL vs. EXEC

27/32
Recursos

Aportes 37

Preguntas 6

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Comandos:
$ docker build -t loop . (construyo la imagen)
$ docker run -d --name looper loop (corro el contenedor)
$ docker stop looper (le envía la señal SIGTERM al contenedor)
$ docker ps -l (muestra el ps del último proceso)
$ docker kill looper (le envía la señal SIGKILL al contenedor)
$ docker exec looper ps -ef (veo los procesos del contenedor)

Shell: Ejecuta el proceso como hijo del shell

FROM ubuntu:trusty
COPY ["loop.sh", "/"]
CMD /loop.sh

Exec: Ejecuta el comando como principal

FROM ubuntu:trusty
COPY ["loop.sh", "/"]
CMD ["/loop.sh"]

27. Deteniendo contenedores correctamente: SHELL vs. EXEC
Contexto de la lección SHELL vs. EXEC
Al estar activo o recién crear un contendor, este debería estar ejecutando un proceso principal o main process para mantenerse en funcionamiento. En caso de que el main process se detenga el contendor debería dejar de funcionar.

Docker tiene una manera de manejar los procesos de los contenedores de manera estándar, cuando se manda detener el contenedor con la instrucción
docker stop <name-container>; con esta instrucción Docker manda una señal estándar de linux llamada SIGTERM al proceso; después de un tiempo el proceso deberá detenerse; en caso de no detenerse el proceso enviará otra señal llamada SIGKILL; con esta señal se garantiza que el proceso se ha terminado de manera forzada.

Existen problemas en la terminación de procesos ejecutados en los contenedores, una de las causas está asociado a ¿Cómo se debería declarar en Dockerfile el proceso a ejecutar?

digamos que tenemos estos dos archivos configurados de la siguiente manera

El primero es el dockerfile; sirve para construir nuestra imagen y el segundo es el archivo bash que se ejecutará como un main process o proceso principal del contenedor. Es importante destacar que la línea de CMD ejecuta nuestro archivo bash, a través de un shell, esta forma de expresar esta línea se conoce como shell form y esto genera que al momento de detener un contenedor que esté ejecutando un proceso por shell form necesariamente tendrá que usar un SIGKILL. Para evitar esto, el CMD debe ejecutar nuestro main process de form exec form , es decir nuestro archivo debe estar configurado de esta manera.


La idea de que el archivo esté configurado de esta manera es que de tiempo a que el contenedor procese las solicitudes restantes y pueda hacer un Great full shutdown. Otra nota importante es que los códigos de salida mayor a 128 es el resultado de una salida por un código de excepción.

comando utilizados en clases

  • $ cd ~/docker/avanzado

  • $ docker build -t loop .
    build -t <nombre imagen> <contexto de construccion>
    Construir la imagen se le coloca un tag de loop

  • $ docker run -d --name looper loop
    run -d --name <nombre contenedor> <nombre imagen>
    Crear un contenedor con un nombre basado en una imagen

  • $ docker stop looper
    stop <nombre contenedor>
    Envía la señal SIGTERM al contenedor

  • $ docker ps -l
    Muestra el último proceso ejecutado

  • $ docker kill looper
    Kill <nombre contenedor>
    Envía la señal SIGKILL al contenedor

  • $ docker exec looper ps -ef
    exec <nombre contenedor> ps -ef
    Muestra los procesos del contenedor

En nuestro Dockerfile tenemos

CMD [“/loop.sh”] EXEC FORM
CMD /loop.sh SHELL FORM

La diferencia es que SHELL FORM lo ejecuta como un comando hijo del shell, EXEC FORM lo ejecuta directamente.

en windows, si estan usando Visual studio Code, y al momento de ejecutar:

docker run -d --name looper loop

si no se queda ejecutando el script, puede ser por los codigos de control, que por defecto en visual studio estan en CRLF y debe ser LF para que funcione en windows

The shell form prevents any CMD or RUN command line arguments from being used, but has the disadvantage that your ENTRYPOINT will be started as a subcommand of /bin/sh -c, which does not pass signals. This means that the executable will not be the container’s PID 1 - and will not receive Unix signals - so your executable will not receive a SIGTERM from docker stop <container>.

Comandos de la clase

Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, RUN [ “echo”, “$HOME” ] will not do variable substitution on $HOME. If you want shell processing then either use the shell form or execute a shell directly, for example: RUN [ “sh”, “-c”, “echo $HOME” ]. When using the exec form and executing a shell directly, as in the case for the shell form, it is the shell that is doing the environment variable expansion, not docker.

Un loop en el min 10:27, este ... este .... este

que hace el flag -ef en el comando $ docker exec looper ps -ef ?

SIGKILL

  • SIGKILL es la mejor forma de matar un proceso. Siempre matará un proceso y lo matará abruptamente, generando un error fatal. SIGKILL siempre debería funcionar. Si no funciona, el sistema operativo ha fallado.
    `

SIGTERM:

  • SIGTERM intenta matar un proceso, pero a diferencia de SIGKILL, puede bloquearse o manejarse de otra manera. Puede considerarse una forma más suave de intentar finalizar un proceso.
    Para la mayoría de los propósitos, SIGKILL será el método más rápido y efectivo para terminar el proceso.

How to kill a process in Linux

Windows user

Estructura de los comandos

cd avanzado/loop
nano loop.sh
######loop.sh######
#!/usr/bin/env bash
trap 'exit 0' SIGTERM
while true; do :; done
###################

– Shell: Ejecuta el proceso como hijo del shell

nano Dockerfile
######Dockerfile######
FROM ubuntu:trusty
COPY ["loop.sh", "/"]
CMD /loop.sh
###################
./loop.sh
docker build -t loop .

docker run -d --name looper loop

docker stop looper

docker kill looper

docker exec looper ps -ef

– Exec: Ejecuta el comando como principal

nano Dockerfile
######Dockerfile######
FROM ubuntu:trusty
COPY ["loop.sh", "/"]
CMD ["/loop.sh"]
###################
docker build -t loop .
docker run -d --name looper loop
docker exec looper ps -ef

SHELL vs. EXEC

docker ps -l muestra el último contenedor creado incluyendo todos los estados.

Supongo que para lograr descubrir esto tuvo que pasar por varias horas de maldecir Docker y buscar porqué sucede jajaja.

En pocas palabras el docker stop pregunta y luego dispara si es el caso y el kill llega disparando

En Windows, cambiar en el archivo loop.sh, en el editor de código, en la parte inferior derecha la forma de hacer los saltos de línea: CRLF a LF.

A seguir aprendiendo… Violento EXEC

Ejecucion EXEC y SHELL

Al usar cmd "/loop.sh" se ejecuta el comando en "shell form". De esta forma, Docker utiliza el shell que se encuentre configurado en el dockerfile y ejecuta el comando como un subproceso del shell. Es así que el shell queda como proceso principal y el comando como subproceso. Al usar cmd ["/loop.sh"] se ejecuta el comando en "exec form". De esta forma, Docker lo ejecuta como proceso principal.

#Enviar señal sigterm al contenedor
docker stop <container>

#Mostar  último proceso
docker ps -l

#Enviar señal sigkill al contenedor
docker kill <container>

#Ver procesos del contenedor
docker exec <container> ps -ef 

forzado de contenedores

a lo chirimbolo XD jajajaja!

Así que… entre SHELL vs EXEC, gana EXEC? que buena pelea

😎

Excelente explicacion… Muy buena clase

  • CMD command param1 param2, ejecuta el comando en la shell.
  • CMD ["command", "param1", "param2"], la forma recomendada, ejecuta el comando en la bash del contenedor.

Estoy trabajando en linux y el contenedor no se queda encendido, se apaga inmediatamente. Cómo hago para que quede encendido?

No basta con solo usar el EXEC FORM en su dockerfile tambien su applicacion debe estar lista para hacer un graceful shutdown

Busquen en sus frameworks favoritos la mejor forma de hacer un graceful shutdown

Excelente la diferencia entre exec y shell.

Chirimbolos

“Chirimbolos” jajaja

segun la explicacion de Guido y el aporte del amigo Isaac Guido

asi deberia ser el codigo en formato exec.

no me queda claro.

Esto me recuerda cuando doy refrescar y no carga hasta los 10 minutos jaja. No pasa muy seguido.