Hola, en la entrada anterior vimos como complicarnos un poco a la hora de construir imágenes. Hoy toca complicarnos un poco más y estudiar algunas de las opciones disponibles para la construcción de imágenes.
Hasta ahora hemos construido imágenes que nos permiten crear contenedores que ejecutarán una aplicación dererminada. La pregunta es ¿como le hemos indicado a docker qué debe ejecutar?¿cómo se ejecuta? y más importante todavía ¿que opciones tenemos?
Evidentemente la primera pregunta es la más sencilla. Si recordamos el dockerfile para nuestra imagen de un servidor ldap, teníamos lo siguiente:
Dockerfile de imagen ldap. |
Como ya sabemos, mediante la instrucción ENTRYPOINT le estamos indicando a docker que programa o comando de nuestra imagen ejecutar al crear un contenedor basado en ella.
Ahora nos queda responder a las otras dos preguntas, las cuales están muy relacionadas entre si así que, como diría Groucho, respondamos primero a la segunda pregunta.
Ya sabemos que al crear una imagen es necesario que indiquemos en el dockerfile que la describe que se ejecutará dentro del contenedor. Para esto hay disponibles dos instrucciones que podemos usar en nuestros dockerfiles, estas instrucciones son CMD y ENTRYPOINT y en ambos casos el resultado al usar una u otra es muy similar, salvo por los siguientes puntos que debemos tener en cuenta:
- El objetivo al usar CMD es el de especificar parámetros por defecto para nuestros contenedores. En este caso, siempre es necesario especificar un ENTRYPOINT junto con la instrucción CMD, la cual no contendrá ningún ejecutable.
- Al usar ENTRYPOINT definiremos siempre un ejecutable que se lanzará al arrancar un contenedor. Esta definición siempre debe contener la ruta al ejecutable que queremos lanzar al crear nuestros contenedores.
Nuevo dockerfile con parámetros por defecto. |
Con esta nueva definición contruimos de nuevo nuestra imagen y ahora, al crear un contenedor, se ejecutará el servidor ldap indicado en ENTRYPOINT con los parámetros por defecto especificados en CMD. Si al crearlo pasamos otros parámetros al comando docker run, estos nuevos parámetros sustituirán a los que hemos especificado en el dockerfile. Veamoslo con un pequeño ejemplo:
Contenedor creado a partir de la imagen ldap. |
Si ahora creo otro contenedor y especifico otros parámetros el resultado será el siguiente:
Cambiando los parámetros en tiempo de creación del contenedor. |
Desde mi punto de vista, creo que lo mejor es usar la combinación de ENTRYPOINT, para el ejecutable y CMD, para los parámetros por defecto, cuando pueda ser necesario cambiar estos últimos al crear un contenedor. Cuando lo que buscamos es asegurarnos de que no se pueden alterar los parámetros por defecto, lo mejor será que nuestro dockerfile solo contenga una entrada ENTRYPOINT que especifique tanto el ejecutable como los parámetros necesarios. En este último caso cualquier parámetro que se añada en el momento de crear el contenedor se añadirá a los parámetros por defecto sin sustituirlos, con lo que nos aseguramos que el servicio arrancará con los parámetros deseados.
Otro punto importante que debemos tener en cuenta al utilizar ENTRYPOINT es el formato que utilizamos. Según la documentación, tenemos dos opciones al especificar la instrucción ENTRYPOINT:
- Formato shell, que es más o menos: ENTRYPOINT comando param1 param2 ...
- Formato exec, que es más o menos: ENTRYPOINY ["ejecutable", "param1", "param2", ... ]
Hasta ahora siempre hemos usado el segundo formato en nuestros dockerfile, el denominado formato exec, en el cual especificamos el ejecutable y sus parámetros como un array JSON. Cuando hemos creado contenedores e inspeccionado los procesos corriendo en los mismos, hemos visto que nuestro ejecutable era siempre el PID número 1. Si usamos el formato shell, ¿que es lo que sucede? Como siempre veamoslo con un ejemplo muy sencillo:
Contenedor creado usando el formato shell de ENTRYPOINT. |
Hasta aquí un poco más de información sobre Docker y como trabajar con imágenes. En la siguiente entrada veremos como personalizar en el momento de crear un contenedor la configuración de nuestro servicio ldap.