Docker representa una gran paso en lo que a desarrollo se refiere, por lo que respecta a replicabilidad, predictibilidad, y un largo etcétera, que ya te hemos contado en este post. En acceseo es una parte fundamental del desarrollo de todos y cada uno de los proyectos. Es por ello, que hoy os traemos un artículo relacionado con Docker exponiendo un caso de uso real.
En este artículo vamos a profundizar en el uso de Docker con un sencillo ejemplo a través de una aplicación que generará el hash de una contraseña. Para ello, utilizaremos como dependencias instaladas a través de composer, el componente de consola de Symfony (symfony/console) para interactuar con el usuario; y el componente password-hasher que nos permite obtener el hash de una contraseña con diferentes tipos de algoritmos.
¿Cómo crear un contenedor con las dependencias de PHP?
Tabla de contenidos
ToggleEn primer lugar, lo que vamos a hacer es crear un Dockerfile con la configuración de PHP necesaria para tener nuestro entorno de ejecución listo. A continuación podemos ver el archivo:
En el Dockerfile hemos añadido diversas líneas que corresponden a los siguientes conceptos:
- Configurar la hora del sistema.
- Un binario de composer copiado de la imagen oficial a través del mecanismo de multistage build.
- Modificar el working directory del contendor a /app, en nuestro caso, instalaremos las dependencias de composer y añadiremos el archivo de ejecución del comando.
- Modificar los permisos de la carpeta (working dir) y el usuario a www-data.
- Instalar algunas dependencias de sistema necesarias para el correcto funcionamiento de composer.
- Instalar las dependencias de PHP que vamos a usar para nuestra aplicación de consola. Esto nos generará los archivos de composer (composer.json y composer.lock), además de crear la carpeta vendor que albergará las dependencias.
- Y por último, modificar el usuario que va a ejecutar el contendor a www-data. Este paso no es necesario, pero si es una buena práctica ejecutar los contenedores con usuarios que no tengan permisos de root.
Tras esta breve explicación, solo nos queda buildear el contenedor para poder empezar a usarlo con el comando correspondiente. En caso de que sea la primera vez que usas la imagen de PHP, o el tag 8.2-cli, Docker la descargará previamente, y te mostrará en el terminal algo similar a lo siguiente:
Tras terminar de descargar la imagen, seguirá interpretando cada una de las líneas de nuestro archivo. Cuando llegue al paso donde instalamos las dependencias de composer nos advierte de que no tiene permisos para crear la carpeta de caché, en nuestro caso, no nos importa, puesto que vamos a cachear este paso a través de Docker y no vamos a necesitar hacer uso de esa caché.
Tras ejecutar el comando de instalación de dependencias, composer nos va a generar un archivo composer.json y composer.lock. Como no vamos a crear un paquete que publicar a packagist, sino que será una funcionalidad aislada, no nos importa en exceso el contenido que nos ha generado por defecto. Si quieres, puedes modificarlo añadiendo el archivo al contenedor, en vez de delegar este proceso a composer.
¿Cómo darle funcionalidad a nuestro contenedor?
En este punto, solo nos queda añadir nuestro código (app.php) a ejecutar dentro del contenedor. En nuestro ejemplo, usaremos un único archivo por simplicidad, pero puedes añadir tantos archivos y directorios como la tarea que vas a llevar a cabo lo requiera.
Para ello, vamos a realizar una nueva modificación al Dockerfile, copiando el archivo de nuestra aplicación (app.php) dentro del contenedor.
Ten en cuenta que el orden de las líneas del Dockefile es importante, ya que afecta a como se buildea el contenedor en caso de haya cambios. Es decir, si ponemos la línea que copia el archivo al principio y se producen cambios, tendrá que buildear todos los pasos posteriores al cambio.
Por eso hemos añadido la copia del archivo al final, para evitar que Docker tenga que interpretar el archivo completo en caso de que hagamos algún cambio en nuestro archivo de aplicación.
Como habrás observado, hemos incluido además de la copia del archivo app.php, una nueva línea en el Dockerfile, para indicarle a Docker que queremos que el punto de entrada del contenedor sea la ejecución de nuestro comando. De esta forma, podemos ejecutar el contenedor sin tener en cuenta cuál es el comando que queremos ejecutar ni en que archivo está.
Ahora solo nos queda ejecutar nuestro comando:
Te aconsejamos que ejecutes el contenedor con el flag –rm, para forzar a Docker a que elimine el contenedor una vez ha terminado la ejecución. De lo contrario el contenedor no se eliminará tras terminar la ejecución, y tras cada nueva ejecución se crearán nuevos contenedores. Además, hemos incluido el flag -it para poder ver los colores del terminal, ¿A quién no le gustan los colores 😄?.
Conclusión
A lo largo del artículo, hemos visto desde la creación de un contenedor con las dependencias necesarias para la ejecución de nuestra herramienta, pasando por el buildeo de la misma. Con esta sencilla prueba de concepto, se hace visible el gran potencial que puede llegar a tener encapsular en un contenedor tareas a ejecutar desde un terminal, con todo lo que ello conlleva.
Nos permite hacer portable y ejecutable en cualquier entorno y en cualquier sistema que tenga instalado Docker. Esto nos permite homogeneizar el flujo de trabajo de un equipo con las mismas herramientas ejecutadas de la misma forma.
En el ejemplo hemos usado Symfony, que está escrito en PHP, pero no es necesario que nos acoplemos al lenguaje, ni al framework. Podemos emplear lo que sea más adecuado para nuestras necesidades (porqué no probar Rust 😜). Quedan fuera de esta prueba de concepto, aspectos como taggear esos contendores, lo cual nos permitiría una mayor flexibilidad a la hora de controlar que versiones se ejecutan, pudiendo incluso deprecar versiones.
Te dejamos que investigues como buildear y pushear esas imágenes a través de GitHub Actions a Docker Hub, o donde prefieras (nosotros ya lo utilizamos para los contenedores de PHP en nuestro entorno de trabajo 😉).