Comment configurer une application évolutive Laravel 6 à l’aide de bases de données gérées et d’un stockage d’objets

introduction

Lors de la mise à l'échelle d'applications Web horizontales, les premières difficultés que vous rencontrerez généralement concernent le stockage de fichiers et la persistance des données. Cela est principalement dû au fait qu'il est difficile de maintenir la cohérence des données variables entre plusieurs nœuds d'application. des stratégies appropriées doivent être mises en place pour garantir que les données créées dans un nœud sont immédiatement disponibles pour les autres nœuds d'un cluster.

Un moyen pratique de résoudre le problème de cohérence consiste à utiliser les systèmesmanaged databases etobject storage. Le premier externalisera la persistance des données vers une base de données gérée et le second fournira un service de stockage à distance dans lequel vous pourrez conserver des fichiers statiques et du contenu variable, tel que des images téléchargées par les utilisateurs. Chaque nœud peut ensuite se connecter à ces services au niveau de l'application.

Le diagramme suivant montre comment une telle configuration peut être utilisée pour une évolutivité horizontale dans le contexte d'applications PHP:

Laravel at scale diagram

Dans ce guide, nous mettrons à jour une application Laravel 6 existante pour la préparer à l'évolutivité horizontale en la connectant à une base de données MySQL gérée et en configurant un magasin d'objets compatible S3 pour enregistrer les fichiers générés par l'utilisateur. À la fin, vous aurez une application de liste de voyage s'exécutant sur un serveur Web Nginx + PHP-FPM:

Travellist v1.0

[.note] #Note: ce guide utiliseDigitalOcean Managed MySQL etSpaces pour démontrer une configuration d'application évolutive utilisant des bases de données gérées et un stockage d'objets. Les instructions contenues ici devraient fonctionner de la même manière pour les autres fournisseurs de services.
#

Conditions préalables

Pour commencer ce didacticiel, vous devez d'abord remplir les conditions préalables suivantes:

  • Accès à un serveur Ubuntu 18.04 en tant qu'utilisateur non root avec des privilèges sudo et avec un pare-feu actif installé sur votre serveur. Pour les configurer, veuillez vous référer à nosInitial Server Setup Guide for Ubuntu 18.04.

  • Nginx et PHP-FPM installés et configurés sur votre serveur, comme expliqué aux étapes1 et3 deHow to Install LEMP on Ubuntu 18.04. Vous devez ignorer l'étape d'installation de MySQL.

  • Composer installé sur votre serveur, comme expliqué aux étapes1 et2 deHow to Install and Use Composer on Ubuntu 18.04.

  • Informations d'identification de l'administrateur sur une base de données MySQL 8 gérée. Pour ce guide, nous utiliserons un clusterDigitalOcean Managed MySQL, mais les instructions ici devraient fonctionner de la même manière pour les autres services de base de données gérés.

  • Ensemble de clés d'API avec des autorisations de lecture et d'écriture sur un service de stockage d'objets compatible S3. Dans ce guide, nous utiliseronsDigitalOcean Spaces, mais vous êtes libre d'utiliser un fournisseur de votre choix.

  • L'outils3cmd installé et configuré pour se connecter à votre lecteur de stockage objet. Pour savoir comment configurer cela pour les espaces DigitalOcean, veuillez consulter nosproduct documentation.

[[step-1 -—- Installing-the-mysql-8-client]] == Étape 1 - Installation du client MySQL 8

Les référentiels par défaut Ubuntu apt sont fournis avec le client MySQL 5, qui n’est pas compatible avec le serveur MySQL 8 que nous utiliserons dans ce guide. Pour installer le client MySQL compatible, nous devons utiliser le référentiel MySQL APT fourni par Oracle.

Commencez par naviguer vers lesMySQL APT Repository page dans votre navigateur Web. Trouvez le boutonDownload dans le coin inférieur droit et cliquez sur la page suivante. Cette page vous invitera à vous connecter ou à vous inscrire pour un compte Web Oracle. Vous pouvez ignorer cela et rechercher à la place le lien qui ditNo thanks, just start my download. Copiez l'adresse du lien et revenez à la fenêtre de votre terminal.

Ce lien doit pointer vers un package.deb qui installera le référentiel MySQL APT sur votre serveur. Après l'avoir installé, vous pourrez utiliserapt pour installer les dernières versions de MySQL. Nous utiliseronscurl pour télécharger ce fichier dans un emplacement temporaire.

Accédez au dossiertmp de votre serveur:

cd /tmp

Maintenant, téléchargez le package aveccurl et en utilisant l'URL que vous avez copiée depuis la page MySQL APT Repository:

curl -OL https://dev.mysql.com/get/mysql-apt-config_0.8.13-1_all.deb

Une fois le téléchargement terminé, vous pouvez utiliserdpkg pour installer le package:

sudo dpkg -i mysql-apt-config_0.8.13-1_all.deb

Un écran apparaîtra dans lequel vous pourrez choisir quelle version de MySQL vous souhaitez sélectionner par défaut, ainsi que les composants MySQL qui vous intéressent:

MySQL APT Repository Install

Vous n’avez rien à changer ici, car les options par défaut installeront les référentiels dont nous avons besoin. Sélectionnez «Ok» et la configuration sera terminée.

Ensuite, vous devrez mettre à jour le cache de votreapt avec:

sudo apt update

Nous pouvons enfin installer le client MySQL 8 avec:

sudo apt install mysql-client

Une fois cette commande terminée, vérifiez le numéro de version du logiciel pour vous assurer que vous disposez de la dernière version:

mysql --version

Vous verrez la sortie comme ceci:

Outputmysql  Ver 8.0.18 for Linux on x86_64 (MySQL Community Server - GPL)

Dans l’étape suivante, nous utiliserons le client MySQL pour vous connecter à votre serveur MySQL géré et préparer la base de données pour l’application.

[[step-2 -—- creation-a-new-mysql-user-and-database]] == Étape 2 - Création d'un nouvel utilisateur et d'une nouvelle base de données MySQL

Au moment d'écrire ces lignes, la bibliothèque native MySQL PHPmysqlnddoesn’t supportcaching_sha2_authentication, la méthode d'authentification par défaut pour MySQL 8. Nous devrons créer un nouvel utilisateur avec la méthode d'authentificationmysql_native_password afin de pouvoir connecter notre application Laravel au serveur MySQL 8. Nous allons également créer une base de données dédiée pour notre application de démonstration.

Pour commencer, connectez-vous à votre serveur en utilisant un compte administrateur. Remplacez les valeurs en surbrillance par vos propres utilisateur, hôte et port MySQL:

mysql -u MYSQL_USER -p -h MYSQL_HOST -P MYSQL_PORT

Lorsque vous y êtes invité, indiquez le mot de passe de l'utilisateur admin. Une fois connecté, vous aurez accès à l'interface de ligne de commande du serveur MySQL 8.

Tout d'abord, nous allons créer une nouvelle base de données pour l'application. Exécutez la commande suivante pour créer une nouvelle base de données nomméetravellist:

CREATE DATABASE travellist;

Ensuite, nous allons créer un nouvel utilisateur et définir un mot de passe, en utilisantmysql_native_password comme méthode d'authentification par défaut pour cet utilisateur. Nous vous encourageons à remplacer les valeurs en surbrillance par vos propres valeurs et à utiliser un mot de passe fort:

CREATE USER 'travellist-user'@'%' IDENTIFIED WITH mysql_native_password BY 'MYSQL_PASSWORD';

Nous devons maintenant donner à cet utilisateur l'autorisation sur notre base de données d'application:

GRANT ALL ON travellist.* TO 'travellist-user'@'%';

Vous pouvez maintenant quitter l'invite MySQL avec:

exit;

Vous disposez maintenant d'une base de données dédiée et d'un utilisateur compatible pour vous connecter à partir de votre application Laravel. Dans l'étape suivante, nous obtiendrons le code de l'application et configurerons les détails de la configuration afin que votre application puisse se connecter à votre base de données MySQL gérée.

[.note] #Dans ce guide, nous utiliseronsLaravel Migrations etdatabase seeds pour configurer nos tables d'application. Si vous avez besoin de migrer une base de données locale existante vers une base de données MySQL gérée par DigitalOcean, veuillez consulter notre documentation surHow to Import MySQL Databases into DigitalOcean Managed Databases.
#

[[step-3 -—- setting-up-the-demo-application]] == Étape 3 - Configuration de l'application de démonstration

Pour commencer, nous allons récupérer l'application de démonstration Laravel à partir de sesGithub repository. N'hésitez pas à inspecter le contenu de l'application avant d'exécuter les commandes suivantes.

L'application de démonstration est une application de liste de voyages qui a été initialement développée dans notre guide surHow to Install and Configure Laravel with LEMP on Ubuntu 18.04. L'application mise à jour contient désormais des améliorations visuelles, notamment des photos de voyage pouvant être téléchargées par un visiteur et une carte du monde. Il introduit également un script de migration de base de données et des bases de données pour créer les tables d'application et les remplir avec des exemples de données, à l'aide des commandesartisan.

Pour obtenir le code d'application compatible avec ce didacticiel, nous allons télécharger les1.1 release depuis le référentiel du projet sur Github. Nous enregistrerons le fichier zip téléchargé sous le nomtravellist.zip dans notre répertoire personnel:

cd ~
curl -L https://github.com/do-community/travellist-laravel-demo/archive/1.1.zip -o travellist.zip

Maintenant, décompressez le contenu de l'application et renommez son répertoire avec:

unzip travellist.zip
mv travellist-laravel-demo-1.1 travellist

Accédez au répertoiretravellist:

cd travellist

Avant de continuer, nous devrons installer quelques modules PHP requis par le framework Laravel, à savoir:php-xml,php-mbstring,php-xml etphp-bcmath. Pour installer ces packages, exécutez:

sudo apt install unzip php-xml php-mbstring php-xml php-bcmath

Pour installer les dépendances d'application, exécutez:

composer install

Vous verrez une sortie semblable à celle-ci:

OutputLoading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 80 installs, 0 updates, 0 removals
  - Installing doctrine/inflector (v1.3.0): Downloading (100%)
  - Installing doctrine/lexer (1.1.0): Downloading (100%)
  - Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%)
  - Installing erusev/parsedown (1.7.3): Downloading (100%)

...

Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.

Les dépendances de l'application sont maintenant installées. Ensuite, nous allons configurer l’application pour qu’elle se connecte à la base de données MySQL gérée.

Création du fichier de configuration de.env et définition de la clé d'application

Nous allons maintenant créer un fichier.env contenant des variables qui seront utilisées pour configurer l'application Laravel dans une base par environnement. L'application comprend un exemple de fichier que nous pouvons copier, puis modifier ses valeurs pour refléter les paramètres de notre environnement.

Copiez le fichier.env.example dans un nouveau fichier nommé.env:

cp .env.example .env

Nous devons maintenant définir la clé d'application. Cette clé est utilisée pour chiffrer les données de session et doit être définie sur une chaîne unique de 32 caractères. Nous pouvons générer cette clé automatiquement avec l'outilartisan:

php artisan key:generate

Modifions le fichier de configuration de l’environnement pour configurer les détails de la base de données. Ouvrez le fichier.env en utilisant l'éditeur de ligne de commande de votre choix. Ici, nous utiliseronsnano:

nano .env

Recherchez la section des informations d'identification de la base de données. Les variables suivantes nécessitent votre attention:

DB_HOST: votre hôte de serveur MySQL géré.
DB_PORT: votre port de serveur MySQL géré.
DB_DATABASE: le nom de la base de données d'application que nous avons créée dansStep 2.
DB_USERNAME: l'utilisateur de la base de données que nous avons créé dansStep 2.
DB_PASSWORD: le mot de passe de l'utilisateur de la base de données que nous avons défini dansStep 2.

Mettez à jour les valeurs en surbrillance avec vos propres informations et informations d'identification MySQL gérées:

...
DB_CONNECTION=mysql
DB_HOST=MANAGED_MYSQL_HOST
DB_PORT=MANAGED_MYSQL_PORT
DB_DATABASE=MANAGED_MYSQL_DB
DB_USERNAME=MANAGED_MYSQL_USER
DB_PASSWORD=MANAGED_MYSQL_PASSWORD
...

Enregistrez et fermez le fichier en tapantCTRL+X puisY etENTER lorsque vous avez terminé les modifications.

Maintenant que l’application est configurée pour se connecter à la base de données MySQL, nous pouvons utiliser l’outil de ligne de commandeartisan de Laravel pour créer les tables de la base de données et les remplir avec des exemples de données.

Migration et remplissage de la base de données

Nous allons maintenant utiliserLaravel Migrations etdatabase seeds pour configurer les tables d'application. Cela nous aidera à déterminer si notre configuration de base de données fonctionne comme prévu.

Pour exécuter le script de migration qui créera les tables utilisées par l'application, exécutez:

php artisan migrate

Vous verrez une sortie semblable à celle-ci:

OutputMigration table created successfully.
Migrating: 2019_09_19_123737_create_places_table
Migrated:  2019_09_19_123737_create_places_table (0.26 seconds)
Migrating: 2019_10_14_124700_create_photos_table
Migrated:  2019_10_14_124700_create_photos_table (0.42 seconds)

Pour renseigner la base de données avec des exemples de données, exécutez:

php artisan db:seed

Vous verrez la sortie comme ceci:

OutputSeeding: PlacesTableSeeder
Seeded:  PlacesTableSeeder (0.86 seconds)
Database seeding completed successfully.

Les tables d'application sont maintenant créées et remplies avec des exemples de données.

Pour terminer la configuration de l'application, nous devons également créer un lien symbolique vers le dossier de stockage public qui hébergera les photos de voyage que nous utilisons dans l'application. Vous pouvez le faire en utilisant l'outilartisan:

php artisan storage:link
OutputThe [public/storage] directory has been linked.

Cela créera un lien symbolique dans le répertoirepublic pointant versstorage/app/public, où nous enregistrerons les photos de voyage. Pour vérifier que le lien a été créé et où il pointe, vous pouvez exécuter:

ls -la public/

Vous verrez la sortie comme ceci:

Outputtotal 36
drwxrwxr-x  5 sammy sammy 4096 Oct 25 14:59 .
drwxrwxr-x 12 sammy sammy 4096 Oct 25 14:58 ..
-rw-rw-r--  1 sammy sammy  593 Oct 25 06:29 .htaccess
drwxrwxr-x  2 sammy sammy 4096 Oct 25 06:29 css
-rw-rw-r--  1 sammy sammy    0 Oct 25 06:29 favicon.ico
drwxrwxr-x  2 sammy sammy 4096 Oct 25 06:29 img
-rw-rw-r--  1 sammy sammy 1823 Oct 25 06:29 index.php
drwxrwxr-x  2 sammy sammy 4096 Oct 25 06:29 js
-rw-rw-r--  1 sammy sammy   24 Oct 25 06:29 robots.txt
lrwxrwxrwx  1 sammy sammy   41 Oct 25 14:59 storage -> /home/sammy/travellist/storage/app/public
-rw-rw-r--  1 sammy sammy 1194 Oct 25 06:29 web.config

Exécution du serveur de test (facultatif)

Vous pouvez utiliser la commandeartisan serve pour vérifier rapidement que tout est correctement configuré dans l'application, avant d'avoir à configurer un serveur Web complet comme Nginx pour servir l'application à long terme.

Nous utiliserons le port8000 pour servir temporairement l'application à des fins de test. Si le pare-feu UFW est activé sur votre serveur, vous devez d'abord autoriser l'accès à ce port avec:

sudo ufw allow 8000

Maintenant, pour exécuter le serveur PHP intégré que Laravel expose via l'outilartisan, exécutez:

php artisan serve --host=0.0.0.0 --port=8000

Cette commande bloquera votre terminal jusqu'à ce qu'elle soit interrompue par unCTRL+C. Il utilisera le serveur Web PHP intégré pour servir l'application à des fins de test sur toutes les interfaces réseau, en utilisant le port8000.

Accédez à présent à votre navigateur et accédez à l’application en utilisant le nom de domaine ou l’adresse IP du serveur sur le port8000:

http://server_domain_or_IP:8000

Vous verrez la page suivante:

Travellist v1.0

Si cette page s'affiche, cela signifie que l'application extrait correctement les données sur les emplacements et les photos de la base de données gérée configurée. Les fichiers d’image sont toujours stockés sur le disque local, mais nous allons changer cela dans une étape suivante de ce guide.

Lorsque vous avez terminé de tester l'application, vous pouvez arrêter la commandeserve en appuyant surCTRL+C.

N'oubliez pas de fermer à nouveau le port8000 si vous exécutez UFW sur votre serveur:

sudo ufw deny 8000

[[step-4 -—- configuring-nginx-to-serve-the-application]] == Étape 4 - Configuration de Nginx pour servir l'application

Bien que le serveur Web PHP intégré soit très utile pour le développement et les tests, il n'est pas destiné à être utilisé comme solution à long terme pour servir les applications PHP. Il est recommandé d’utiliser un serveur Web complet tel que Nginx.

Pour commencer, nous allons déplacer le dossier de l'application vers/var/www, qui est l'emplacement habituel des applications Web exécutées sur Nginx. Tout d'abord, utilisez la commandemv pour déplacer le dossier de l'application avec tout son contenu vers/var/www/travellist:

sudo mv ~/travellist /var/www/travellist

Nous devons maintenant donner à l'utilisateur du serveur Web un accès en écriture aux dossiersstorage etbootstrap/cache, où Laravel stocke les fichiers générés par l'application. Nous définirons ces autorisations à l'aide desetfacl, un utilitaire de ligne de commande qui permet des paramètres d'autorisation plus robustes et plus précis dans les fichiers et les dossiers.

Pour inclure les autorisations de lecture, d'écriture et d'exécution (rwx) de l'utilisateur du serveur Web sur les répertoires requis, exécutez:

sudo setfacl -R -m g:www-data:rwx /var/www/travellist/storage
sudo setfacl -R -m g:www-data:rwx /var/www/travellist/bootstrap/cache

Les fichiers de l’application sont maintenant en ordre, mais nous devons toujours configurer Nginx pour servir le contenu. Pour ce faire, nous allons créer un nouveau fichier de configuration d'hôte virtuel à/etc/nginx/sites-available:

sudo nano /etc/nginx/sites-available/travellist

Le fichier de configuration suivant contient les paramètresrecommended pour les applications Laravel sur Nginx:

/etc/nginx/sites-available/travellist

server {
    listen 80;
    server_name server_domain_or_IP;
    root /var/www/travellist/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Copiez ce contenu dans votre fichier/etc/nginx/sites-available/travellist et ajustez les valeurs en surbrillance pour qu'elles correspondent à votre propre configuration. Enregistrez et fermez le fichier une fois l’édition terminée.

Pour activer le nouveau fichier de configuration d'hôte virtuel, créez un lien symbolique verstravellist danssites-enabled:

sudo ln -s /etc/nginx/sites-available/travellist /etc/nginx/sites-enabled/

[.note] #Note: Si vous avez un autre fichier d'hôte virtuel qui a été précédemment configuré pour les mêmesserver_name que ceux utilisés dans l'hôte virtueltravellist, vous devrez peut-être désactiver l'ancienne configuration en suppression du lien symbolique correspondant à l'intérieur de/etc/nginx/sites-enabled/.
#

Pour vérifier que la configuration ne contient aucune erreur de syntaxe, vous pouvez utiliser:

sudo nginx -t

Vous devriez voir la sortie comme ceci:

Outputnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Pour appliquer les modifications, rechargez Nginx avec:

sudo systemctl reload nginx

Si vous rechargez votre navigateur maintenant, les images de l'application seront brisées. Cela est dû au fait que nous avons déplacé le répertoire de l'application vers un nouvel emplacement sur le serveur. C'est pourquoi nous devons recréer le lien symbolique dans le dossier de stockage de l'application.

Supprimer l'ancien lien avec:

cd /var/www/travellist
rm -f public/storage

Maintenant, exécutez à nouveau la commandeartisan pour générer le lien de stockage:

php artisan storage:link

Maintenant, allez dans votre navigateur et accédez à l’application en utilisant le nom de domaine ou l’adresse IP du serveur, comme défini par la directiveserver_name dans votre fichier de configuration:

http://server_domain_or_IP

Travellist v1.0

À l’étape suivante, nous intégrerons un service de stockage d’objets dans l’application. Cela remplacera le stockage sur disque local actuel utilisé pour les photos de voyage.

[[step-5 -—- integration-an-s3-compatible-object-storage-into-the-application]] == Étape 5 - Intégration d'un stockage d'objets compatible S3 dans l'application

Nous allons maintenant configurer l’application de manière à utiliser un service de stockage d’objets compatible S3 pour stocker les photos de voyage exposées sur la page d’index. Étant donné que l'application contient déjà quelques exemples de photos stockées sur le disque local, nous utiliserons également l'outils3cmd pour télécharger les fichiers d'image locaux existants vers le stockage d'objets distant.

Configuration du pilote S3 pour Laravel

Laravel utiliseleague/flysystem, une bibliothèque d'abstraction de système de fichiers qui permet à une application Laravel d'utiliser et de combiner plusieurs solutions de stockage, y compris des services de disque local et de cloud. Un package supplémentaire est requis pour utiliser le pilotes3. Nous pouvons installer ce package en utilisant la commandecomposer require.

Accédez au répertoire de l'application:

cd /var/www/travellist
composer require league/flysystem-aws-s3-v3

Vous verrez une sortie semblable à celle-ci:

OutputUsing version ^1.0 for league/flysystem-aws-s3-v3
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 8 installs, 0 updates, 0 removals
  - Installing mtdowling/jmespath.php (2.4.0): Loading from cache
  - Installing ralouphie/getallheaders (3.0.3): Loading from cache
  - Installing psr/http-message (1.0.1): Loading from cache
  - Installing guzzlehttp/psr7 (1.6.1): Loading from cache
  - Installing guzzlehttp/promises (v1.3.1): Loading from cache
  - Installing guzzlehttp/guzzle (6.4.1): Downloading (100%)
  - Installing aws/aws-sdk-php (3.112.28): Downloading (100%)
  - Installing league/flysystem-aws-s3-v3 (1.0.23): Loading from cache
...

Maintenant que les packages requis sont installés, nous pouvons mettre à jour l'application pour qu'elle se connecte au stockage d'objets. Tout d'abord, nous rouvrirons le fichier.env pour configurer les détails de configuration tels que les clés, le nom du bucket et la région de votre service de stockage d'objets.

Ouvrez le fichier.env:

nano .env

Incluez les variables d'environnement suivantes, en remplaçant les valeurs en surbrillance par les détails de la configuration de votre librairie:

/var/www/travellist/.env

DO_SPACES_KEY=EXAMPLE7UQOTHDTF3GK4
DO_SPACES_SECRET=exampleb8e1ec97b97bff326955375c5
DO_SPACES_ENDPOINT=https://ams3.digitaloceanspaces.com
DO_SPACES_REGION=ams3
DO_SPACES_BUCKET=sammy-travellist

Enregistrez et fermez le fichier lorsque vous avez terminé. Ouvrez maintenant le fichierconfig/filesystems.php:

nano config/filesystems.php

Dans ce fichier, nous allons créer une nouvelle entréedisk dans le tableaudisks. Nous nommerons ce disquespaces, et nous utiliserons les variables d'environnement que nous avons définies dans le fichier.env pour configurer le nouveau disque. Incluez l'entrée suivante dans le tableaudisks:

config/filesystems.php

'spaces' => [
   'driver' => 's3',
   'key' => env('DO_SPACES_KEY'),
   'secret' => env('DO_SPACES_SECRET'),
   'endpoint' => env('DO_SPACES_ENDPOINT'),
   'region' => env('DO_SPACES_REGION'),
   'bucket' => env('DO_SPACES_BUCKET'),
],

Toujours dans le même fichier, recherchez l'entréecloud et modifiez-la pour définir le nouveau disquespaces comme disque du système de fichiers cloud par défaut:

config/filesystems.php

'cloud' => env('FILESYSTEM_CLOUD', 'spaces'),

Enregistrez et fermez le fichier une fois l’édition terminée. Depuis vos contrôleurs, vous pouvez désormais utiliser la méthodeStorage::cloud() comme raccourci pour accéder au disquecloud par défaut. De cette façon, l'application reste flexible pour utiliser plusieurs solutions de stockage et vous pouvez basculer entre les fournisseurs en fonction de l'environnement.

L'application est maintenant configurée pour utiliser le stockage d'objets, mais nous devons toujours mettre à jour le code qui télécharge les nouvelles photos dans l'application.

Examinons d'abord l'itinéraire actueluploadPhoto, situé dans la classePhotoController. Ouvrez le fichier en utilisant votre éditeur de texte:

nano app/Http/Controllers/PhotoController.php

app/Http/Controllers/PhotoController.php

…

public function uploadPhoto(Request $request)
{
   $photo = new Photo();
   $place = Place::find($request->input('place'));

   if (!$place) {
       //add new place
       $place = new Place();
       $place->name = $request->input('place_name');
       $place->lat = $request->input('place_lat');
       $place->lng = $request->input('place_lng');
   }

   $place->visited = 1;
   $place->save();

   $photo->place()->associate($place);
   $photo->image = $request->image->store('/', 'public');
   $photo->save();

   return redirect()->route('Main');
}

Cette méthode accepte une requêtePOST et crée une nouvelle entrée photo dans le tableau des photos. Il commence par vérifier si un lieu existant a été sélectionné dans le formulaire de téléchargement de photos et, dans le cas contraire, il créera un nouveau lieu à l'aide des informations fournies. L'endroit est alors défini survisited et enregistré dans la base de données. Suite à cela, une association est créée pour que la nouvelle photo soit liée au lieu désigné. Le fichier image est ensuite stocké dans le dossier racine du disquepublic. Enfin, la photo est enregistrée dans la base de données. L'utilisateur est ensuite redirigé vers la route principale, à savoir la page d'index de l'application.

La ligne en surbrillance dans ce code est ce qui nous intéresse. Dans cette ligne, le fichier image est enregistré sur le disque en utilisant la méthodestore. La méthodestore est utilisée pour enregistrer des fichiers sur l'un des disques définis dans le fichier de configuration defilesystem.php. Dans ce cas, il utilise le disque par défaut pour stocker les images téléchargées.

Nous allons modifier ce comportement afin que l'image soit enregistrée dans le magasin d'objets au lieu du disque local. Pour ce faire, nous devons remplacer le disquepublic par le disquespaces dans l'appel de la méthodestore. Nous devons également nous assurer que la visibilité du fichier téléchargé est définie surpublic au lieu deprivate.

Le code suivant contient la classePhotoController complète, y compris la méthodeuploadPhoto mise à jour:

app/Http/Controllers/PhotoController.php

 $places
       ]);
   }

   public function uploadPhoto(Request $request)
   {
       $photo = new Photo();
       $place = Place::find($request->input('place'));

       if (!$place) {
           //add new place
           $place = new Place();
           $place->name = $request->input('place_name');
           $place->lat = $request->input('place_lat');
           $place->lng = $request->input('place_lng');
       }

       $place->visited = 1;
       $place->save();

       $photo->place()->associate($place);
       $photo->image = $request->image->store('/', 'spaces');
       Storage::setVisibility($photo->image, 'public');
       $photo->save();

       return redirect()->route('Main');
   }
}

Copiez le code mis à jour dans vos propresPhotoController afin qu'il reflète les modifications mises en évidence. Enregistrez et fermez le fichier une fois l’édition terminée.

Nous devons toujours modifier la vue principale de l’application afin qu’elle utilise l’URL du fichier de stockage d’objet pour restituer l’image. Ouvrez le modèletravel_list.blade.php:

nano resources/views/travel_list.blade.php

Localisez maintenant la sectionfooter de la page, qui ressemble actuellement à ceci:

resources/views/travel_list.blade.php

@section('footer')
   

Travel Photos [ Upload Photo ]

@foreach ($photos as $photo)

{{ $photo->place->name }}

@endforeach @endsection

Remplacez l'attribut de l'image actuellesrc pour utiliser l'URL du fichier du disque de stockagespaces:

Si vous allez maintenant sur votre navigateur et rechargez la page de l'application, il ne montrera que des images brisées. Cela se produit parce que les fichiers image de ces photos de voyage ne sont encore que sur le disque local. Nous devons télécharger les fichiers d’image existants dans le stockage d’objets afin que les photos déjà stockées dans la base de données puissent être exposées avec succès dans la page de l’application.

Synchronisation des images locales avecs3cmd

L'outils3cmd peut être utilisé pour synchroniser des fichiers locaux avec un service de stockage d'objets compatible S3. Nous allons exécuter une commandesync pour télécharger tous les fichiers destorage/app/public/photos vers le service de stockage d'objets.

Accédez au répertoire de stockage de l'applicationpublic:

cd /var/www/travellist/storage/app/public

Pour voir les fichiers déjà stockés sur votre disque distant, vous pouvez utiliser la commandes3cmd ls:

s3cmd ls s3://your_bucket_name

Exécutez maintenant la commandesync pour télécharger les fichiers existants dans le dossier de stockage public vers le stockage d'objets:

s3cmd sync ./ s3://your_bucket_name --acl-public --exclude=.gitignore

Cela synchronisera le dossier actuel (storage/app/public) avec le répertoire racine du stockage d'objets distants. Vous obtiendrez une sortie similaire à celle-ci:

Outputupload: './bermudas.jpg' -> 's3://sammy-travellist/bermudas.jpg'  [1 of 3]
 2538230 of 2538230   100% in    7s   329.12 kB/s  done
upload: './grindavik.jpg' -> 's3://sammy-travellist/grindavik.jpg'  [2 of 3]
 1295260 of 1295260   100% in    5s   230.45 kB/s  done
upload: './japan.jpg' -> 's3://sammy-travellist/japan.jpg'  [3 of 3]
 8940470 of 8940470   100% in   24s   363.61 kB/s  done
Done. Uploaded 12773960 bytes in 37.1 seconds, 336.68 kB/s.

Maintenant, si vous exécutez à nouveaus3cmd ls, vous verrez que trois nouveaux fichiers ont été ajoutés au dossier racine de votre compartiment de stockage d'objets:

s3cmd ls s3://your_bucket_name
Output2019-10-25 11:49   2538230   s3://sammy-travellist/bermudas.jpg
2019-10-25 11:49   1295260   s3://sammy-travellist/grindavik.jpg
2019-10-25 11:49   8940470   s3://sammy-travellist/japan.jpg

Accédez à votre navigateur et rechargez la page de l'application. Toutes les images doivent maintenant être visibles et si vous les inspectez à l'aide des outils de débogage de votre navigateur, vous remarquerez qu'elles utilisent toutes des URL à partir de votre stockage d'objets.

Test de l'intégration

L’application de démonstration est désormais entièrement fonctionnelle, stockant des fichiers dans un service de stockage d’objets distant et enregistrant des données dans une base de données MySQL gérée. Nous pouvons maintenant télécharger quelques photos pour tester notre configuration.

Accédez à la route de l'application/upload depuis votre navigateur:

http://server_domain_or_IP/upload

Vous verrez le formulaire suivant:

Travellist Photo Upload Form

Vous pouvez maintenant télécharger quelques photos pour tester l'intégration du stockage d'objets. Après avoir choisi une image sur votre ordinateur, vous pouvez sélectionner un lieu existant dans le menu déroulant, ou vous pouvez ajouter un nouveau lieu en fournissant son nom etgeographic coordinates afin qu'il puisse être chargé dans la carte de l'application.

[[step-6 -—- scaling-up-a-digitalocean-managed-mysql-database-with-read-only-nodes-optional]] == Étape 6 - Mise à l'échelle d'une base de données MySQL gérée par DigitalOcean avec des nœuds en lecture seule (Optionnel)

Les opérations en lecture seule étant généralement plus fréquentes que les opérations d'écriture sur des serveurs de base de données, il est courant de mettre à l'échelle un cluster de bases de données en configurant plusieurs noeuds en lecture seule. Cela distribuera la charge générée par les opérationsSELECT.

Pour illustrer cette configuration, nous allons d’abord ajouter 2 nœuds en lecture seule à notre cluster DigitalOcean Managed MySQL. Ensuite, nous allons configurer l’application Laravel pour utiliser ces nœuds.

Accédez auxDigitalOcean Cloud Panel et suivez ces instructions:

  1. Accédez àDatabases et sélectionnez votre cluster MySQL.

  2. Cliquez surActions et choisissezAdd a read-only node dans le menu déroulant.

  3. Configurez les options de nœud et cliquez sur le boutonCreate. Notez que le nouveau nœud peut prendre plusieurs minutes pour être prêt.

  4. Répétez les étapes 1 à 4 une fois de plus pour obtenir 2 nœuds en lecture seule.

  5. Notez les hôtes des deux nœuds, car nous en aurons besoin pour notre configuration Laravel.

Une fois que vos nœuds en lecture seule sont prêts, retournez à votre terminal.

Nous allons maintenant configurer notre application Laravel pour qu’elle fonctionne avec plusieurs nœuds de base de données. Lorsque nous aurons terminé, les requêtes telles queINSERT etUPDATE seront transférées vers votre nœud de cluster principal, tandis que toutes les requêtesSELECT seront redirigées vers vos nœuds en lecture seule.

Tout d'abord, allez dans le répertoire de l'application sur le serveur et ouvrez votre fichier.env à l'aide de l'éditeur de texte de votre choix:

cd /var/www/travellist
nano .env

Localisez la configuration de la base de données MySQL et commentez la ligneDB_HOST:

/var/www/travellist/.env

DB_CONNECTION=mysql
#DB_HOST=MANAGED_MYSQL_HOST
DB_PORT=MANAGED_MYSQL_PORT
DB_DATABASE=MANAGED_MYSQL_DB
DB_USERNAME=MANAGED_MYSQL_USER
DB_PASSWORD=MANAGED_MYSQL_PASSWORD

Enregistrez et fermez le fichier lorsque vous avez terminé. Ouvrez maintenant lesconfig/database.php dans votre éditeur de texte:

nano config/database.php

Recherchez l'entréemysql dans le tableauconnections. Vous devez inclure les nouveaux éléments dethree dans ce tableau de configuration:read,write etsticky. Les entréesread etwrite configureront les nœuds du cluster, et l'optionsticky définie surtrue réutilisera les connexionswrite afin que les données écrites dans la base de données est immédiatement disponible dans le même cycle de demande. Vous pouvez le définir surfalse si vous ne souhaitez pas ce comportement.

/var/www/travel_list/config/database.php

...
      'mysql' => [
         'read' => [
           'host' => [
              'READONLY_NODE1_HOST',
              'READONLY_NODE2_HOST',
           ],
         ],
         'write' => [
           'host' => [
             'MANAGED_MYSQL_HOST',
           ],
         ],
       'sticky' => true,
...

Enregistrez et fermez le fichier une fois l’édition terminée. Pour tester que tout fonctionne comme prévu, nous pouvons créer une route temporaire à l'intérieur deroutes/web.php pour extraire des données de la base de données et afficher des détails sur la connexion utilisée. De cette façon, nous pourrons voir comment les charges sont équilibrées entre les nœuds en lecture seule.

Ouvrez le fichierroutes/web.php:

nano routes/web.php

Inclure l'itinéraire suivant:

/var/www/travel_list/routes/web.php

...

Route::get('/mysql-test', function () {
  $places = App\Place::all();
  $results = DB::select( DB::raw("SHOW VARIABLES LIKE 'server_id'") );

  return "Server ID: " . $results[0]->Value;
});

Maintenant, allez dans votre navigateur et accédez à la route de l'application/mysql-test:

http://server_domain_or_IP/mysql-test

Vous verrez une page comme celle-ci:

mysql node test page

Rechargez la page plusieurs fois et vous remarquerez que la valeur deServer ID change, indiquant que les requêtes sont distribuées aléatoirement entre les deux nœuds en lecture seule.

Conclusion

Dans ce guide, nous avons préparé une application Laravel 6 pour un environnement hautement disponible et évolutif. Nous avons sous-traité le système de base de données à un service MySQL géré externe et avons intégré un service de stockage d'objets compatible S3 dans l'application pour stocker les fichiers téléchargés par les utilisateurs. Enfin, nous avons vu comment mettre à niveau la base de données de l’application en incluant des nœuds de cluster en lecture seule supplémentaires dans le fichier de configuration de l’application.

Le code de l'application de démonstration mis à jour contenant toutes les modifications apportées dans ce guide se trouve dans les2.1 tag du référentiel de l'application sur Github.

À partir de là, vous pouvez configurer unLoad Balancer pour répartir la charge et faire évoluer votre application entre plusieurs nœuds. Vous pouvez également tirer parti de cette configuration pour créer uncontainerized environment pour exécuter votre application sur Docker.

Related