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

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 luis@luisiblogdeinformatica.com

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 docker run -p. Si es -p (minúscula) tienes que indicar puerto entrada:puerto salida. Si es -P (mayúscula) el de salida es fijo y el de entrada aleatorio.

También, si solo usas EXPOSE y al hacer run no especificas ni -p ni -P lo que va a pasar es que esos puertos solo sean accesibles desde otros contenedores, no desde el exterior.

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 docker run -v.

Ejemplo:

VOLUME /unadireccion

WORKDIR Especifica el directorio desde el que se van a ejecutar las ordenes de:

  • RUN
  • CMD
  • ENTRYPOINT
  • COPY
  • ADD

Sustituye al comando cd. Y si no existe el directorio, lo crea.

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

Crear Dockerfile 0

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.

Crear Dockerfile 2

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 .

Crear Dockerfile 4

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