En la continuación de este tutorial vamos a ver en la segunda publicación la creación del proyecto backend ADMIN_APP utilizando Docker Compose para crear un proyecto con Laravel sobre Nginx y MySQL.

Índice

EL proyecto lo realizaremos en una 8 publicaciones apróximadamente, vamos a ver el punto 2 en esta publicación.

  1. Explicación del proyecto: Creación de una aplicación de microservicios con Laravel y RabbitMQ
  2. Creación del proyecto backend ADMIN-APP con Docker Compose : Laravel, Nginx y MySQL
    1. Creación del proyecto Laravel
    2. Contenedor Docker con la definición del Dockerfile para la máquina principal con PHP
    3. Creación del fichero de configuración para el servidor web con Nginx
    4. Configuración con docker-compose de Laravel / Servidor Web / MySQL
  3. Desarrollamos la API REST de ADMIN-APP para empresas y clientes
    1. CRUD controller y API controller para las empresas (cm_enterprise) (30/01/2022)
    2. CRUD controller y API controller para los clientes (cm_customer) (06/02/2022)
  4. Creación del proyecto order app con docker frontend pedidos
  5. RabbitMQ admin y order app , actualización de clientes
  6. Creamos la página de entrada de pedidos
  7. RabbitMQ Automatización y colas diferenciadas
  8. RabbitMQ actualizamos el saldo de clientes en ADMIN-APP desde ORDER-APP
  • Nota: durante las publicaciones este índice podrá sufrir alguna modificación para adaptar el contenido.

Software que utilizaremos

En este listado incluimos todo el software utilizado en todo el proyecto, no solo en esta publicación:

  • Linux (Ubuntu 20.04 LTS): sistema operativo Linux con la versión de Ubuntu 20.04 LTS
  • Docker (docker): Docker version 20.10.7, esta guía se ha generado utilizando esta versión de Docker.
  • Docker compose (docker-compose): docker-compose version 1.25.0, , esta guía se ha generado utilizando esta versión
  • Laravel 8: framewok PHP de desarrollo de aplicaciones web, en este caso utilizaremos la versión 8.
  • Mysql 5.7: versión utilizada en la imagen de docker-compose para la base de datos.
  • Nginx: servidor web de aplicaciones
  • PHP 7.4: utilizamos PHP en una versión superior a 7.4 siguiendo las recomendaciones de Laravel, por eso la imagen que utilicemos será de esta versión.
  • Composer 2: gestor de paquetes a partir de archivos json utilizado por Laravel, utilizamos Composer 2 porque lo necesitamos para Laravel 8, en esta publicación indicamos como actualizarlo.
  • Artisan: programa de línea de comandos de Laravel que nos ayuda en la creación de elementos como modelos, controladores, …, y también, nos proporciona otras utilidades como gestión de las migraciones o el listado de las rutas
  • RabbitMQ / CloudAMQP: en este proyecto utlizaremos CloudAMQP (provides managed RabbitMQ servers in the cloud), que nos proporciona un servidor para RabbitMQ en la nube, y así nos facilita el desarrollo en la nube. Otra opción sería instalar una máquina Docker con RabbitMQ pero eso complicaría el objetivo de este tutorial

2. Creación del proyecto backend ADMIN-APP con Docker Compose : Laravel, Nginx y MySQL

En la aplicacíon Admin APP crearemos una API para poder actualizar las empresas y clientes, será una aplicación desarrollada con el framework PHP Laravel utilizando como base de datos MySQL, como ya hemos comentado utilizaremos contenedores Docker para la gestión y mantenimiento de los proyectos.

Vamos a ver como crear un proyecto Laravel con Docker Compose con MySQL como motor de base de datos y Nginx como servidor de aplicaciones, aquí veremos paso a paso todo lo necesario, pero sin entrar en detalles, ya que los puedes ver en la publicación Docker Laravel: configuración e instalación de un proyecto con Laravel

Para este proyecto Admin APP creamos el directorio cx-lpm-customerdb-admin, dentro desde directorio crearemos nuestro proyecto y los contenedores Docker para el soporte del mismo:

mkdir cx-lpm-customerdb-admin

2.1. Creación del proyecto Laravel

Utilizaremos Composer para la creación del proyecto con Laravel, como vamos a usar Laravel 8, es necesario tener actualizado Composer a la versión 2, lo puedes ver en Instalación y actualización de Composer 2 ; una vez comprobado esto ya podemos proceder a crear el proyecto de Admin APP dentro de la carpeta cx-lpm-customerdb-admin, en mi caso voy a llamar al proyecto: cx-lpm-customerdb-admin-app:

$composer create-project laravel/laravel cx-lpm-customerdb-admin-app
 Creating a "laravel/laravel" project at "./cx-lpm-customerdb-admin-app"
 Installing laravel/laravel (v8.6.10)
 Installing laravel/laravel (v8.6.10): Extracting archive
 Created project in /home/xules/xulprocx-local/DOCKER-Projects/Docker-Laravel/cx-laravel-microservices-customerdb-publish/cx-lpm-customerdb-admin/cx-lpm-customerdb-admin-app 
   @php -r "file_exists('.env') || copy('.env.example', '.env');"
   Loading composer repositories with package information 

Hasta aquí se crean los directorios del proyecto, y posteriormente se descargan todas las librerías de partida para utilizar con el proyecto Laravel, si quieres ver el listado despliega la salida de la creación:

Updating dependencies
 Lock file operations: 110 installs, 0 updates, 0 removals
 Locking asm89/stack-cors (v2.0.5)
 Locking brick/math (0.9.3)
 Locking dflydev/dot-access-data (v3.0.1)
 Locking doctrine/inflector (2.0.4)
 Locking doctrine/instantiator (1.4.0)
 Locking doctrine/lexer (1.2.1)
 Locking dragonmantank/cron-expression (v3.2.3)
 Locking egulias/email-validator (2.1.25)
 Locking facade/flare-client-php (1.9.1)
 Locking facade/ignition (2.14.1)
 Locking facade/ignition-contracts (1.0.2)
 Locking fakerphp/faker (v1.17.0)
 Locking filp/whoops (2.14.5)
 Locking fruitcake/laravel-cors (v2.0.5)
 Locking graham-campbell/result-type (v1.0.4)
 Locking guzzlehttp/guzzle (7.4.1)
 Locking guzzlehttp/promises (1.5.1)
 Locking guzzlehttp/psr7 (2.1.0)
 Locking hamcrest/hamcrest-php (v2.0.1)
 Locking laravel/framework (v8.78.1)
 Locking laravel/sail (v1.12.12)
 Locking laravel/sanctum (v2.13.0)
 Locking laravel/serializable-closure (v1.0.5)
 Locking laravel/tinker (v2.6.3)
 Locking league/commonmark (2.1.1)
 Locking league/config (v1.1.1)
 Locking league/flysystem (1.1.9)
 Locking league/mime-type-detection (1.9.0)
 Locking mockery/mockery (1.4.4)
 Locking monolog/monolog (2.3.5)
 Locking myclabs/deep-copy (1.10.2)
 Locking nesbot/carbon (2.55.2)
 Locking nette/schema (v1.2.2)
 Locking nette/utils (v3.2.6)
 Locking nikic/php-parser (v4.13.2)
 Locking nunomaduro/collision (v5.10.0)
 Locking opis/closure (3.6.2)
 Locking phar-io/manifest (2.0.3)
 Locking phar-io/version (3.1.0)
 Locking phpdocumentor/reflection-common (2.2.0)
 Locking phpdocumentor/reflection-docblock (5.3.0)
 Locking phpdocumentor/type-resolver (1.6.0)
 Locking phpoption/phpoption (1.8.1)
 Locking phpspec/prophecy (v1.15.0)
 Locking phpunit/php-code-coverage (9.2.10)
 Locking phpunit/php-file-iterator (3.0.6)
 Locking phpunit/php-invoker (3.1.1)
 Locking phpunit/php-text-template (2.0.4)
 Locking phpunit/php-timer (5.0.3)
 Locking phpunit/phpunit (9.5.11)
 Locking psr/container (1.1.2)
 Locking psr/event-dispatcher (1.0.0)
 Locking psr/http-client (1.0.1)
 Locking psr/http-factory (1.0.1)
 Locking psr/http-message (1.0.1)
 Locking psr/log (1.1.4)
 Locking psr/simple-cache (1.0.1)
 Locking psy/psysh (v0.10.12)
 Locking ralouphie/getallheaders (3.0.3)
 Locking ramsey/collection (1.2.2)
 Locking ramsey/uuid (4.2.3)
 Locking sebastian/cli-parser (1.0.1)
 Locking sebastian/code-unit (1.0.8)
 Locking sebastian/code-unit-reverse-lookup (2.0.3)
 Locking sebastian/comparator (4.0.6)
 Locking sebastian/complexity (2.0.2)
 Locking sebastian/diff (4.0.4)
 Locking sebastian/environment (5.1.3)
 Locking sebastian/exporter (4.0.4)
 Locking sebastian/global-state (5.0.3)
 Locking sebastian/lines-of-code (1.0.3)
 Locking sebastian/object-enumerator (4.0.4)
 Locking sebastian/object-reflector (2.0.4)
 Locking sebastian/recursion-context (4.0.4)
 Locking sebastian/resource-operations (3.0.3)
 Locking sebastian/type (2.3.4)
 Locking sebastian/version (3.0.2)
 Locking swiftmailer/swiftmailer (v6.3.0)
 Locking symfony/console (v5.4.2)
 Locking symfony/css-selector (v5.4.2)
 Locking symfony/deprecation-contracts (v2.5.0)
 Locking symfony/error-handler (v5.4.2)
 Locking symfony/event-dispatcher (v5.4.0)
 Locking symfony/event-dispatcher-contracts (v2.5.0)
 Locking symfony/finder (v5.4.2)
 Locking symfony/http-foundation (v5.4.2)
 Locking symfony/http-kernel (v5.4.2)
 Locking symfony/mime (v5.4.2)
 Locking symfony/polyfill-ctype (v1.24.0)
 Locking symfony/polyfill-iconv (v1.24.0)
 Locking symfony/polyfill-intl-grapheme (v1.24.0)
 Locking symfony/polyfill-intl-idn (v1.24.0)
 Locking symfony/polyfill-intl-normalizer (v1.24.0)
 Locking symfony/polyfill-mbstring (v1.24.0)
 Locking symfony/polyfill-php72 (v1.24.0)
 Locking symfony/polyfill-php73 (v1.24.0)
 Locking symfony/polyfill-php80 (v1.24.0)
 Locking symfony/polyfill-php81 (v1.24.0)
 Locking symfony/process (v5.4.2)
 Locking symfony/routing (v5.4.0)
 Locking symfony/service-contracts (v2.5.0)
 Locking symfony/string (v5.4.2)
 Locking symfony/translation (v5.4.2)
 Locking symfony/translation-contracts (v2.5.0)
 Locking symfony/var-dumper (v5.4.2)
 Locking theseer/tokenizer (1.2.1)
 Locking tijsverkoyen/css-to-inline-styles (2.2.4)
 Locking vlucas/phpdotenv (v5.4.1)
 Locking voku/portable-ascii (1.5.6)
 Locking webmozart/assert (1.10.0)
 Writing lock file
 Installing dependencies from lock file (including require-dev)
 Package operations: 110 installs, 0 updates, 0 removals
 Downloading symfony/polyfill-ctype (v1.24.0)
 Downloading dragonmantank/cron-expression (v3.2.3)
 Downloading symfony/polyfill-php80 (v1.24.0)
 Downloading symfony/polyfill-mbstring (v1.24.0)
 Downloading symfony/var-dumper (v5.4.2)
 Downloading symfony/polyfill-intl-grapheme (v1.24.0)
 Downloading symfony/string (v5.4.2)
 Downloading symfony/deprecation-contracts (v2.5.0)
 Downloading psr/container (1.1.2)
 Downloading symfony/service-contracts (v2.5.0)
 Downloading symfony/polyfill-php73 (v1.24.0)
 Downloading symfony/console (v5.4.2)
 Downloading phpoption/phpoption (1.8.1)
 Downloading graham-campbell/result-type (v1.0.4)
 Downloading vlucas/phpdotenv (v5.4.1)
 Downloading symfony/css-selector (v5.4.2)
 Downloading tijsverkoyen/css-to-inline-styles (2.2.4)
 Downloading symfony/routing (v5.4.0)
 Downloading symfony/process (v5.4.2)
 Downloading symfony/polyfill-intl-idn (v1.24.0)
 Downloading symfony/mime (v5.4.2)
 Downloading symfony/http-foundation (v5.4.2)
 Downloading symfony/event-dispatcher-contracts (v2.5.0)
 Downloading symfony/event-dispatcher (v5.4.0)
 Downloading symfony/error-handler (v5.4.2)
 Downloading symfony/http-kernel (v5.4.2)
 Downloading symfony/finder (v5.4.2)
 Downloading symfony/polyfill-iconv (v1.24.0)
 Downloading symfony/polyfill-php81 (v1.24.0)
 Downloading symfony/translation-contracts (v2.5.0)
 Downloading symfony/translation (v5.4.2)
 Downloading nesbot/carbon (2.55.2)
 Downloading league/mime-type-detection (1.9.0)
 Downloading league/flysystem (1.1.9)
 Downloading nette/utils (v3.2.6)
 Downloading league/commonmark (2.1.1)
 Downloading laravel/serializable-closure (v1.0.5)
 Downloading laravel/framework (v8.78.1)
 Downloading fakerphp/faker (v1.17.0)
 Downloading asm89/stack-cors (v2.0.5)
 Downloading fruitcake/laravel-cors (v2.0.5)
 Downloading guzzlehttp/guzzle (7.4.1)
 Downloading laravel/sail (v1.12.12)
 Downloading laravel/sanctum (v2.13.0)
 Downloading nikic/php-parser (v4.13.2)
 Downloading psy/psysh (v0.10.12)
 Downloading laravel/tinker (v2.6.3)
 Downloading filp/whoops (2.14.5)
 Downloading phpdocumentor/type-resolver (1.6.0)
 Downloading sebastian/exporter (4.0.4)
 Downloading phpunit/php-file-iterator (3.0.6)
 Downloading phpunit/php-code-coverage (9.2.10)
 Downloading phpspec/prophecy (v1.15.0)
 Downloading phpunit/phpunit (9.5.11)
 Installing doctrine/inflector (2.0.4): Extracting archive
 Installing doctrine/lexer (1.2.1): Extracting archive
 Installing symfony/polyfill-ctype (v1.24.0): Extracting archive
 Installing webmozart/assert (1.10.0): Extracting archive
 Installing dragonmantank/cron-expression (v3.2.3): Extracting archive
 Installing symfony/polyfill-php80 (v1.24.0): Extracting archive
 Installing symfony/polyfill-mbstring (v1.24.0): Extracting archive
 Installing symfony/var-dumper (v5.4.2): Extracting archive
 Installing symfony/polyfill-intl-normalizer (v1.24.0): Extracting archive
 Installing symfony/polyfill-intl-grapheme (v1.24.0): Extracting archive
 Installing symfony/string (v5.4.2): Extracting archive
 Installing symfony/deprecation-contracts (v2.5.0): Extracting archive
 Installing psr/container (1.1.2): Extracting archive
 Installing symfony/service-contracts (v2.5.0): Extracting archive
 Installing symfony/polyfill-php73 (v1.24.0): Extracting archive
 Installing symfony/console (v5.4.2): Extracting archive
 Installing psr/log (1.1.4): Extracting archive
 Installing monolog/monolog (2.3.5): Extracting archive
 Installing voku/portable-ascii (1.5.6): Extracting archive
 Installing phpoption/phpoption (1.8.1): Extracting archive
 Installing graham-campbell/result-type (v1.0.4): Extracting archive
 Installing vlucas/phpdotenv (v5.4.1): Extracting archive
 Installing symfony/css-selector (v5.4.2): Extracting archive
 Installing tijsverkoyen/css-to-inline-styles (2.2.4): Extracting archive
 Installing symfony/routing (v5.4.0): Extracting archive
 Installing symfony/process (v5.4.2): Extracting archive
 Installing symfony/polyfill-php72 (v1.24.0): Extracting archive
 Installing symfony/polyfill-intl-idn (v1.24.0): Extracting archive
 Installing symfony/mime (v5.4.2): Extracting archive
 Installing symfony/http-foundation (v5.4.2): Extracting archive
 Installing psr/event-dispatcher (1.0.0): Extracting archive
 Installing symfony/event-dispatcher-contracts (v2.5.0): Extracting archive
 Installing symfony/event-dispatcher (v5.4.0): Extracting archive
 Installing symfony/error-handler (v5.4.2): Extracting archive
 Installing symfony/http-kernel (v5.4.2): Extracting archive
 Installing symfony/finder (v5.4.2): Extracting archive
 Installing symfony/polyfill-iconv (v1.24.0): Extracting archive
 Installing egulias/email-validator (2.1.25): Extracting archive
 Installing swiftmailer/swiftmailer (v6.3.0): Extracting archive
 Installing symfony/polyfill-php81 (v1.24.0): Extracting archive
 Installing ramsey/collection (1.2.2): Extracting archive
 Installing brick/math (0.9.3): Extracting archive
 Installing ramsey/uuid (4.2.3): Extracting archive
 Installing psr/simple-cache (1.0.1): Extracting archive
 Installing opis/closure (3.6.2): Extracting archive
 Installing symfony/translation-contracts (v2.5.0): Extracting archive
 Installing symfony/translation (v5.4.2): Extracting archive
 Installing nesbot/carbon (2.55.2): Extracting archive
 Installing league/mime-type-detection (1.9.0): Extracting archive
 Installing league/flysystem (1.1.9): Extracting archive
 Installing nette/utils (v3.2.6): Extracting archive
 Installing nette/schema (v1.2.2): Extracting archive
 Installing dflydev/dot-access-data (v3.0.1): Extracting archive
 Installing league/config (v1.1.1): Extracting archive
 Installing league/commonmark (2.1.1): Extracting archive
 Installing laravel/serializable-closure (v1.0.5): Extracting archive
 Installing laravel/framework (v8.78.1): Extracting archive
 Installing facade/ignition-contracts (1.0.2): Extracting archive
 Installing facade/flare-client-php (1.9.1): Extracting archive
 Installing facade/ignition (2.14.1): Extracting archive
 Installing fakerphp/faker (v1.17.0): Extracting archive
 Installing asm89/stack-cors (v2.0.5): Extracting archive
 Installing fruitcake/laravel-cors (v2.0.5): Extracting archive
 Installing psr/http-message (1.0.1): Extracting archive
 Installing psr/http-client (1.0.1): Extracting archive
 Installing ralouphie/getallheaders (3.0.3): Extracting archive
 Installing psr/http-factory (1.0.1): Extracting archive
 Installing guzzlehttp/psr7 (2.1.0): Extracting archive
 Installing guzzlehttp/promises (1.5.1): Extracting archive
 Installing guzzlehttp/guzzle (7.4.1): Extracting archive
 Installing laravel/sail (v1.12.12): Extracting archive
 Installing laravel/sanctum (v2.13.0): Extracting archive
 Installing nikic/php-parser (v4.13.2): Extracting archive
 Installing psy/psysh (v0.10.12): Extracting archive
 Installing laravel/tinker (v2.6.3): Extracting archive
 Installing hamcrest/hamcrest-php (v2.0.1): Extracting archive
 Installing mockery/mockery (1.4.4): Extracting archive
 Installing filp/whoops (2.14.5): Extracting archive
 Installing nunomaduro/collision (v5.10.0): Extracting archive
 Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
 Installing phpdocumentor/type-resolver (1.6.0): Extracting archive
 Installing phpdocumentor/reflection-docblock (5.3.0): Extracting archive
 Installing sebastian/version (3.0.2): Extracting archive
 Installing sebastian/type (2.3.4): Extracting archive
 Installing sebastian/resource-operations (3.0.3): Extracting archive
 Installing sebastian/recursion-context (4.0.4): Extracting archive
 Installing sebastian/object-reflector (2.0.4): Extracting archive
 Installing sebastian/object-enumerator (4.0.4): Extracting archive
 Installing sebastian/global-state (5.0.3): Extracting archive
 Installing sebastian/exporter (4.0.4): Extracting archive
 Installing sebastian/environment (5.1.3): Extracting archive
 Installing sebastian/diff (4.0.4): Extracting archive
 Installing sebastian/comparator (4.0.6): Extracting archive
 Installing sebastian/code-unit (1.0.8): Extracting archive
 Installing sebastian/cli-parser (1.0.1): Extracting archive
 Installing phpunit/php-timer (5.0.3): Extracting archive
 Installing phpunit/php-text-template (2.0.4): Extracting archive
 Installing phpunit/php-invoker (3.1.1): Extracting archive
 Installing phpunit/php-file-iterator (3.0.6): Extracting archive
 Installing theseer/tokenizer (1.2.1): Extracting archive
 Installing sebastian/lines-of-code (1.0.3): Extracting archive
 Installing sebastian/complexity (2.0.2): Extracting archive
 Installing sebastian/code-unit-reverse-lookup (2.0.3): Extracting archive
 Installing phpunit/php-code-coverage (9.2.10): Extracting archive
 Installing doctrine/instantiator (1.4.0): Extracting archive
 Installing phpspec/prophecy (v1.15.0): Extracting archive
 Installing phar-io/version (3.1.0): Extracting archive
 Installing phar-io/manifest (2.0.3): Extracting archive
 Installing myclabs/deep-copy (1.10.2): Extracting archive
 Installing phpunit/phpunit (9.5.11): Extracting archive
 80 package suggestions were added by new dependencies, use <code>composer suggest</code> to see details.
 Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead.
 Generating optimized autoload files 
   Illuminate\Foundation\ComposerScripts::postAutoloadDump
   @php artisan package:discover --ansi
   Discovered Package: facade/ignition
   Discovered Package: fruitcake/laravel-cors
   Discovered Package: laravel/sail
   Discovered Package: laravel/sanctum
   Discovered Package: laravel/tinker
   Discovered Package: nesbot/carbon
   Discovered Package: nunomaduro/collision
   Package manifest generated successfully.
   77 packages you are using are looking for funding.
   Use the <code>composer fund</code> command to find out more!
   @php artisan vendor:publish --tag=laravel-assets --ansi --force
   No publishable resources for tag [laravel-assets].
   Publishing complete.
   @php artisan key:generate --ansi 
Application key set successfully.

2.2. Contenedor Docker con la definición del Dockerfile para la máquina principal con PHP

Para la creación del fichero Dockerfile nos situamos dentro de la carpeta que hemos creado al crear el proyecto Laravel, en mi caso cx-lcustomerdb, una vez dentro creamos el fichero Dockerfile (este fichero se crea sin extensión de tipo de archivo) veremos paso a paso su contenido explicando los comandos y utilidades, partimos de una imagen php con la versión 7.4 para ello utilizamos la imagen disponible: 7.4-fpm

El fichero Dockerfile sería el siguiente a posteriori hago una explicación breve, ya que tienes una explicación detallada en : Creación del Dockerfile de la máquina principal con PHP, la creación de la imagen parte de una imagen PHP en concreto php:7.4-fpm, los demás pasos seguidos tenéis una explicación breve en el propio fichero:

FROM php:7.4-fpm

# Permitimos el paso de parámetros (argumentos) que se definirán en el fichero docker-compose.yml
ARG user
ARG uid

# Añadimos dependencias y utilidades interesantes al sistema como: git, curl, zip, ...:
RUN apt-get update apt-get install -y \
    git \
    curl \
    libxml2-dev \
    libonig-dev \
    libpng-dev \
    zip \
    unzip

# Una vez finalizado borramos cache y limpiamos los archivos de instalación
RUN apt-get clean rm -rf /var/lib/apt/lists/*

# Instalamos las dependencias y extensiones PHP que necesitaremos en nuestro proyecto como: pdo_mysql o mbstring
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd sockets 

# Instalamos dentro de la imagen la última versión de composer, para ello copiamos la imagen disponible en el repositorio:
COPY --from=composer:2.0.13 /usr/bin/composer /usr/bin/composer

# Copiamos de la última imagen de node en nuestro proyecto las librerías de los módulos y de node
COPY --from=node:latest /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=node:latest /usr/local/bin/node /usr/local/bin/node
# Creamos un enlace virtual para poder utilizar directamente npm dentro de la máquina Docker:
RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm


# Creamos un usuario de sistema para ejecutar los comando Composer y Artisan:
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Definimos el directorio de trabajo dentro de nuestra imagen
WORKDIR /var/www

USER $user

2.3. Creación del fichero de configuración para el servidor web con Nginx

Este fichero lo utilizarmoes dentro del fichero docker-compose un fichero de configuración para el servidor Nginx, en este fichero se define el puerto de escucha los ficheros index, y de log, está es una configuracion estándar de un servidor Nginx, por ello no entraremos en más detalles.

En mi caso dentro del proyecto creo una carpeta denominada docker-compose y dentro otra llamada nginx, aquí creamos el fichero cx-lpm-customerdb-server.conf dentro de la carpeta nginx creada anteroirmente y con la siguiente configuración:

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 admin-app-lpm: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;
     }
 }

Es un fichero de configuración básico para Nginx, lo único que podrás ver algo diferente es donde hacemos referencia al equipo que admin-app-lpm que definiremos con docker-compose.

Ya tenemos todo lo necesarico para crear ya el fichero docker-compose del proyecto.

2.4. Configuración con docker-compose de Laravel / Servidor Web / MySQL

En nuestro fichero de configuración de docker-compose vamos a definir 3 servicios y 1 red, los servicios que definiremos serán:

  • admin-app-lpm: en este servicio instalamos una imagen con PHP en concreto la versión php:7.4-fpm, p, la variante que se utiliza aquí correspondiente a php:<version>-fpm es una variante la cual contiene una implementación FastCGI para PHP, esta configuración la definimos anteriormente en el fichero Dockerfile.
  • admin-db-lpm: este servicio lo vamos a dedicar a nuestra base de datos MySQL para ello partiremos de la imagen: mysql:5.7, ,utilizaremos los parámetros para la creación de los usuarios, claves y base de datos inicial, la definición por defecto de Laravel en el fichero..env , veremos como.
  • nginx: nuestro servidor de aplicaciones web donde lanzaremos nuestra aplicación, utilizamos como ya hemos visto una configuración estándar en cx-lpm-customerdb-server.conf, lo único que necesitamos activar el servicio fastcgi al utilizar la imagen php:7.4-fpm

Como red definimos net-cx-lpm-customerdb que tiene una configuración básica en modo bridge como veremos asociaremos todos los servicios dentro de la misma red para que estén interconectados.

La estructura inicial del fichero sobre el que iremos añadiendo la configuración a los servicios es la siguiente:

version: "3"
 services:
   admin-app-lpm:
     build:
       dockerfile: Dockerfile
     image: cx-lpm-customerdb-admin-app-001
     container_name: cx-lpm-customerdb-admin-app-001
     ……….
     networks:
       - net-cx-lpm-customerdb-admin-001
   admin-db-lpm:
     image: mysql:5.7
     container_name: cx-lcustomerdb-db
     ……….
     networks:
       - net-cx-lpm-customerdb-admin-001
   nginx:
    image: nginx:1.21.3-alpine
    container_name: cx-lpm-customerdb-admin-nginx-001
     ……….
     networks:
       - net-cx-lpm-customerdb-admin-001
 networks:
   net-cx-lpm-customerdb-admin-001:
     driver: bridge

Después de explicar la estructura base de nuestra aplicación con docker-compose vamos a ir viendo paso a paso la definición de cada uno de los servicios.

Servicio admin-app-lpm: aplicación Laravel

En el apartado 2 hemos definido el fichero Dockerfile con la estructura base de nuestra aplicación, a partir de una imagen base de php , donde definimos 2 parámetros user y uid, y hacemos referencia a la red net-cx-lpm-customerdb-admin-001 que definimos anteriormente, en el apartado volumes incluimos la referencia al proyecto:

version: "3"
 services:
  admin-app-lpm:
    build:
      args:
        user: xules
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: cx-lpm-customerdb-admin-app-001
    container_name: cx-lpm-customerdb-admin-app-001
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      - ./:/var/www
    networks:
      - net-cx-lpm-customerdb-admin-001 

Servicio admin-db-lpm: base de datos MySQL

En este servicio creamos el servidor de base de datos MySQL, para ello utilizaremos la imagen mysql:5.7, nos serviremos de las variables de entorno que hemos definido en el fichero .env al crear el proyecto con Laravel, docker-compose entiende por defecto está configuración si el fichero tuviese otro nombre se le podría indicar con la etiqueta env_file.

version: "3"
 services:
  admin-app-lpm:
     ...
  admin-db-lpm:
    image: mysql:latest
    container_name: cx-lpm-customerdb-admin-db-001
    restart: unless-stopped
    ports:
     - 127.0.0.1:23317:3306
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - ../cx-lpm-customerdb-admin-db/var/lib/mysql:/var/lib/mysql
    networks:
      - net-cx-lpm-customerdb-admin-001

Ya podemos definir en nuestro fichero .env los datos de conexión a la base de datos en nuestro caso, el nombre de la base de datos será customerminidb:

DB_CONNECTION=mysql
DB_HOST=cx-lpm-customerdb-admin-db-001
DB_PORT=3306
DB_DATABASE=customerminidb
DB_USERNAME=xules
DB_PASSWORD=xulescode

En nuestro caso no hemos creado todavía la base de datos la crearemos una vez lancemos la aplicación con docker-compose ya que utilizamos un volumen para hacer la base de datos persistente en la instalación.

Servicio nginx: servidor de aplicaciones Nginx

Para el servidor de aplicaciones utizamos Nginx como ya hemos comentado antes, hemos visto un fichero de configuración estándar de Nginx y donde el servidor estará escuchando en el puerto 80. Utilizamos la imagen nginx:alpine , alpine hace referencia a Alpine Linux Project que es una distribución de Linux optimizado, orientada a la seguridad y de muy poco peso.

La configuración final es la siguiente, donde hacemos referencia al fichero de configuración y al alojamiento del proyecto en el apartado de volumes, se define como puerto externo de escucha el 28021 y la red definida para el proyecto:

  admin-nginx-lpm:
    image: nginx:1.21.3-alpine
    container_name: cx-lpm-customerdb-admin-nginx-001
    restart: unless-stopped
    ports:
      - 127.0.0.1:28021:80
    volumes:
      - ./:/var/www
      - ./docker-compose/nginx:/etc/nginx/conf.d/
    networks:
      - net-cx-lpm-customerdb-admin-001

Construimos nuestros contenedores e instalamos dependencias

Una vez que ya hemos completado nuestro fichero llega el momento de construirlo para ello docker-compose descargá las imágenes solicitadas sino disponemos de ellas en nuestro equipo, antes os dejo el fichero completo de docker-compose, despliega para ver la información completa:

version: "3"
# En el nodo services para incluir los servicios app, db y nginx.
services:
  admin-app-lpm:
    build:
      args:
        user: xules
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: cx-lpm-customerdb-admin-app-001
    container_name: cx-lpm-customerdb-admin-app-001
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      - ./:/var/www
    networks:
      - net-cx-lpm-customerdb-admin-001 
  admin-db-lpm:
    image: mysql:latest
    container_name: cx-lpm-customerdb-admin-db-001
    restart: unless-stopped
    ports:
     - 127.0.0.1:23317:3306
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - ../cx-lpm-customerdb-admin-db/var/lib/mysql:/var/lib/mysql
    networks:
      - net-cx-lpm-customerdb-admin-001

  admin-nginx-lpm:
    image: nginx:1.21.3-alpine
    container_name: cx-lpm-customerdb-admin-nginx-001
    restart: unless-stopped
    ports:
      - 127.0.0.1:28021:80
    volumes:
      - ./:/var/www
      - ./docker-compose/nginx:/etc/nginx/conf.d/
    networks:
      - net-cx-lpm-customerdb-admin-001
networks:
  net-cx-lpm-customerdb-admin-001:
    driver: bridge

Una vez tenemos completo el fichero docker-compose ya podemos lanzar la construcción de las indicaciones del fichero utilizamos uno de los comandos que nos proporciona docker-compose que es build, también podemos construirlo y lanzarlo con up, en nuestro caso vamos a hacerlo todo directamente con up:

xules@xxxxx:~/$ docker-compose up

Con la aplicación levantada procedemos a instalar composer y node, para instalar composer lanzamos composer install dentro del contenedor:

xules@xxxx:/$ docker-compose exec admin-app-lpm composer install
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead.
Generating optimized autoload files
&amp;amp;amp;amp;amp;amp;amp;gt; Illuminate\Foundation\ComposerScripts::postAutoloadDump
&amp;amp;amp;amp;amp;amp;amp;gt; @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
77 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

Seguimos ahora con la generación de la clave para nuestra aplicación con la llamada a artisan, para ello con docker-compose llamamos a la aplicación app para que ejecute la generación automática de la clave:

xules@xxxxx:~/$ docker-compose exec admin-app-lpm php artisan key:generate
Application key set successfully.

Instalamos node y npm con los paquetes que hemos decargado y copiado de la imagen original:

xules@xxxxx:~/$ docker-compose exec admin-app-lpm npm install
npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.

added 755 packages, and audited 756 packages in 41s

82 packages are looking for funding
  run `npm fund` for details

4 low severity vulnerabilities

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

Creamos ya también la base de datos, accediendo al contenedor de MySQL:

xules@xxxxx:~/$ docker exec -it cx-lpm-customerdb-admin-db-001 bash
root@b5548d1dfd2a:/# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.26 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql&amp;amp;amp;amp;amp;amp;amp;gt; create database customerminidb;
Query OK, 1 row affected (0.01 sec)

Ahora ya podemos comprobar que tenemos listo nuestro proyecto para empezar accediendo en el navegador a http://localhost:28021/, si todo fue bien verá la info por defecto de creación de un proyecto con Laravel:

Docker Laravel Home page
Docker Laravel Home page