Introducción
Lumen es un micro-framework de Laravel. Es la solución perfecta para crear micro-servicios y APIs. Como está formada por los componentes de Laravel, Lumen te permite utilizar todas tus características favoritas de Laravel, como Eloquent, almacenamiento en caché, colas, validación, enrutamiento y middleware.
Deployer es una herramienta de despliegue escrita en PHP con soporte para frameworks populares listos para usar. Aunque no viene con una receta específica de Lumen, puedes reutilizar su receta actual de Laravel y ajustarla a tus necesidades.
En este tutorial, crearemos una API Lumen simple en una máquina local y la desplegaremos en el servidor Ubuntu 18.04 con Deployer.
Requisitos previos
El framework Lumen viene con algunos Requisitos de Servidor. Además de eso, vamos a configurar dos máquinas:
- Una máquina local que se usará para agrupar el código API de Lumen y subirlo al servidor Ubuntu usando Deployer.
- Una máquina servidor que se convertirá en el objetivo del despliegue, donde se ejecutará la API de Lumen.
Nota
En lugar de implementar el código desde la máquina local, podríamos usar una de las soluciones de CI existentes como Travis, Github Actions o Gitlab Runners. Sin embargo, en este tutorial, para simplificar, utilizaremos la máquina local tanto para el desarrollo como para el despliegue.
Requisitos previos de la máquina servidor
El único requisito previo aquí es el servidor Ubuntu 18.04, accesible con una contraseña de root a través de SSH. En este tutorial, iremos paso a paso para la instalación de PHP 7.4 y Apache 2.4 con mod_php en este servidor.
Requisitos previos de la máquina local
Aquí hay algunos requisitos previos, incluyendo PHP, Composer y Deployer. Algunas forma de conseguir que corran localmente son las siguientes:
- Instalación de un servidor web PHP en el sistema operativo, es decir: MAMP
- Usar un hipervisor alojado como VirtualBox con Vagrant. O incluso mejor, usando una caja Vagrant oficial, pre-paquetizada Laravel Homestead.
- Usar una tecnología de contenedor como Docker con Docker Compose para definir los servicios de la aplicación en formato YAML. O incluso mejor, usando Laradock, el proyecto de la comunidad Laravel.
En este tutorial no entraremos en detalles sobre cómo crear este entorno local. En cambio, nos centraremos en crear un proyecto con Composer, instalar Deployer y configurarlo según nuestras necesidades.
Sin más preámbulos, comencemos con la configuración de la máquina del servidor.
Instalación de PHP 7.4 y Apache2
Ubuntu 18.04 viene con la versión PHP 7.2 por defecto, por lo que necesitaremos usar los repositorios deb proporcionados por Sury.org para obtener la versión de PHP más nueva.
Para Ubuntu, Sury mantiene los Archivos Personales Paquetizados de PHP Ubuntu, que vamos a instalar ahora:
apt install software-properties-common -y add-apt-repository ppa:ondrej/php -y apt update -y apt install php7.4
Debido a que php7.4 depende de libapache2-mod-php7.4, que a su vez recomienda el paquete apache2 obtendremos PHP y Apache con mod_php en funcionamiento de una sola vez.
Configuración de Apache2 para servir la API Lumen
cd /etc/apache2/sites-available/ cat > 001-lumen-api.conf <<EOF
<VirtualHost *:80> ServerName lumen_api DocumentRoot /var/www/lumen_api/current/public DirectoryIndex /index.php <Directory /var/www/lumen_api/current/public> AllowOverride None Require all granted FallbackResource /index.php </Directory> ErrorLog /var/log/apache2/lumen_api_error.log CustomLog /var/log/apache2/lumen_api_access.log combined </VirtualHost> EOF
Hagamos una pausa aquí por un momento e intentemos entender porqué DocumentRoot y Directory apuntan a /var/www/lumen_api/current/public y no a /var/www/lumen_api/public, como recomienda la documentación de Lumen.
Como hemos decidido usar la herramienta Deployer para el despliegue, creará los siguientes directorios:
- releases que contiene directorios de lanzamientos.
- current que es un enlace simbólico al directorio de la versión actual - éste es el directorio que Apache2 debería conocer y leer.
- shared que contiene archivos y directorios compartidos.
Sabiendo esto, procedamos al último paso, es decir, deshabilitar la configuración predeterminada de Apache2 y habilitar la nuestra:
a2dissite 000-default.conf a2ensite 001-lumen-api.conf
Con todo esto, ya tenemos nuestro servidor Ubuntu corriendo y en funcionamiento. Ahora nos centraremos en la base de código de la API Lumen.
Base de código de la API Lumen en la máquina local
composer create-project --prefer-dist laravel/lumen lumen-api
Después de haber ejecutado el comando Composer, deberíamos tener el directorio lumen-api con el proyecto Lumen estructurado, como se muestra más abajo:
.
├── README.md
├── app
│ ├── Console
│ │ ├── Commands
│ │ └── Kernel.php
│ ├── Events
│ │ ├── Event.php
│ │ └── ExampleEvent.php
│ ├── Exceptions
│ │ └── Handler.php
│ ├── Http
│ │ ├── Controllers
│ │ └── Middleware
│ ├── Jobs
│ │ ├── ExampleJob.php
│ │ └── Job.php
│ ├── Listeners
│ │ └── ExampleListener.php
│ ├── Providers
│ │ ├── AppServiceProvider.php
│ │ ├── AuthServiceProvider.php
│ │ └── EventServiceProvider.php
│ └── User.php
├── artisan
├── bootstrap
│ └── app.php
├── composer.json
├── composer.lock
├── database
│ ├── factories
│ │ └── ModelFactory.php
│ ├── migrations
│ └── seeds
│ └── DatabaseSeeder.php
├── deploy.php
├── phpunit.xml
├── public
│ └── index.php
├── resources
│ └── views
├── routes
│ └── web.php
├── storage
│ ├── app
│ ├── framework
│ │ ├── cache
│ │ └── views
│ └── logs
│ └── lumen-2020-04-11.log
├── tests
│ ├── ExampleTest.php
│ └── TestCase.php
└── vendor
├── autoload.php
├── bin
/// ...
Para simplificar las cosas, vamos a agregar una ruta GET /timezones dentro del archivo routes/web.php, como se muestra más abajo:
<?php
$router->get('/', function () use ($router) {
return $router->app->version();
});
// Simple GET route to list all Time Zones Identifiers.
$router->get('/timezones', function () {
return DateTimeZone::listIdentifiers();
});
Nuestra Lumen API está funcionando en local, pero aún nos falta el paso final: agrupar y cargar el código en el servidor Ubuntu 18.04 con Deployer. Para esto, necesitamos instalar y configurar la herramienta Deployer.
Deployer en la máquina local
Hay tres formas de instalar Deployer:
- Archivo PHAR
- Instalación del compositor fuente
- Instalación del compositor de sustitución
Para este tutorial, hemos escogido la segunda forma: instalación del compositor fuente
Instalación de Deployer con Composer como una dependencia dev
composer require deployer/deployer --dev
Después de que hayamos requerido la dependencia de Deployer, nuestro archivo composer.json debería ser similar al siguiente fragmento:
{
"name": "laravel/lumen",
"description": "The Laravel Lumen Framework.",
"keywords": ["framework", "laravel", "lumen"],
"license": "MIT",
"type": "project",
"require": {
"php": "^7.2.5",
"laravel/lumen-framework": "^7.0"
},
"require-dev": {
"deployer/deployer": "^6.7",
"fzaninotto/faker": "^1.9.1",
"mockery/mockery": "^1.3.1",
"phpunit/phpunit": "^8.5"
},
...
}
Adicionalmente, deberíamos obtener el nuevo ejecutable dep dentro del directorio vendor/bin:./vendor/bin/dep --version
Creación de la receta Deployer
dep init --template=Laravel
Este comando ha creado el archivo básico deploy.php y lo ha inicializado con la plantilla de receta de Laravel.
Nota
Si quieres ampliar la información sobre lo que aporta la receta de Laravel, puedes hacerlo tú mismo en GitHub.
Ajuste de la receta de Deployer
php
<?php
namespace Deployer;
require 'recipe/laravel.php';
// Hosts
host('IP_OR_DOMAIN_OF_YOUR_UBUNTU_SERVER')
->user('root')
->port(22)
->set('deploy_path', '/var/www/lumen_api');
// Main deploy task which consist of 4 other steps
task('deploy', [
'build',
'release',
'cleanup',
'success'
]);
// Installs all Lumen API dependencies on local machine
task('build', function () {
run('composer install');
})->local();
task('release', [
'deploy:prepare',
'deploy:release',
'upload',
'deploy:shared',
'deploy:writable',
'deploy:symlink',
]);
// Uploads current directory from local machine to the release path on the ubuntu server machine
task('upload', function () {
upload(__DIR__ . "/", '{{release_path}}');
});
Antes de continuar, examinemos juntos lo que acaba de ocurrir:
- Hemos definido sólo un host con contraseña root dentro de nuestra receta. Sin embargo, podríamos utilizar en su lugar el Arhivo Inventorio y las llaves SSH.
- Hemos usado Build Server Strategy y hemos hecho que Composer corra de forma local para simplificar el número de pasos. Sin embargo, podríamos usar Single Server Strategy y correr todos los pasos en el servidor, incluido el repositorio GIT.
- Hemos sobreescrito la tarea deploy por defecto y la hemos ajustado a nuestras necesidades. Pero hay mucho más que aprender sobre Deployer Flow para aquéllos que tengáis sed de conocimiento.
Despliegue
Antes de proceder al despliegue, veamos lo que hemos conseguido hasta ahora:
- Hemos configurado con éxito el Servidor Ubuntu 18.04 con PHP 7.4 y Apache 2.4 corriendo en modo mod_php.
- Hemos estructurado la API Lumen simple en nuestra máquina local
- Hemos instalado Deployer y lo hemos configurado para construir nuestra API Lumen con todas sus dependencias en nuestra máquina local.
Es hora del paso final: el despliegue. Por suerte, éste es bastante simple
dep deploy
El proceso de despliegue debería tomar 1-2 minutos y parecerse bastante a este extracto:
✔ Executing task build
➤ Executing task deploy:prepare
✔ root@85.208.21.90's password:
✔ Executing task deploy:release
➤ Executing task upload
✔ root@85.208.21.90's password:
✔ Executing task deploy:shared
✔ Executing task deploy:writable
✔ Executing task deploy:symlink
✔ Executing task cleanup
Successfully deployed!
Nota
Como ves, Deployer te pedirá dos veces por la contraseña para tu servidor Ubuntu. La primera vez para la tarea deploy:prepare y la segunda vez para la tarea upload. Si esto te molesta, la forma más fácil de saltártelo es usar la configuración y las llaves SSH. Puedes leer más acerca de ello en la documentación de Host de Deployer.
Tan pronto como nuestro despliegue finalice con éxito, podemos abrir el navegador web y escribir la URL http://tu-servidor-ip - esto debería mostrar la ruta por defecto de la API Lumen. También podemos utilizar la URL http://TU-servidor-ip/zonasdetiempo, la cual hemos creado antes de forma adicional.
Es más, si nos logueamos al servidor Ubuntu a través de SSH, podemos investigar la estructura del directorio creado por Developer.
/var/www/lumen_api/ ├── current -> releases/2 ├── releases │ ├── 1 │ │ ├── app │ │ ├── artisan │ │ ├── bootstrap │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── composer.phar │ │ ├── database │ │ ├── deploy.php │ │ ├── phpunit.xml │ │ ├── public │ │ ├── README.md │ │ ├── resources │ │ ├── routes │ │ ├── storage -> ../../shared/storage │ │ ├── tests │ │ └── vendor │ └── 2 │ ├── app │ ├── artisan │ ├── bootstrap │ ├── composer.json │ ├── composer.lock │ ├── database │ ├── deploy.php │ ├── phpunit.xml │ ├── public │ ├── README.md │ ├── resources │ ├── routes │ ├── storage -> ../../shared/storage │ ├── tests │ └── vendor └── shared └── storage ├── app ├── framework └── logs
Aquí podemos ver, como hemos mencionado de forma breve anteriormente, que Deployer ha creado el enlace simbólico current, el cual ahora mismo apunta al directorio releases/2.
Cada vez que ejecutamos dep deploy con éxito, deberíamos ver que el enlace simbólico current se redirige a sí mismo al último directorio lanzado.
En caso de que tengas algún tema de código después del despliegue, puedes usar el comando dep rollback, que le da instrucciones a Deployer para redigir de forma automática el enlace simbólico current al lanzamiento previo.
Conclusión
- Hemos arrancado un proyecto API Lumen simple juntos.
- Además de eso, hemos instalado y configurado Deployer, una herramienta PHP muy práctica, que nos ha ayudado con el despliegue.
- También hemos mostrado cómo configurar un servidor Ubuntu simple.
Si quieres, no tienes porqué dejarlo aquí. Puedes configurar toda una granja de servidores y comprobar cómo Deployer puede ayudarte a implementar tu código en todos ellos a la vez.
¿No es bueno tener finalmente una herramienta de despliegue que se ajuste al ecosistema PHP, similar a Ruby y su Capistrano? ¡Deja un comentario!