No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Curso de Docker

Curso de Docker

Guido Vilari帽o

Guido Vilari帽o

Deteniendo contenedores correctamente: SHELL vs. EXEC

27/32
Recursos

Aportes 51

Preguntas 10

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

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 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

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, 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.

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鈥檚 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 [ 鈥渆cho鈥, 鈥$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 [ 鈥渟h鈥, 鈥-c鈥, 鈥渆cho $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.

Si no se ejcuta correctamente el contenedor y en los logs dice algo como permiso denegado, en el Dockerfile se debe agregar permisos de ejecuci贸n al script loop

FROM ubuntu:trusty
COPY ["loop.sh", "/"]
RUN chmod +x /loop.sh
CMD ["/loop.sh"]
~                                                                                                                     
~                         

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

#Enviar seal sigterm al contenedor
docker stop <container>

#Mostar  煤ltimo proceso
docker ps -l

#Enviar seal sigkill al contenedor
docker kill <container>

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

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

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

Excelente clase, suena a pregunta tricky de una entrevista de docker!

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

Clase magistral de docker, linux y linea de comandos que fue esta clase, solo queria acotar eso 馃榿馃榿.

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

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.

Conclusi贸n: Se recomienda usar EXEC

Detener usando Shell (docker stop <nombre_contenedor>): Cuando se utiliza el comando docker stop, Docker env铆a una se帽al SIGTERM al proceso principal del contenedor. Esto le da al proceso la oportunidad de realizar tareas de limpieza y apagar correctamente antes de finalizar. Sin embargo, algunos procesos o aplicaciones pueden no manejar adecuadamente la se帽al SIGTERM y podr铆an necesitar m谩s tiempo para finalizar. Si el proceso no se detiene en un tiempo razonable (10 segundos por defecto), Docker puede enviar una se帽al SIGKILL, que fuerza la terminaci贸n inmediata del contenedor. Esto podr铆a resultar en p茅rdida de datos o recursos no liberados.

Detener usando Exec (docker exec -it <nombre_contenedor> bash): Al usar docker exec, est谩s ingresando a un nuevo proceso dentro del contenedor (en este caso, un shell Bash). Al salir del shell (con exit), el proceso del shell se detiene, pero el contenedor en s铆 no se detiene. Esto podr铆a ser 煤til si necesitas acceder al interior del contenedor para realizar tareas de mantenimiento o soluci贸n de problemas, sin detener completamente el contenedor y sus servicios.

Esta ha sido una clase bastante sustanciosa, excelente!

exec from vs. shell form

Recordando: Docker asigna al proceso principal de un contenedor el PID_1 y que de este depende la vida del contenedor. Esto por el ciclo de vida de los contenedores. Un SybProceso tendra su propio PID y el PPID que representa el proceso padre que lo llama, siendo este un proceso hijo.

En ocaciones se requiere que termine el proceso para apagar el contenedor y docker tiene medios para pedir ese cierre de forma controlada y la app termine lo que esta haciendo y no forzar el cierre.

Docker para terminar el proceso manda una se帽al:

  • SIGTERM: Es una se帽al estandar de linux que pide terminar un proceso, funciona como el Ctrl+C en la terminal. Esta se帽al se puede enviar mediante el comando docker stop <app>. Pero despues de un tiempo se llamara a al SIGKILL si no se detiene.
  • SIGKILL: Es una se帽al que garantizara que el proceso se terminara de una forma forzada. Se puede llamar con docker kill <app>.

El proceso principal /bin/sh -c /loop.sh no reenvia las se帽ales a los hijos y por ende no termina el proceso del loop.sh. (Investigar si es asi o si es que el proceso termina pero no el principal)

Para captar la se帽al hay que tener la app preparada. Por ejemplo la siguiente app de bash revisara que no haya una se帽al SIGTERM para continuar (con un loop infinito) y si la hay terminara el proceso. Ademas que este en el proceso PID=1.

comandos

docker build -t loop .
docker run -d --name looper loop

# enviar la se帽al SIGTERM
docker stop looper

# revisar los procesos del contenedor
docker exec looper ps -ef

archivo loop.sh

trap 'exit 0' SIGTERM
while true: do:; done

dockerfile de loop

FROM ubuntu:trusty
COPY ["loop.sh", "/"]
CMD /loop.sh #SHELL FORM: llamado por shell `/bin/sh -c /loop.sh`

Este intenta detener el proceso con SIGTERM, pero tarda mucho y pasa a usar el SIGKILL.

Esto ocurre porque el proceso main es /bin/sh -c /loop.sh y el subproceso es el ./loop.sh, terminando el subproceso y no el proceso principal.

Para analizar podemos usar el docker ps -l que mostrara el ultimo contenedor. Este mostrara que salio con el codigo 137 Exited (137). Los codigos de salida sobre 128 es el resultado de una excepcion o una se帽al no manejada correctamente. Entonces 137-128 = 9, entonces la se帽al que recibio para salir es 9 que es SIGKILL, la se帽al de linux que mata todo. Si mandamos en lugar del SIGTERM el SIGKILL, terminaria el proceso casi al instante.

Entonces lo que necesitamos para hacer el 鈥淕raceful Shutdown鈥 que es un apagado sin que afecte a los usuarios, es modificar la forma de ejecucion que tenemos en el Dockerfile. Donde por ejemplo queremos que un contenedor deje de recibir peteciones de usuarios con un SIGTERM y termine las que faltan y se apague para colocar una nueva version del contenedor.

dockerfile de loop (Correcto)

FROM ubuntu:trusty
COPY ["loop.sh", "/"]
CMD ["/loop.sh"] #EXEC FORM: Se ejecuta directamente

En su lugar usamos el EXEC FORM que tendra como proceso principal el archivo /loop.sh deteniendose el proceso con solo el SIGTERM inmediatamente. El comando asociado sera "/loop.sh" si lo vemos con el docker ps. Y la salida tendra un estatus de Exited (0).

Formas de ejecutar:

  • SHELL FORM: El Shell Form ejecuta el comando como un hijo del proceso shell.

    CMD /loop.sh
    
  • EXEC FORM: Mientras que este lo ejecuta directamente, siendo este su propio proceso.

    CMD ["/loop.sh"]
    

Siempre que tengamos un c贸digo de salida mayor a 128 es por una excepci贸n.

Siempre es recomendable usar el formato 鈥楨XEC鈥 antes que el formato 鈥楽HELL鈥, es decir:

CMD ["/loop.sh"]

Esto siempre debe de estar entre corchetes y con comillas.

Muy interezante esta clase

Si deseas borrar todas las imagenes en uso o no:
docker image rm -f $(docker image ls -aq)

Igualmente para todos los volumenes en uso, primero borras los containers y luego puedes hacer :
docker volume rm -f $(docker volume ls -q)

excelente explicaci贸n, docker es una gran herramienta para aprender y utilizar

En mi caso me dio el c贸digo de salida 127 que significa el sistema no puede encontrar la ruta especificada., alguna idea del por que me da el error e estado revisando pero no encuentro el error.

Que buena clase, todos estos detallitos valen oro

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

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.

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?

Excelente la diferencia entre exec y shell.

Chirimbolos

鈥淐hirimbolos鈥 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.