
Introducción
En los últimos años, Docker se ha convertido en una solución de uso frecuente para implementar aplicaciones gracias a cómo simplifica la ejecución y la implementación de aplicaciones en contenedores. Cuando se utiliza un stack de aplicaciones LEMP, por ejemplo, con PHP, Nginx, MySQL y el framework Laravel, Docker puede simplificar significativamente el proceso de configuración.
Docker Compose ha simplificado aún más el proceso de desarrollo al permitir a los desarrolladores definir su infraestructura, incluidos servicios de aplicaciones, redes y volúmenes, en un solo archivo. Docker Compose ofrece una alternativa eficiente a la ejecución de múltiples comandos docker container create y docker container run.
En este articulo, creará una aplicación web utilizando el framework Laravel, con Nginx como servidor web y MySQL como base de datos, todo esto dentro de contenedores Docker. Definirá la configuración completa del stack en un archivo docker-compose, junto con los archivos de configuración para PHP, MySQL y Nginx.
Prerequisitos
Los requisitos para la seguir este tutorial son los siguientes:
- Tener docker instalado en Linux
- Tener un usuario con privilegios de root
- Tener Git instalado
- Tener docker-composer instalado
Paso 1: Descargando Laravel e instalando dependencias
Como primer paso, obtendremos la última versión de Laravel e instalaremos las dependencias para el proyecto, incluido Composer, el administrador de paquetes para PHP. Instalaremos estas dependencias con Docker para evitar tener que instalar Composer globalmente.
Primero, verifique que esté en su directorio de inicio y clone la última versión de Laravel en un directorio llamado laravel-app
cd ~
git clone https://github.com/laravel/laravel.git laravel-app
Vaya al directorio laravel-app:
cd ~/laravel-app
A continuación, use la imagen de Composer de Docker para montar los directorios que necesitará para su proyecto Laravel y evitar tener que instalar Composer de forma global:
docker run --rm -v $(pwd):/app composer install
El uso de las opciones -v y --rm con Docker Run crea un contenedor que se montará en su directorio actual antes de eliminarlo. Esto copiará el contenido de su directorio ~ / laravel-app al contenedor y también asegurará que la carpeta vendor que Composer crea dentro del contenedor se copie a su directorio actual.
Como paso final, establezca permisos en el directorio del proyecto para que sea propiedad de su usuario actual (diferente al usuario root)
sudo chown -R $USER:$USER ~/laravel-app
Esto será importante cuando escriba el Dockerfile para la imagen de su aplicación en el Paso 4, ya que le permitirá trabajar con el código de su aplicación y ejecutar procesos en su contenedor como usuario no root.
Paso 2: Creación del archivo Docker Compose
Construir sus aplicaciones con Docker Compose simplifica el proceso de configuración y control de versiones de su infraestructura. Para configurar nuestra aplicación Laravel, escribiremos un archivo docker-compose que defina nuestro servidor web, base de datos y servicios de aplicación.
Abra el archivo, para este tutorial usaremos nano pero usted puede utilizar cual procesador de texto.
nano ~/laravel-app/docker-compose.yml
En el archivo docker-compose, definirá tres servicios: aplicación, servidor web y base de datos. Agregue el siguiente código al archivo, asegurándose de reemplazar la contraseña del root MYSQL_ROOT_PASSWORD, definida como una variable de entorno para el servicio de base de datos, asegúrese de escribir una contraseña segura.
version: '3'
services:
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
image: digitalocean.com/php
container_name: app
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
working_dir: /var/www
networks:
- app-network
#Nginx Service
webserver:
image: nginx:alpine
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
networks:
- app-network
#MySQL Service
db:
image: mysql:5.7.22
container_name: db
restart: unless-stopped
tty: true
ports:
- "3306:3306"
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: mi_contrasena_aqui
SERVICE_TAGS: dev
SERVICE_NAME: mysql
networks:
- app-network
#Docker Networks
networks:
app-network:
driver: bridge
Los servicios definidos aquí incluyen:
- Aplicación: Este de servicio contiene la aplicación Laravel y ejecuta una imagen Docker personalizada, digitalocean.com/php, que definirá en el Paso 4. También establece el directorio de trabajo en el contenedor a /var/www.
- Servidor web: este de servicio extrae la imagen nginx:alpine de Docker y abre los puertos 80 y 443.
- Base de datos: este servicio extrae la imagen mysql:5.7.22 de Docker y define algunas variables de entorno, también incluye una base de datos llamada laravel para su aplicación y la contraseña para la base de datos. Puede asignarle el nombre que quiera a la base de datos y debe reemplazar mi_contrasena_aqui con su propia contraseña. Esta servicio también asigna el puerto 3306 en el host al puerto 3306 en el contenedor.
Cada propiedad container_name define un nombre para el contenedor, que corresponde al nombre del servicio. Si no define esta propiedad, Docker asignará un nombre a cada contenedor combinando el nombre de una persona históricamente famosa y una palabra aleatoria separada por un guión bajo.
Para facilitar la comunicación entre contenedores, los servicios están conectados a un puente de red o bridge llamada app-network. Un puente de red utiliza un puente de software que permite que los contenedores conectados al mismo puente de red se comuniquen entre sí. El controlador de puente instala automáticamente las reglas en la máquina host para que los contenedores en diferentes puentes no puedan comunicarse directamente entre sí. Esto crea un mayor nivel de seguridad para las aplicaciones, asegurando que solo los servicios relacionados puedan comunicarse entre sí. También significa que puede definir múltiples redes y servicios que se conectan a funciones relacionadas: por ejemplo, los servicios de aplicaciones front-end pueden usar una red frontend, y los servicios back-end pueden usar una red back-end.
Paso 3: Datos persistentes
Docker tiene características potentes y convenientes para datos persistentes. En nuestra aplicación, haremos uso de volúmenes y montajes de enlace para conservar la base de datos y los archivos de aplicación y configuración. Los volúmenes ofrecen flexibilidad para copias de seguridad y persistencia más allá del ciclo de vida de un contenedor, mientras que los montajes de enlace facilitan los cambios de código durante el desarrollo, haciendo cambios en sus archivos o directorios de host disponibles de inmediato en sus contenedores. Nuestra configuración hará uso de ambos.
In the docker-compose file, define a volume called dbdata under the database service definition to persist the MySQL database:
…
#MySQL Service
db:
…
volumes:
- dbdata:/var/lib/mysql
networks:
- app-network
…
El volumen con nombre dbdata persiste el contenido de la carpeta /var/lib/mysql presente dentro del contenedor. Esto le permite detener y reiniciar el servicio de base de datos sin perder datos. En la parte inferior del archivo, agregue la definición para el volumen dbdata:
…
#Volumes
volumes:
dbdata:
driver: local
Con esta definición podrá utilizar este volumen en todos los servicios. A continuación, agregue un montaje de enlace al servicio de base de datos para los archivos de configuración de MySQL que creará en el paso 7:
#MySQL Service
db:
…
volumes:
- dbdata:/var/lib/mysql
- ./mysql/my.cnf:/etc/mysql/my.cnf
…
Este montaje de enlace, enlaza ~/laravel-app/mysql/my.cnf a /etc/mysql/my.cnf en el contenedor. A continuación, agregue montajes de enlace al servicio del servidor web. Habrá dos: uno para el código de su aplicación y otro para la definición de configuración de Nginx que creará en el paso 6:
#Nginx Service
webserver:
…
volumes:
- ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/
networks:
- app-network
El primer montaje de enlace vincula el código de la aplicación en el directorio ~/laravel-app al directorio /var/www dentro del contenedor. El archivo de configuración que agregará a ~/laravel-app/nginx/ conf.d/ también se montará en /etc/nginx/conf.d/ en el contenedor, lo que le permitirá agregar o modificar el contenido del directorio de configuración según sea necesario .
Finalmente, agregue los siguientes montajes de enlace al servicio de la aplicación para el código de la aplicación y los archivos de configuración:
#PHP Service
app:
…
volumes:
- ./:/var/www
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- app-network
Su archivo docker-compose ahora debera verse así:
version: '3'
services:
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
image: digitalocean.com/php
container_name: app
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
working_dir: /var/www
volumes:
- ./:/var/www
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- app-network
#Nginx Service
webserver:
image: nginx:alpine
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
volumes:
- ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/
networks:
- app-network
#MySQL Service
db:
image: mysql:5.7.22
container_name: db
restart: unless-stopped
tty: true
ports:
- "3306:3306"
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: mi_contrasena_aqui
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- dbdata:/var/lib/mysql/
- ./mysql/my.cnf:/etc/mysql/my.cnf
networks:
- app-network
#Docker Networks
networks:
app-network:
driver: bridge
#Volumes
volumes:
dbdata:
driver: local
Guarde el archivo y salga de su editor cuando termine de hacer los cambios.
Paso 4: Creación del Dockerfile
Docker le permite especificar el entorno dentro de contenedores individuales con un Dockerfile. Un Dockerfile le permite crear imágenes personalizadas que puede usar para instalar el software requerido por su aplicación y configurar las opciones según sus requisitos.
Nuestro Dockerfile estará ubicado en el directorio ~/laravel-app. Crea el archivo:
nano ~/laravel-app/Dockerfile
Este Dockerfile establecerá la imagen base y especificará los comandos e instrucciones necesarios para construir la imagen de la aplicación Laravel. Agregue el siguiente código al archivo:
FROM php:7.2-fpm
# copiar composer.lock y composer.json
COPY composer.lock composer.json /var/www/
# establecer directorio de trabajo
WORKDIR /var/www
# Instalar dependencias
RUN apt-get update && apt-get install -y \
build-essential \
default-mysql-client \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl
# limpiar cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Instalar extensiones
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd
# Instalar composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# añadir usuario para la aplicacion laravel
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www
# copiar el contenido del directorio de la aplicacion existente
COPY . /var/www
# copiar aplicacion y establecer permisos
COPY --chown=www:www . /var/www
# cambiar usuario actual a www
USER www
# abir puerto 9000 y empezar proceso php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
Primero, el Dockerfile crea una imagen utilizando la imagen de Docker php: 7.2-fpm. Esta es una imagen basada en Debian que tiene instalada la implementación PHP FastCGI PHP-FPM. El archivo también instala los requisitos previos para Laravel: mcrypt, pdo_mysql, mbstring e imagick con composer.
La directiva RUN especifica los comandos para actualizar, instalar y configurar los ajustes dentro del contenedor, incluida la creación de un usuario y un grupo dedicado llamado www. La instrucción WORKDIR especifica el directorio /var/www como el directorio de trabajo para la aplicación.
La creación de un usuario y grupo dedicado con permisos restringidos mitiga la vulnerabilidad inherente al ejecutar contenedores Docker, que se ejecutan de forma predeterminada como root. En lugar de ejecutar este contenedor como root, hemos creado el usuario www, que tiene acceso de lectura y escritura a la carpeta /var/www gracias a la instrucción COPY que estamos usando con el indicador --chown para copiar los permisos de la carpeta de la aplicación .
Finalmente, el comando EXPOSE abre un puerto en el contenedor, 9000, para el servidor php-fpm. CMD especifica el comando que debe ejecutarse una vez que se crea el contenedor. Aquí, CMD especifica "php-fpm", que iniciará el servidor.
Guarde el archivo y salga de su editor cuando termine de hacer los cambios.
Paso 5: Configurando PHP
Ahora que ha definido su infraestructura en el archivo docker-compose, puede configurar el servicio PHP para que actúe como un procesador PHP para las solicitudes entrantes de Nginx.
Para configurar PHP, creará un archivo local.ini dentro de la carpeta php. Este es el archivo que montó en /usr/local/etc/php/conf.d/local.ini dentro del contenedor en el Paso 2. La creación de este archivo le permitirá sobrescribir el archivo php.ini predeterminado que PHP lee cuando inicia.
Crea el directorio php:
mkdir ~/laravel-app/php
A continuación, abra el archivo local.ini:
nano ~/laravel-app/php/local.ini
Para demostrar cómo configurar PHP, agregaremos el siguiente código para limitar el tamaño de los archivos cargados al servidor:
upload_max_filesize=40M
post_max_size=40M
Las directivas upload_max_filesize y post_max_size establecen el tamaño máximo permitido para los archivos cargados, y demuestran cómo puede configurar php.ini desde su archivo local.ini. Puede colocar cualquier configuración específica de PHP que sobrescribir en el archivo local.ini.
Guarde el archivo y salga de su editor.
Paso 6 - Configurando Nginx
Con el servicio PHP configurado, puede modificar el servicio Nginx para usar PHP-FPM como el servidor FastCGI para servir contenido dinámico. El servidor FastCGI se basa en un protocolo binario para interconectar programas interactivos con un servidor web.
Para configurar Nginx, creará un archivo app.conf con la configuración del servicio en la carpeta ~/laravel-app/nginx/conf.d/
Primero, cree el directorio nginx/conf.d/
mkdir -p ~/laravel-app/nginx/conf.d
A continuación, cree el archivo de configuración app.conf
nano ~/laravel-app/nginx/conf.d/app.conf
Agregue el siguiente código al archivo para especificar su configuración de Nginx:
server {
listen 80;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}
El bloque server define la configuración para el servidor web Nginx con las siguientes directivas:
- listen: esta directiva define el puerto en el que el servidor escuchará las solicitudes entrantes.
- error_log y access_log: estas directivas definen los archivos para escribir registros.
- root: esta directiva establece la ruta de la carpeta raíz, formando la ruta completa a cualquier archivo solicitado en el sistema de archivos local.
En el bloque location, la directiva fastcgi_pass especifica que el servicio de la aplicación está escuchando en un socket TCP en el puerto 9000. Esto hace que el servidor PHP-FPM escuche a través de la red en lugar de hacerlo en un socket Unix. Aunque un socket Unix tiene una ligera ventaja en velocidad sobre un socket TCP, no tiene un protocolo de red y, por lo tanto, omite la pila de red. Para los casos en que los hosts se encuentran en una sola máquina, un socket Unix puede tener sentido, pero en los casos en que los servicios se ejecutan en diferentes hosts, un socket TCP ofrece la ventaja de permitirle conectarse a servicios distribuidos. Debido a que nuestro contenedor de aplicaciones se ejecuta en un host diferente de nuestro contenedor de servidor web, un socket TCP tiene más sentido para nuestra configuración.
Guarde el archivo y salga de su editor cuando termine de hacer cambios.
Paso 7 - Configurando MySQL
Con PHP y Nginx configurados, puede habilitar MySQL para que actúe como la base de datos de su aplicación.
Para configurar MySQL, creará el archivo my.cnf en la carpeta mysql. Este es el archivo que enlazo en /etc/mysql/my.cnf dentro del contenedor en el Paso 2. Este montaje de enlace le permite sobrescribir la configuración de my.cnf cuando sea necesario.
Para demostrar cómo funciona esto, agregaremos configuraciones al archivo my.cnf para que habiliten el registro de consultas generales y especifiquemos el archivo de registro.
Primero, cree el directorio mysql:
mkdir ~/laravel-app/mysql
A continuación, cree el archivo my.cnf:
nano ~/laravel-app/mysql/my.cnf
En el archivo, agregue el siguiente código para habilitar el registro de consultas y establecer la ubicación del archivo de registro:
[mysqld]
general_log = 1
general_log_file = /var/lib/mysql/general.log
Este archivo my.cnf habilita los registros, definiendo la configuración general_log como 1 para permitir registros generales. La configuración general_log_file especifica dónde se almacenarán los registros.
Guarde el archivo y salga de su editor.
Paso 8: Ejecutar los contenedores y modificar la configuración del entorno
Ahora que ha definido todos sus servicios en su archivo docker-compose y creado los archivos de configuración para estos servicios, puede iniciar los contenedores. Sin embargo, como paso final, haremos una copia del archivo .env.example que Laravel incluye de manera predeterminada y nombraremos la copia .env, que es el archivo que Laravel espera definir su entorno:
cp .env.example .env
Configuraremos los detalles específicos de nuestra configuración en este archivo una vez que hayamos iniciado los contenedores.
Con todos sus servicios definidos en su archivo docker-compose, solo necesita ejecutar un solo comando para iniciar todos los contenedores, crear los volúmenes, configurar y conectar las redes:
docker-compose up -d
Cuando ejecute Docker-compose por primera vez, descargará todas las imágenes de Docker necesarias, lo que puede llevar un tiempo. Una vez que las imágenes se descargan y almacenan en su máquina local, Compose creará sus contenedores. La opción -d ejecuta sus contenedores en segundo plano.
Una vez que se complete el proceso, use el siguiente comando para listar todos los contenedores en ejecución:
docker ps
Verá la siguiente salida con detalles sobre su aplicación, servidor web y contenedores de base de datos:
Output
CONTAINER ID NAMES IMAGE STATUS PORTS
c31b7b3251e0 db mysql:5.7.22 Up 2 seconds 0.0.0.0:3306->3306/tcp
ed5a69704580 app digitalocean.com/php Up 2 seconds 9000/tcp
5ce4ee31d7c0 webserver nginx:alpine Up 2 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
El CONTAINER ID en esta salida es un identificador único para cada contenedor, mientras que NAMES enumera el nombre del servicio asociado con cada uno. Puede usar ambos identificadores para acceder a los contenedores. IMAGE define el nombre de la imagen para cada contenedor, mientras que STATUS proporciona información sobre el estado del contenedor: si se está ejecutando, reiniciando o deteniendo.
Ahora puede modificar el archivo .env en el contenedor de la aplicación para incluir detalles específicos sobre su configuración.
Abra el archivo usando docker-compose exec, que le permite ejecutar comandos específicos en contenedores. En este caso, está abriendo el archivo para editarlo:
docker-compose exec app nano .env
Encuentre el bloque que especifica DB_CONNECTION y actualicelo para reflejar los detalles de su configuración. Modificará los siguientes campos:
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laraveluser
DB_PASSWORD=contrasena_de_su_base_de_datos
Guarde sus cambios y salga de su editor.
Luego, configure la key de la aplicación con el comando php artisan key:generate. Este comando generará una clave y la copiará a su archivo .env, asegurando que sus sesiones de usuario y datos cifrados permanezcan seguros:
docker-compose exec app php artisan key:generate
Ahora ya tiene la configuración del entorno necesaria para ejecutar su aplicación. Para almacenar en caché estas configuraciones en un archivo, lo que aumentará la velocidad de carga de su aplicación, ejecute:
docker-compose exec app php artisan config:cache
Sus ajustes de configuración se guardaran en /var/www/bootstrap/cache/config.php en el contenedor. Como paso final, visite http://su_direccion_ip en el navegador. Verá la siguiente página de inicio para su aplicación Laravel:

Paso 9 - Crear un usuario para MySQL
La instalación predeterminada de MySQL solo crea la cuenta administrativa root, que tiene privilegios ilimitados en el servidor de la base de datos. En general, es mejor evitar usar la cuenta root cuando interactúa con la base de datos. En su lugar, creemos un usuario de base de datos dedicado para la base de datos Laravel de nuestra aplicación.
Para crear un nuevo usuario, ejecute un shell bash interactivo en el contenedor db con docker-compose exec:
docker-compose exec db bash
Dentro del contenedor, inicie sesión con la cuenta root de MySQL:
root@cs58asd442as:/# mysql -u root -p
Se le solicitará la contraseña que configuró para la cuenta root de MySQL durante la instalación en su archivo docker-compose.
Comience por verificar la base de datos llamada laravel, que definió en su archivo docker-compose existe. Ejecute el comando show databases; para verificar las bases de datos existentes:
mysql> show databases;
Verá la base de datos laravel listada en la salida:
Output
+--------------------+
| Database |
+--------------------+
| information_schema |
| laravel |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
Luego, cree la cuenta de usuario que podrá acceder a esta base de datos. Nuestro nombre de usuario será laraveluser, aunque puede reemplazarlo con otro nombre si lo prefiere. Solo asegúrese de que su nombre de usuario y contraseña coincidan con los detalles que estableció en su archivo .env en el paso anterior:
mysql> GRANT ALL ON laravel.* TO 'laraveluser'@'%' IDENTIFIED BY 'password_aqui';
Actualice los privilegios para notificar al servidor MySQL de los cambios, salga de mysql, y salga del contenedor de base de datos.
mysql> FLUSH PRIVILEGES;
mysql> EXIT;
root@cs58asd442as:/# exit
Ha configurado la cuenta de usuario para la base de datos de su aplicación Laravel y está listo para ejecutar las migraciones iniciales de Laravel.
Cree las migraciones iniciales ejecutando el comando php artisan migrate, que crea una tabla de migraciones en la base de datos
docker-compose exec app php artisan migrate
Este comando migrará las tablas predeterminadas de Laravel. El resultado que confirma la migración se verá así:
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
Ahora tiene una aplicación del stack LEMP ejecutándose en su servidor, que ha probado accediendo a la página de bienvenida de Laravel y creando migraciones de bases de datos MySQL. La clave de la simplicidad de esta instalación es Docker Compose, que le permite crear un grupo de contenedores Docker, definidos en un solo archivo, con un solo comando.
Contenido del articulo
- Comentarios
Comentarios
No hay comentarios. Inicia sesión para comentar.