La creación de una imagen la podemos hacer de varias maneras (por ejemplo con docker commit
) pero la más recomendada es con docker build
a partir de un Dockerfile. Puedes recordar el comando build
y sus parámetros en Docker Cheatsheet (comandos más usados).
Resumen del artículo
Dockerfile no es un comando. Como su propio nombre indica es un archivo. Este archivo no tiene terminación y podemos crearlo con cualquier editor de texto. Dentro de este archivo lo que vamos a encontrar son las instrucciones para crear una imagen.
Yo recomiendo usar nano
como editor de texto en Linux, pero sí estas en Mac o Windows puedes usar el Notepad simplemente.
nano dockerfile
Como hemos visto en la teoría de docker, una imagen es una sucesión de comandos que crean capas sobre el Kernel.
En el Dockerfile podemos indicar varias instrucciones.
Sin mucha importancia | ||
MAINTAINER | Podemos añadir nuestro nombre y correo. Los datos de quien ha creado el Dockerfile y la imagen. | Ejemplo:
MAINTAINER redxlus [email protected] |
Obligatorio | ||
FROM | Es obligatorio. Al principio de cada Dockerfile. Indica cual es la imagen base. | Ejemplo:
FROM debian:latest |
De ejecución | ||
RUN | Ejecuta comandos en una nueva capa y crea un nuevo contenedor intermedio. Normalmente es usado para instalar nuevos paquetes. | Ejemplo:
RUN apt-get update |
CMD | El comando que se especifique a continuación, se ejecutara cuando haga docker run si no se especificar otro comando. |
Ejemplo:
CMD apt-get update |
ENTRYPOINT | Igual que CMD pero no es ignorado si indicamos otro comando. | Ejemplo:
ENTRYPOINT apt-get update |
Datos | ||
COPY | Copia archivos o directorios desde la máquina local (donde esta instalado docker) al contenedor Docker. | Ejemplo:
COPY texto.txt /directorio/ejemplo |
ADD | Similar a COPY. Añade más funcionalidades. Permite 2 fuentes además de la posibilidad de que sean URLs. Se pueden usar escapes. Y si la usas con un archivo comprimido(gzip, bzip2, xz) te lo descomprime. | Ejemplo:
ADD https://a.luisiblogdeinformatica.com/nc1 / |
Otros | ||
EXPOSE | Indica (no expone) el puerto del contenedor.
Útil para que los puertos no se expongan aleatoriamente. Es complementario a También, si solo usas EXPOSE y al hacer Se puede especificar también si es TCP o UDP. Por defecto es TCP. |
Ejemplo:
EXPOSE 8080 |
VOLUME | Indica el destino de un volumen dentro del contenedor.
Puede ser uno o varios. Igual que si especificáramos |
Ejemplo:
VOLUME /unadireccion |
WORKDIR | Especifica el directorio desde el que se van a ejecutar las ordenes de:
Sustituye al comando |
Ejemplo:
WORKDIR /midirectorio |
ENV | Variables del sistema o entorno personales.
Podemos llamarlas después dentro del contenedor. |
Ejemplo:
ENV nombre luis Luego dentro del contenedor: echo $nombre |
USER | Indica el nombre o UID que va a ejecutar las acciones del Dockerfile. | Ejemplo:
USER luisdieguez |
Formatos
Hay dos tipos de formatos que podemos aplicar a:
- RUN
- CMD
- ENTRYPOINT
- COPY
- ADD
El primer formato es Shell. Este formato sigue la sintaxis:
RUN comando parámetro1 parámetro2 ...
Por ejemplo para instalar Vim (un editor de texto):
RUN apt update && apt install -y vim
El formato Shell es sencillo de usar, pero como su nombre indica, invoca una shell (/bin/bash -c) para ejecutar el comando. Es muy importante ya que este formato ejecuta las variables del sistema.
El otro formato es JSON. Este formato nos permite pasar los datos como arrays. Esto significa que no utiliza la consola y nos permite hacer varios cambios, unido junto a CMD, con menos esfuerzo. Es el formato recomendado por Docker. También llamado exec form.
La sintaxis es:
RUN ["comando", "parámetro1","parámetro2"]
Ejemplo formato JSON
Como decía anteriormente, un ejemplo clásico es con el uso de los array.
Como puedes ver, llamamos al ejecutable del comando echo (sirve para mostrar texto, en realidad tiene muchos más usos pero lo vamos a utilizar para ese solo). No va a llamar a la consola (intérprete de comandos). Entonces con el ENTRYPOINT se ejecuta al hacer un docker run
y el CMD después.
ENTRYPOINT ["/bin/echo", "Hello"] CMD ["world"]
¿Qué pasa si ponemos una variable?. Pues que aunque la variable ENV exista, no la va a interpretar.
¿Puedo usar una consola dentro del formato JSON?. Pues sí. Tan solo tienes que llamar al interprete de ella (bash, sh...) y ejecutar los comandos como parámetros. Entonces al ser un interpreté sí te reconoce las variables.
ENTRYPOINT ["/bin/bash", "-c" "echo Hello"] CMD ["world"]
Para resumir, si tienes que elegir entre los distintos tipos de formatos:
- Shell: Sencillo y tiene los beneficios de una consola clásica (pipelines y redireccionamientos).
- JSON: Es más seguro. Permite unir ENTRYPOINT con CMD.
Si necesitas usar pipelines o redireccionamientos puedes usar un script en Bash y añadirlo al Dockerfile con ADD/COPY. O si lo necesitas que se ejecute justo al inicio puedes usar ENTRYPOINT.
Otro ejemplo de JSON, esta vez sí usando la mezcla entre ENTRYPOINT y CDM:
ENTRYPOINT ["/bin/ping", "-c3", "luisiblogdeinformatica.com" ] CMD ["-srcaddr"]
Esto lo que ejecutará sería el ping -c3 luisiblogdeinformatica.com -srcaddr
al inicio del contenedor. Pero si al hacer el Docker run especificamos otro parámetro, por ejemplo docker run nombrecontenedor -t
. Todo lo que hayamos puesto en el CMD será sustituido, con lo que nos iniciaría con el comando ping -c3 luisiblogdeinformatica.com -t
. Esto lo podemos complicar todo lo que queramos, teneis más infomación en
Recuerda que puedes sustituir lo que hayas puesto en el ENTRYPOINT al usar docker run --entrypoint
. También lo que hayas puesto en el CMD (como acabamos de ver) simplemente añadiendo después del docker run
.
Ejemplo Dockerfile:
Primero abrimos el editor, como decía, el editor de texto que queramos. En Linux:
nano dockerfile
Y podemos utilizar este ejemplo. Simplemente va a utilizar la imagen base de Debian (la última versión), actualizar los paquetes del sistema e instalar VIM. Luego si no especificamos comando va a hacer un ping y saludar y por último copiar un archivo dentro del contenedor.
FROM debian:latest RUN apt-get update && apt-get upgrade -y && apt-get install -y git CMD ping google.es > /test.txt ENV minombre Luis ENTRYPOINT echo "Hola $minombre" COPY archivo.txt /home/$USER/archiv.txt
Después lo guardamos. Ahora vamos a construir la imagen. En el docker build
vamos a indicar el nombre luistest y la etiqueta version001. Luego con el último punto vamos a indicar que el dockerfile está en el mismo directorio en el que estamos.
docker build -t luistest:version001 .
Y ya tendríamos nuestra imagen personalizada con el Dockerfile lista para crear un nuevo contenedor en Docker. Recuerda, no es recomendado borrar el dockerfile después de usarlo. Puedes crear un nuevo directorio y tenerlos ordenados por si los necesitamos de nuevo o simplemente para revisar.
Luego podemos actualizar esa imagen simplemente modificando la etiqueta. El último paso ya es hacer un docker run
para crear un contenedor.
Variables Dockerfile
Muy corto. Podemos especificar nuestras propias variables en el Dockerfile con ENV. Pero también podemos llamar a las variables de entorno de todo sistema Linux.
Ejemplo variable entorno ENV:
ENV NombrePerro Laika CMD echo $NombrePerro
Ejemplo variable entorno Shell:
CMD echo $HOME
Ejemplo variable entorno JSON:
CMD [ "/bin/sh", "-c", "echo $HOME" ]
cool! pero… que son los rufuarrays? :-O
Hola!
Los array son conjuntos de datos, estos se almacenan en matrices (como las que estudiábamos en matemáticas en el colegio).
Voy a añadir algún ejemplo más y una explicación más clara.
Y se me coló el rufu- 😂
Gracias por preguntar!