Uso de las instrucciones ENTRYPOINT y CMD en el Dockerfile

Si alguna vez has necesitado ejecutar uno o dos comandos en tu contenedor Docker al iniciarse, este tutorial es para ti. Utilizando el archivo Dockerfile y las instrucciones ENTRYPOINT y CMD, puedes ejecutar tantos comandos de inicio como desees.

En este tutorial, aprenderás cómo utilizar las instrucciones ENTRYPOINT y CMD para ejecutar comandos de inicio en un Dockerfile y comprender las diferencias entre ellos.

Prerrequisitos

Dado que este tutorial será una demostración práctica, asegúrate de tener lo siguiente en su lugar:

  • A Windows 10 PC – Windows 10 v10.0.19042 was used in this tutorial.
  • Docker Desktop – Este tutorial utiliza Docker Desktop v3.3.1.

Creación de un Dockerfile

Antes de poder ejecutar comandos de inicio del contenedor Docker, primero debes crear un Dockerfile. Un Dockerfile es un documento de texto que contiene una lista de comandos para construir contenedores, imágenes de Docker y determina cómo se crea una imagen de Docker.

1. Primero, abre PowerShell como administrador.

2. Crea una nueva carpeta para almacenar el Dockerfile y todos los archivos asociados que este tutorial utilizará, y cambia a ese directorio. Este tutorial está utilizando ~/docker.

mkdir ~/docker
cd docker

3. Ahora, crea un archivo de texto en blanco llamado Dockerfile con el siguiente comando.

cd > Dockerfile

Alternativamente, puedes crear un Dockerfile con el siguiente comando si estás en Linux o Mac OS.

touch Dockerfile

4. Finalmente, agrega el siguiente contenido al Dockerfile

FROM ubuntu:20.04

¡Ahora has creado un Dockerfile que pronto será utilizado!

Construyendo una Imagen de Docker

Ahora que has creado tu Dockerfile, debes construir una imagen de Docker para ejecutar los comandos escritos en las instrucciones ENTRYPOINT y CMD de tu Dockerfile. Una forma de construir una imagen es mediante el uso del build comando.

Mientras estés en el directorio ~/docker, ejecuta el siguiente comando. El comando a continuación crea una imagen de Docker llamada demo (-t demo) a partir del Dockerfile en ~/docker especificando el directorio de trabajo actual (.).

docker build -t demo .
Building a Docker Image

Ejecutando un Contenedor de Docker

Después de haber construido la imagen de Docker, necesitarás un contenedor para ejecutar la imagen de Docker que ejecutará los comandos de las instrucciones ENTRYPOINT y CMD del Dockerfile.

Para ejecutar un contenedor Docker, llama al comando run para crear una capa de contenedor sobre la imagen Docker (demo). El siguiente ejemplo utiliza el parámetro -it para conectarse de forma interactiva al contenedor, lo que te permite ver la salida de muestra.

docker run -it demo
Running a Docker Container

Forma de Ejecución vs. Forma de Shell

Cuando comienzas a trabajar con un archivo Docker y descubres cómo ejecutar comandos de inicio, es posible que te encuentres con dos métodos diferentes para definir estos comandos. Cada método invocará comandos, pero lo hace de manera un poco diferente.

Cuando Docker ejecuta comandos, puede hacerlo directamente llamando a exec o a través de la shell del contenedor (/bin/sh -c en Linux o cmd /S /C en Windows), llamado shell.

Notarás que los comandos ejecutados mediante exec tienen una instrucción seguida de los ejecutables a invocar, seguidos por uno o más argumentos de línea de comandos, como se muestra a continuación.

ENTRYPOINT ["executables", "parameter1", "parameter2", ...]
CMD ["executables", "parameter1", "parameter2:, ...]

La escritura de comandos en forma de shell, por otro lado, no requiere envolver los comandos entre corchetes, como se muestra a continuación.

ENTRYPOINT <command> "parameter1"
CMD <command> "parameter1"

Si no especificas un argumento para CMD, Docker siempre ejecutará el comando en forma de exec, por ejemplo, CMD <command>.

Si estás empezando, diferenciar entre estas dos invocaciones de comandos no importará demasiado, pero a medida que te vuelvas más avanzado, pronto verás los beneficios y las desventajas de cada uno.

Ejecución de Comandos de Inicio

Vamos a adentrarnos en el meollo de este tutorial y ensuciarnos las manos recorriendo algunos ejemplos de ejecución de comandos de inicio dentro de un archivo Dockerfile ENTRYPOINT y las instrucciones CMD.

1. Abre el Dockerfile que creaste anteriormente en tu editor de texto preferido.

2. Copia y pega el contenido del ejemplo de Dockerfile en tu Dockerfile, como se muestra a continuación, y guárdalo.

Este Dockerfile crea una capa usando la imagen base ubuntu:20.04. Luego le indica a Docker que invoque el comando echo pasándole el argumento Hello world tanto para las instrucciones CMD como ENTRYPOINT del Dockerfile utilizando la forma exec y shell.

FROM ubuntu:20.04
# Instrucción CMD
CMD ["echo", "Hello world"] # Exec Form
CMD echo "Hello world"      # Shell Form
# Instrucción ENTRYPOINT
ENTRYPOINT ["echo", "Hello world"] # Exec Form
ENTRYPOINT echo "Hello world"      # Shell Form

3. Mientras estés en el directorio ~/docker, construye la nueva imagen ejecutando docker build y llámala demo. El comando a continuación etiqueta la imagen como demo y busca un Dockerfile en el directorio de trabajo actual (.).

docker build -t demo .
Building a Docker image with docker build

4. Ahora, ejecuta un contenedor utilizando la imagen y luego ejecuta un contenedor Docker basado en la imagen Docker creada anteriormente. Ahora verás que el contenedor devuelve Hello world, que proviene de la instrucción CMD proporcionada en el Dockerfile.

docker run -it demo
Running a Docker container with docker run

Uso de variables en un Dockerfile

A veces, es posible que no conozcas de antemano los argumentos exactos de la línea de comandos para pasar al comando. Los argumentos que necesitas pasar a un comando solo se exponen en tiempo de ejecución. En lugar de asignar estáticamente los argumentos del comando, puedes capturar y pasar esos argumentos a los comandos con variables.

Solo puedes usar variables de Dockerfile en forma de shell. Docker no admite variables en comandos invocados mediante exec.

Abre el Dockerfile en tu editor de texto preferido nuevamente, reemplaza todo por la siguiente serie de comandos y guárdalo.

Esta vez notarás que el Dockerfile utiliza variables de entorno y se muestra usando ENV. En el ejemplo a continuación, el Dockerfile está definiendo una variable de entorno llamada name con un valor de friend. Una vez creada, esta variable de entorno se referencia mediante $name.

Cuando Docker ejecuta un contenedor basado en este Dockerfile, invocará el comando echo y pasará el argumento Bienvenido, amigo.

FROM ubuntu:20.04
ENV name friend

CMD echo "Welcome, $name"
# o
## ENTRYPOINT echo "Bienvenido, $name"

Ahora, crea la imagen de Docker y ejecuta el contenedor nuevamente, proporcionando opcionalmente un nombre de etiqueta shellform. Notarás que Docker invocó el comando echo y devolvió la salida esperada.

Building a Docker Image (shellform) and Running a Docker Container

Combinando las instrucciones ENTRYPOINT y CMD del Dockerfile

Gran parte del tiempo, invocarás comandos de inicio ya sea en CMD o en la instrucción ENTRYPOINT. Después de todo, puedes invocar tantos comandos como desees utilizando cada método. Pero también puedes invocar un solo comando y “añadirle” utilizando ambas instrucciones.

Basándonos en los ejemplos anteriores, tal vez tengas un Dockerfile que se vea como el siguiente ejemplo. Tal como está, si creas una imagen y ejecutas un contenedor a partir de esa imagen, Docker invocaría el comando echo y devolvería Hello.

FROM ubuntu:20.04
ENTRYPOINT ["echo", "Hello"]

Tal vez tengas otro argumento que te gustaría pasar al comando echo pero no de inmediato. Tal vez te gustaría hacerlo más adelante en el Dockerfile. Al llamar a la instrucción CMD sin un comando, puedes hacerlo.

Cuando especificas un comando para ejecutar a través de la instrucción ENTRYPOINT seguido de la instrucción CMD, Docker asume automáticamente que el valor pasado a CMD es un argumento; no un comando.

Ahora, agrega una referencia de instrucción CMD sin un comando, solo un argumento llamado world, como se muestra a continuación.

FROM ubuntu:20.04
ENTRYPOINT ["echo", "Hello"]
CMD ["world"]

Combinar instrucciones siempre debe escribirse en forma ejecutiva debido a su comportamiento “similar a un array” de especificar valores individualmente separados por comas en lugar de todos en una sola cadena.

Después de construir la imagen y ejecutar el contenedor desde la imagen, puedes ver que en lugar de dos líneas de salida (Hello y world), Docker solo devuelve una, lo que significa solo una invocación del comando echo.

Building a Docker Image (demo3) and Running a Docker Container

Conclusión

Deberías tener ahora un buen entendimiento de cómo ejecutar comandos de inicio de contenedores Docker a través de las instrucciones del archivo Docker CMD y ENTRYPOINT. Cada instrucción es un poco diferente pero logra la misma tarea e incluso pueden ser usadas juntas.

¿Puedes pensar en un escenario donde preferirías usar CMD en lugar de ENTRYPOINT para ejecutar un comando de inicio?

Source:
https://adamtheautomator.com/dockerfile-entrypoint/