Cómo usar Docker en proyectos PHP

Hace tiempo que vengo usando (¡y abogando por su uso!) máquinas virtuales para mis proyectos PHP.

Hasta ahora me venía manejando con Vagrant y debo decir que me ha dado unas cuantas satisfacciones.

Sin embargo, hay algunos problemas derivados de su uso:

  1. Las VM se pueden volver muy pesadas
    • Ocupan mucho espacio en el disco
    • Son lentas de levantar
    • No es sencillo tener muchas corriendo a la par (Consumen muchos recursos de hardware)
  2. No es fácil asegurarme de que en Producción y en Desarrollo tengo exactamente el mismo software instalado.

Investigando un poco y, hay que decirlo también, por consejo de algunos colegas me metí con docker.

Qué es Docker

Docker es una herramienta de virtualización basada en un concepto algo diferente al que usa Vagrant: los contenedores.

No me voy a meter acá en los detalles técnicos, simplemente diré que un contenedor hace un uso mucho más eficiente de los recursos del hardware y, a los fines prácticos, cumple la misma función que una VM.

Cómo se usa Docker

Docker se basa en el docker daemon corriendo constantemente y luego en un cliente que le envía comandos.

Lo primero que necesitás es tener algún contenedor levantado… y para eso, lo primero que necesitás es tener algún contenedor creado.

Los contenedores se crean en base a imágenes.

Qué es una imagen de Docker

Una imagen de docker es una definición de un entorno de ejecución completo (algo así como una VM de Vagrant).

Un contenedor es una imagen en ejecución.

Podrías pensarlo como la diferencia entre un programa y un proceso.

Las imágenes docker se definen en un archivo de texto llamado Dockerfile (Bastante similar al Vagrantfile).

Por ejemplo:

FROM php:7.2-cli
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
CMD [ "php", "./your-script.php" ]

Lo que ves es una serie de instrucciones.

La primera (FROM) es tal vez la más importante: la imagen base.

Las imágenes docker manejan un concepto similar al de la herencia de POO: Sobre una imagen base es posible crear otras más especializadas.

Para efectivamente arrancar esta imagen debemos crear un contenedor basado en ella.

Antes de hacer eso es conveniente crear un archivo llamado your-script.php (Es importante hacerlo antes de crear el contenedor porque el comando COPY se ejecutará durante la creación y no volverá a ejecutarse hasta que el contenedor sea destruido y vuelto a crear).

En cierto sentido, esto es como quemar una ROM 🙂

Pues entonces, creemos un archivo your-script.php con este contenido:

<?php

echo "Estoy en docker!!".PHP_EOL;

Y ahora sí ¡estamos listos para darle vida a nuestro primer contenedor docker!

sudo docker build -t my-php-app .

Con este comando hemos creado nuestro contenedor.

Para ejecutar algún comando dentro de él usaremos:

sudo docker run -it --rm --name my-running-app my-php-app

Y obtendremos la salida:

Estoy en docker!!

Cómo correr una aplicación web PHP en docker

Típicamente para ejecutar una aplicación web PHP vas a necesitar al menos un servidor web y el intérprete de PHP instalado.

Podrías definir tu propia imagen instalando todos los paquetes y demás, pero… ¿vale realmente la pena?

No.

Puedes basar tu imagen en una que ya tenga un poco más allanado el camino.

Por ejemplo php:7.3-apache está basada en Ubutu 18.04 y ya trae php 7.3, Apache y algún par de utilidades más.

De modo que usando un Dockerfile como este:

FROM php:7.3-apache
COPY . /var/www/html/

Podremos tener un contenedor que incluya un Apache y nuestro código en el DocumentRoot.

Un detalle importante que falta es «avisar» a docker que queremos que nuestro contenedor pueda ser accedido desde afuera a través del puerto 80 (Muy parecido al mapeo de puertos que se usa en Vagrant).

Para eso vamos a usar el comando EXPOSE. El Dockerfile se verá así:

FROM php:7.3-apache
COPY . /var/www/html/
EXPOSE 80

Para no complicar mucho las cosas renombremos el archivo your-script.php a index.php y usemos este comando para crear nuestro contenedor:

sudo docker build -t my-php-web-app .

Para entrar a ver nuestro flamante sitio tenemos que ejecutar:

sudo docker run -p 80:80 --rm -it --name my-web-app my-php-web-app:latest

Y, por supuesto, abrir un navegador en http://localhost.

Si todo salió bien deberías ver algo como:

Cómo desplegar una imagen Docker en Producción

Muy bien, ya tenemos todo casi listo, sólo nos falta ver cómo desplegar nuestra imagen en un servidor de producción y concluimos.

Claramente, esta es la parte que realmente hace una diferencia respecto de usar Vagrant… difícilmente vas a querer montar una VM en un servidor productivo por cada aplicación que tengas… o vas a tener una factura bien abultada en AWS.

Existen varias opciones para realizar el despliegue. Para mantener este artículo dentro de un alcance acotado me voy a limitar a la que considero requiere menos conocimientos extra:

  1. Grabar la imagen en nuestra máquina local
sudo docker save -o image.zip my-php-web-app
  1. Subir la imagen al servidor de producción
scp image.zip <user>@<server-addres>:<target-location>
  1. Agregar la imagen al repositorio de docker
docker load -i <path-to-image.zip>
  1. Crear el contenedor a partir de la imagen
docker run -d -p 8888:80 my-php-web-app

Y listo! Ahora se puede acceder a la aplicación entrando a la dirección pública del servidor y el puerto 8888 (Y si es tu única webapp podrías directamente mapear el puerto 80 de tu servidor al del contenedor).

mchojrin

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes

¿Te quedó alguna duda? Publica aca tu pregunta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.