martes, 7 de junio de 2016

INSTRUCCIONES EN EL FICHERO DOCKERFILE

Ya hemos visto algunas de las instrucciones disponibles para utilizar en el fichero Dockerfile, como RUN y EXPOSE. Pero también hay una gran variedad de instrucciones que podemos utilizar en nuestro Dockerfile. Estos incluyen CMD, ENTRYPOINT, ADD, COPY, VOLUME, WORKDIR, USER, ONBUILD, LABEL, STOPSIGNAL, ARG y ENV. 

Vamos a ver la lista completa.

CMD

La instrucción CMD especifica el comando a ejecutar cuando se inicia un contenedor. Es similar a la instrucción RUN, pero en lugar de ejecutarse el comando cuando se está construyendo el contenedor, se especificará el comando a ejecutar cuando se inicia el contenedor, al igual que la especificación de un comando para ejecutar al iniciar un contenedor con el comando “docker run”.

Por último, es importante entender que podemos anular la instrucción CMD usando el comando “docker run”. Si especificamos un CMD en nuestro Dockerfile y uno en la línea de comando del comando “docker run”, la línea de comandos anulará la instrucción CMD del Dockerfile.

ENTRYPOINT

En estrecha relación con la instrucción CMD, y que puede crear confusión con el mismo, está la instrucción ENTRYPOINT. Entonces vamos a ver cuál es la diferencia entre los dos y porque necesitamos a ambos para poder anular la instrucción CMD en la línea de comando de “docker run”. A veces, esto no es suficiente cuando queremos que un contenedor se comporte de una determinada manera. La instrucción ENTRYPOINT, ofrece un comando que no se anulará con la misma facilidad. Sin embargo, cualquier argumento que especifique en la línea de comandos del comando “docker run” serán pasados como argumentos para el comando especificado en el ENTRYPOINT o punto de entrada. Vamos a ver un ejemplo de una instrucción ENTRYPOINT.

ENTRYPOINT [“/usr/sbin/nginx”]

Como con la instrucción CMD, también podemos especificar parámetros añadiéndolos a la matriz. Por ejemplo:

ENTRYPOINT[“/usr/sbin/nginx”,”-g”,”daemon off;”]

En caso de requerirlo en tiempo de ejecución, nosotros podríamos llegar a sobrescribir la instrucción ENTRYPOINT usando junto con el comando “docker run” el parámetro “--entrypoint”.

WORKDIR

La instrucción WORKDIR ofrece una manera de establecer el directorio de trabajo para el contenedor y para la instrucción ENTRYPOINT y / o CMD para que sea ejecutado cuando un contenedor se inicia desde la imagen.
Podemos utilizarlo para establecer el directorio de trabajo para una serie de instrucciones o para el contenedor final. Por ejemplo, para establecer el directorio de trabajo para una instrucción específica podría ser:

WORKDIR /opt/webapp/db
RUN bundle install
WORKDIR /opt/webapp
ENTRYPOINT [“rackup”]

Aquí hemos cambiado al directorio de trabajo /opt/webapp/db y hemos ejecutado bundle install y luego cambiamos el directorio de trabajo a /opt/webapp antes de especificar nuestra instrucción ENTRYPOINT de rackup.

Podemos reemplazar el directorio de trabajo en tiempo de ejecución con el parámetro -w, por ejemplo:

$ docker run –ti –w /var/log ubuntu pwd /var/log

Esto configurará el directorio de trabajo por defecto del contenedor a /var/log

ENV

La instrucción ENV es usada para configurar variables de entorno durante el proceso de construcción de la imagen. Por ejemplo:

ENV RAPP_PATH /home/rapp

Estas nuevas variables de entorno, podrán ser usadas por cualquier instrucción RUN posterior.
Podemos especificar varias variables de entorno con una sóla instrucción ENV, como por ejemplo:

ENV RAPP_PATH=/home/rapp RAPP_FLAGS=”-arch i386”

También podemos utilizar estas variables de entorno en otras instrucciones:

ENV DESTINO_DIR /opt/app
WORKDIR $DESTINO_DIR

Hemos especificado una nueva variable de entorno, DESTINO_DIR, y hemos usado su valor para definir el directorio de trabajo con la instrucción WORKDIR, el cual quedará establecido como /opt/app.

Estas variables de entorno serán persistentes en los contenedores creados desde la imagen. Pero si nosotros ejecutamos el comando ENV dentro del contenedor construido alteraremos su valor.
También podemos pasar variables de entorno con el comando “docker run” utilizando el parámetro –e. Estas variables sólo se utilizaran en tiempo de ejecución.

USER

La instrucción USER especifica un usuario en el que la imagen se ejecutará, por ejemplo:

      USER nginx

Esto hará que los contenedores creados a partir de la imagen se ejecuten por el usuario nginx. Podemos especificar un nombre de usuario o un UID y grupo o GID. O incluso una combinación de los mismos, por ejemplo:

USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group

También podemos sobrescribir ésto en tiempo de ejecución especificando el parámetro –u con el comando “docker run”

VOLUME

La instrucción VOLUME añade volúmenes a cualquier contenedor creado a partir de una imagen. Un volumen es un directorio especialmente designado dentro de uno o más contenedores que no utiliza el sistema de archivos del contenedor, aunque se integra en el mismo para proporcionar varias funciones útiles para que los datos sean persistentes y se puedan compartir con facilidad:
• Los volúmenes pueden ser compartidos y reutilizados entre los contenedores.
• Un contenedor no tiene que estar en ejecución para compartir sus volúmenes.
• Los cambios en un volumen se hacen directamente.
• Los cambios en un volumen no se incluirán al actualizar una imagen.
• Los volúmenes persisten incluso cuando dejan de usarlo los contenedores.
Esto nos permite añadir datos (como el código fuente), una base de datos, o cualquier otro contenido en una imagen sin comprometer la imagen y nos permite compartir los datos entre los contenedores. Esto se puede utilizar para hacer pruebas con los contenedores y el código de una aplicación, administrar registros, o manejar bases de datos dentro de un contenedor.
La instrucción VOLUME se puede utilizar de la siguiente forma:

VOLUME [“/opt/app”]

Esta instrucción crea un punto de montaje en “/opt/app” a cualquier contenedor creado desde esta imagen.
También podemos especificar múltiples volúmenes especificando un array:

VOLUME [“/opt/app”,”/datos”]

ADD

La instrucción ADD agrega archivos y directorios de nuestro entorno de compilación en nuestra imagen; por ejemplo, al instalar una aplicación. La instrucción ADD especifica un origen y un destino para los archivos, así por ejemplo:

ADD licencia.lic /opt/application/licencia.lic

Esta instrucción ADD copiará el archivo licencia.lic desde el directorio de construcción de la imagen a “/opt/application/licencia.lic” dentro de la propia imagen. El origen del archivo puede ser una URL, nombre de archivo o directorio, siempre y cuando esté accesible dentro del entorno de construcción. No se pueden añadir archivos desde fuera del directorio de construcción.
Cuando añadimos archivos con la instrucción ADD, Docker utiliza el carácter final de la ruta del destino para determinar cuál es la fuente. Si el destino termina en /, entonces se considera que la fuente es un directorio. Si no termina en un /, considera que la fuente es un archivo.
La fuente del archivo también puede ser un URL; por ejemplo:

ADD http://wordpress.org/latest.zip /root/wordpress.zip

Por último, la instrucción ADD tiene algo de especial para el manejo de archivos tar locales. Si un archivo tar (tipos de archivo válidos son gzip, bzip2, xz) se especifica como el archivo de origen, entonces Docker automáticamente lo descomprimirá:

ADD latest.tar.gz /var/www/wordpress/

Esto descomprimiría el archivo latest.tar.gz en el directorio /var/www/wordpress/. El archivo es extraído con el mismo comportamiento que ejecutar tar con la opción -x: la salida es la unión de todo lo que existe en el destino, más el contenido del archivo. Si un archivo o directorio con el mismo nombre ya existe en el destino, no se sobrescribirá.
Actualmente esto no funciona con un archivo tar especificado en una dirección URL.
Por último, si el destino no existe, Docker creará la ruta completa para nosotros, incluyendo cualquier directorio. Los nuevos archivos y directorios se crearán con un modo de permisos 0755 y un UID y GID de 0.
También es importante tener en cuenta que la memoria caché de compilación puede ser invalidada por las instrucciones ADD. Si los archivos o directorios agregados por una instrucción ADD cambiaran, entonces esto va a invalidar la caché para todas las siguientes instrucciones del Dockerfile.

COPY

La instrucción COPY está estrechamente relacionado con la instrucción ADD. La diferencia clave es que la instrucción COPY está pensado para la copia de archivos locales del entorno de construcción y no tiene ninguna capacidad de extracción o de descompresión de archivos.

Ejemplo:
COPY conf.d/  /etc/apache2/

Esto copiará los archivos desde el directorio conf.d al directorio /etc/apache2/.
El origen de los archivos debe ser la ruta a un archivo o directorio en relación con el entorno de construcción, el directorio de origen local en el que está localizado el fichero Dockerfile. No se puede copiar nada que esté fuera de este directorio, porque el entorno de construcción se carga en el demonio de Docker y la copia se lleva a cabo allí. El destino debe ser una ruta absoluta dentro del contenedor.

Los archivos y directorios creados por la copia tendrá un UID y GID de 0.
Si el origen es un directorio, todo el directorio se copia, incluidos los metadatos del sistema de archivos; si la fuente es cualquier otro tipo de archivo, se copia de forma individual junto con sus metadatos. En nuestro ejemplo, el destino termina con una barra inclinada /, por lo que se considera un directorio y copia en el directorio de destino.

Si el destino no existe, se crea junto con todos los directorios que faltan en su camino, al igual que funciona el comando mkdir -p.

LABEL

La instrucción LABEL añade metadatos a una imagen Docker. Los metadatos se presenta en forma de parejas clave/valor. Por ejemplo:

LABEL version= "1.0"
LABEL localizacion= “Murcia” tipo="CPD " rol = "Servidor Web"

La instrucción LABEL se escribe en el formato etiqueta = "valor". Se puede especificar un elemento de metadatos por instrucción LABEL o varios elementos separados por espacios en blanco. Se recomienda combinar todos sus metadatos en una sola instrucción LABEL para evitar la creación de múltiples capas con cada etiqueta de metadatos. Podemos inspeccionar las etiquetas en una imagen usando el comando “docker inspect”.

$ docker inspect jalapuente/apache

Y podemos ver los metadatos que acabamos de definir mediante el uso de la instrucción LABEL.

STOPSIGNAL

La instrucción de instrucciones STOPSIGNAL establece la señal de llamada al sistema que será enviado al contenedor cuando se le indica que se detenga. Esta señal puede ser un número válido permitido por el kernel, por ejemplo 9, o un nombre de señal en el SIGNAME formato, por ejemplo SIGKILL.

ARG

La instrucción ARG define variables que se pueden pasar en tiempo de compilación a través del comando “docker build”. Esto se hace utilizando el parámetro --build-arg. Sólo puede especificar argumentos en tiempo de compilación que han sido definidos en el fichero DOCKERFILE, aquí tenemos un ejemplo de uso:

ARG build ARG webapp_user = usuario

La segunda instrucción ARG establece valor por defecto, si no se especifica ningún valor para el argumento en tiempo de construcción, se utiliza el valor predeterminado. Aquí tenemos un ejemplo  de uso de estos argumentos en en la ejecución del comando “docker build”.

$ docker build -- build-arg constru=1234 -t jalapuente/webapp .

Cuando se construye la imagen jalapuente/webapp la variable constru se establecerá en 1234 y la variable webapp_user heredará el valor predeterminado de usuario.
Docker tiene un conjunto de variables ARG predefinidos que se pueden utilizar en tiempo de compilación, sin que exista una instrucción ARG correspondiente en el Dockerfile.

HTTP_PROXY http_proxy
HTTPS_PROXY https_proxy
FTP_PROXY ftp_proxy
NO_PROXY no_proxy

Para utilizar estas variables predefinidas, pasarlas con el parámetro “--build-arg <variable> = <valor>” al comando docker build.

ONBUILD

La instrucción ONBUILD añade disparadores (también conocidos como triggers) a las imágenes. Un disparador se ejecuta cuando se utiliza la imagen como base de otra imagen (por ejemplo, si tenemos una imagen que necesita agregar código fuente desde una ubicación específica que podría no estar disponible aún, o si necesitamos ejecutar un script que es específico para el entorno en el que se construye la imagen).

El disparador inserta una nueva instrucción en el proceso de construcción, como si se especifica inmediatamente después de la instrucción FROM. El desencadenante puede ser cualquier instrucción de construcción.

Por ejemplo:

ONBUILD ADD ./app/src
ONBUILD RUN cd  /app/src && make

Esto añadiría un disparador ONBUILD a la imagen que se está creando, lo que podemos ver ejecutando el comando docker inspect sobre la imagen.

$ docker inspect imagen
 … “OnBuild”: [“ADD ./app/src”, “RUN cd /app/src / && make”] …

Por ejemplo, vamos a construir un nuevo Dockerfile de una imagen Apache2 que llamaremos jalapuente/apache2.

FROM Ubuntu:14.04
MAINTAINER Javier Hernandez “jalapuente@example.com”
RUN apt-get update && apt-get install –y apache2
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ONBUILD ADD . /var/www/
EXPOSE 80
ENTRYPOINT [“/usr/sbin/apache2”]
CMD [“D”, “FOREGROUND”]

Ahora vamos a construir esta imagen.

$ docker build –t=”jalapuente/apache2”.

Ahora tenemos una imagen con una instrucción ONBUILD que utiliza la instrucción ADD para agregar el contenido del directorio que estamos construyendo desde el directorio /var/www/ a nuestra imagen. Esto podría ser fácilmente nuestra plantilla de aplicación web genérica para la construcción de aplicaciones web.


Vamos a utilizar esto mediante la construcción de una nueva imagen llamada webapp con el siguiente fichero Dockerfile:

FROM jalapuente/apache2
MAINTAINER Javier Hernandez jalapuente@example.com
ENV APPLICATION_NAME webapp
ENV ENVIRONMENT development

Si nosotros ahora ejecutáramos el comando para construir esta imagen:

$ docker build -t=”jalapuente/webapp” .

entre los pasos veríamos:

# Executing 1 build triggers Step onbuild-0: ADD . /var/www/

Se puede ver que inmediatamente después de la instrucción FROM, Docker ha insertado la instrucción ADD, especificado por el disparador ONBUILD y, a continuación, se procedió a ejecutar los pasos restantes. Esto permitiría añadir siempre la fuente local y especificar alguna configuración o construir información para cada aplicación; por lo tanto, esto se convierte en una de imagen plantilla bastante útil.

Los disparadores ONBUILD se ejecutan en el orden especificado en la imagen padre y sólo se heredan de una vez (es decir, por los niños y no los nietos). Si construimos otra imagen de esta nueva imagen, un nieto de la imagen jalapuente/apache2, los disparadores no serían ejecutados cuando se construye esa nueva imagen.


Existen varias instrucciones que no se pueden utilizar en ONBUILD, entre ellas FROM, MAINTAINER, y ONBUILD a si mismo. Esto se hace para evitar la recursividad en la compilación del fichero Dockerfile.

No hay comentarios:

Publicar un comentario