Recomendaciones para usar Docker

Docker cambió nuestra forma de desarrollar software. Permite simplificar los entornos de desarrollo y los despliegues, pero es fácil caer en trampas al escribir tus primeros Dockerfiles. Estas prácticas nos ayudaron a mitigar problemas comunes cuando empezamos a usar Docker.
No crees múltiples imágenes para el mismo software.
Una gran ventaja de usar Docker para construir, ejecutar y desplegar aplicaciones es tener un entorno de ejecución consistente. Así puedes asegurarte de que el software de producción sea el mismo que el del servidor de staging, por ejemplo, y simplificar el despliegue y las pruebas.
Un error común al empezar a crear contenedores Docker es empaquetar archivos de configuración o parámetros de ejecución junto con el software. Probablemente necesitarás una imagen distinta para cada entorno, lo que anula parte de los beneficios de contenerizar la aplicación.
Argumentos de línea de comandos
Si necesitas pasar distintos argumentos a tu programa según el entorno, puedes usar la directiva ENTRYPOINT para ejecutarlo y proporcionar los argumentos necesarios, por ejemplo:
# Dockerfile
FROM ubuntu:18.04
ENTRYPOINT ["ls"]
CMD ["-shl", "/"]
Ahora puedes construirlo y ejecutarlo así:
$ docker build --tag myls .
$ docker run myls
$ docker run myls -la /bin
Como ves, podemos usar el contenedor como si fuera la utilidad ls. También podemos proporcionar parámetros predeterminados mediante la directiva CMD.
Archivos de configuración y variables de entorno
Las variables de entorno suelen ser la solución habitual para la configuración. Puedes establecerlas una a una con la CLI de Docker o usar un archivo de variables de entorno, por ejemplo:
# Dockerfile
FROM ubuntu:18.04
CMD ["sh", "-c", "echo ${SOME_TEXT} ${SOME_OTHER_TEXT}"]
Construye y ejecuta:
$ docker build --tag myecho .
$ docker run -e SOME_TEXT=Hello -e SOME_OTHER_TEXT=World myecho
Hello World
También puedes usar un archivo de variables de entorno en lugar de pasarlas una a una:
# file.env
SOME_TEXT=Hello,
SOME_OTHER_TEXT=Bob
$ docker run --env-file file.env myecho
Hello, Bob
A veces el software necesita un archivo de configuración dentro del contenedor. Puedes hacerlo sin empaquetarlo junto con el programa, por ejemplo:
# Dockerfile
FROM ubuntu:18.04
CMD ["sh", "-c", "cat /config.txt"]
# config-pro.txt
Production config file :D
$ docker build --tag myconfig .
$ docker run -v /full/path/to/config-pro.txt:/config.txt myconfig
Production config file :D
Quizá quieras usar un directorio de configuración en lugar de un archivo, por ejemplo:
# Dockerfile
FROM ubuntu:18.04
CMD ["sh", "-c", "cat /config/*.txt"]
Ahora crea una carpeta llamada my-config y escribe dos archivos en ella.
# a.txt
This is file A
# b.txt
This is file B
$ docker build --tag mydir .
$ docker run -v /full/path/to/my-config:/config mydir
This is file A
This is file B
Entorno local
El entorno local suele ser una excepción a esta regla. Al desarrollar software necesitas pasar rápidamente de escribir código a ejecutar el programa. Esto suele requerir versiones de desarrollo de las dependencias, construir en modo Debug y posiblemente ejecutar los programas en distintos modos.
Puedes lograrlo con compilaciones de varias etapas. Un solo Dockerfile permite construir, ejecutar y probar la versión de desarrollo y también crear la imagen final de producción.
Escribe tus registros en stdout y/o stderr.
La aplicación debe escribir sus registros en stdout siempre que sea posible. Esto facilita inspeccionar la salida y recopilar registros en la base de datos que elijas. Docker recoge automáticamente lo que se escribe en stdout o stderr en un archivo JSON específico del contenedor, que puedes inspeccionar con el comando docker logs <container-id>.
Evita los registros de varias líneas: son difíciles de agrupar y complican la búsqueda de valores clave.
Modifica cómo tu lenguaje o framework muestra excepciones, errores y trazas de pila, algo para lo que la mayoría ofrece un mecanismo, para que toda la información necesaria aparezca en una sola línea. Considera mostrarlos como cadenas JSON.
Usa compilaciones de varias etapas.
Las compilaciones de varias etapas permiten usar un solo Dockerfile para construir el software y crear la imagen final de Docker. Esto ayuda a reducir el tamaño de los contenedores y simplifica la compilación. La documentación de Docker explica muy bien esta función: compilaciones de varias etapas.
Con estos consejos sencillos, podrás crear contenedores fáciles de gestionar y usar en distintos entornos, desde una arquitectura desplegada a medida hasta clústeres Kubernetes con gran capacidad de escalar.