前書き

Webアプリケーションを水平方向にスケーリングする場合、通常直面する最初の問題は、ファイルストレージとデータの永続性に対処することです。 これは主に、複数のアプリケーションノード間で変数データの一貫性を維持するのが難しいという事実によるものです。 1つのノードで作成されたデータをクラスター内の他のノードですぐに使用できるようにするために、適切な戦略を実施する必要があります。

一貫性の問題を解決する実用的な方法は、https://www.digitalocean.com/community/tutorials/understanding-managed-databases [管理対象データベース]およびhttps://www.digitalocean.com/community/tutorials/objectを使用することです。 -storage-vs-block-storage-services [オブジェクトストレージ]システム。 前者はデータの永続性を管理されたデータベースにアウトソースし、後者はユーザーがアップロードした画像などの静的ファイルと可変コンテンツを保持できるリモートストレージサービスを提供します。 各ノードは、アプリケーションレベルでこれらのサービスに接続できます。

次の図は、このようなセットアップを使用して、PHPアプリケーションのコンテキストで水平スケーラビリティを実現する方法を示しています。

画像:https://assets.digitalocean.com/articles/laravel_at_scale/scaling_laravel_final.png [縮尺図のLaravel]

このガイドでは、既存のLaravel 6アプリケーションを更新して、管理されたMySQLデータベースに接続し、S3互換オブジェクトストアを設定してユーザー生成ファイルを保存することにより、水平スケーラビリティに対応します。 最後に、Nginx + PHP-FPM Webサーバーで実行される旅行リストアプリケーションが作成されます。

画像:https://assets.digitalocean.com/articles/laravel_at_scale/travellist_version1-0.png [旅行リストv1.0]

前提条件

このチュートリアルを開始するには、最初に次の前提条件が必要です。

  • sudo特権を持つ非rootユーザーとしてUbuntu 18.04サーバーにアクセスし、サーバーにアクティブなファイアウォールをインストールします。 これらを設定するには、https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-18-04 [Ubuntu 18.04の初期サーバーセットアップガイド]を参照してください。

  • https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-のステップ* 1 および 3 *で説明されているように、サーバーにインストールおよび構成されたNginxおよびPHP-FPM php-lemp-stack-ubuntu-18-04 [Ubuntu 18.04にLEMPをインストールする方法]。 MySQLがインストールされているステップをスキップする必要があります。

  • Composerはサーバーにインストールされています。これについては、https://www.digitalocean.com/community/tutorials/how-to-install-and-のステップ* 1 および 2 *で説明されています。 use-composer-on-ubuntu-18-04 [Ubuntu 18.04にComposerをインストールして使用する方法]。

  • 管理されたMySQL 8データベースの管理者資格情報。 このガイドでは、https://www.digitalocean.com/docs/databases/mysql/quickstart/#create-mysql-database-clusters [DigitalOcean Managed MySQL]クラスターを使用しますが、ここの手順は同様に機能するはずです他のマネージドデータベースサービス用。

  • S3互換オブジェクトストレージサービスに対する読み取りおよび書き込み権限を持つAPIキーのセット。 このガイドでは、https://www.digitalocean.com/docs/spaces/ [DigitalOcean Spaces]を使用しますが、任意のプロバイダーを自由に使用できます。

  • オブジェクトストレージドライブに接続するようにインストールおよび設定された `+ s3cmd +`ツール。 DigitalOcean Spacesでこれを設定する方法については、https://www.digitalocean.com/docs/spaces/resources/s3cmd/ [製品ドキュメント]を参照してください。

ステップ1-MySQL 8クライアントのインストール

デフォルトのUbuntu aptリポジトリにはMySQL 5クライアントが付属しています。これは、このガイドで使用するMySQL 8サーバーと互換性がありません。 互換性のあるMySQLクライアントをインストールするには、Oracleが提供するMySQL APTリポジトリを使用する必要があります。

Webブラウザでhttps://dev.mysql.com/downloads/repo/apt/[MySQL APTリポジトリページ]に移動することから始めます。 右下隅の[ダウンロード]ボタンを見つけ、クリックして次のページに進みます。 このページでは、ログインするか、Oracle Webアカウントにサインアップするよう求められます。 それをスキップして、代わりに「いいえ、ダウンロードを開始してください」というリンクを探してください。 リンクアドレスをコピーして、ターミナルウィンドウに戻ります。

このリンクは、サーバーにMySQL APTリポジトリをセットアップする `+ .deb `パッケージを指している必要があります。 インストール後、 ` apt `を使用してMySQLの最新リリースをインストールできます。 このファイルを一時的な場所にダウンロードするには、 ` curl +`を使用します。

サーバーの `+ tmp`フォルダーに移動します。

cd /tmp

次に、 `+ curl +`でパッケージをダウンロードし、MySQL APTリポジトリページからコピーしたURLを使用します。

curl -OL

ダウンロードが完了したら、 `+ dpkg +`を使用してパッケージをインストールできます。

sudo dpkg -i

どのMySQLバージョンをデフォルトとして選択するか、どのMySQLコンポーネントに関心があるかを選択できる画面が表示されます。

image:https://assets.digitalocean.com/articles/pma_managed_db/dpkg_mysql_apt_config_alt2.png [MySQL APT Repository Install]

デフォルトのオプションでは必要なリポジトリがインストールされるため、ここで何も変更する必要はありません。 「OK」を選択すると、構成が完了します。

次に、 `+ apt`キャッシュを更新する必要があります:

sudo apt update

これで、最終的にMySQL 8クライアントをインストールできます。

sudo apt install mysql-client

そのコマンドが終了したら、ソフトウェアのバージョン番号をチェックして、最新のリリースがあることを確認します。

mysql --version

次のような出力が表示されます。

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

次のステップでは、MySQLクライアントを使用して管理対象MySQLサーバーに接続し、アプリケーション用のデータベースを準備します。

ステップ2-新しいMySQLユーザーとデータベースの作成

この記事の執筆時点では、ネイティブMySQL PHPライブラリ + mysqlnd + https://www.php.net/manual/en/ref.pdo-mysql.php [サポートしていません] + caching_sha2_authentication +、デフォルトMySQL 8の認証方法。 LaravelアプリケーションをMySQL 8サーバーに接続できるようにするには、 `+ mysql_native_password +`認証方法で新しいユーザーを作成する必要があります。 また、デモアプリケーション専用のデータベースを作成します。

開始するには、管理者アカウントを使用してサーバーにログインします。 強調表示された値を独自のMySQLユーザー、ホスト、およびポートに置き換えます。

mysql -u  -p -h  -P

プロンプトが表示されたら、管理ユーザーのパスワードを入力します。 ログインすると、MySQL 8サーバーのコマンドラインインターフェイスにアクセスできるようになります。

最初に、アプリケーション用の新しいデータベースを作成します。 次のコマンドを実行して、「++」という名前の新しいデータベースを作成します。

CREATE DATABASE ;

次に、このユーザーのデフォルトの認証方法として「+ mysql_native_password +」を使用して、新しいユーザーを作成し、パスワードを設定します。 強調表示された値を独自の値に置き換え、強力なパスワードを使用することをお勧めします。

CREATE USER ''@'%' IDENTIFIED WITH mysql_native_password BY '';

次に、このユーザーにアプリケーションデータベースに対するアクセス許可を与える必要があります。

GRANT ALL ON .* TO ''@'%';

これで、MySQLプロンプトを終了できます。

exit;

これで、Laravelアプリケーションから接続する専用のデータベースと互換性のあるユーザーができました。 次のステップでは、アプリケーションコードを取得して構成の詳細を設定し、アプリが管理されたMySQLデータベースに接続できるようにします。

手順3-デモアプリケーションのセットアップ

まず、https://github.com/do-community/travellist-laravel-demo [Github repository]からデモLaravelアプリケーションを取得します。 次のコマンドを実行する前に、アプリケーションの内容を自由に調べてください。

デモアプリケーションは、https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-laravel-with-lemp-on-ubuntuのガイドで最初に開発された旅行バケットリストアプリです。 -18-04 [Ubuntu 18.04でLEMPを使用してLaravelをインストールおよび構成する方法]。 更新されたアプリには、訪問者がアップロードできる旅行写真や世界地図などの視覚的な改善が含まれています。 また、データベース移行スクリプトとデータベースシードを導入して、アプリケーションテーブルを作成し、 `+ artisan +`コマンドを使用してそれらにサンプルデータを入力します。

このチュートリアルと互換性のあるアプリケーションコードを取得するには、https://github.com/do-community/travellist-laravel-demo/releases/tag/1.1 [+ 1.1 + release]をダウンロードしますGithubのプロジェクトのリポジトリ。 ダウンロードしたzipファイルをホームディレクトリ内に「+ travellist.zip +」として保存します。

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

次に、アプリケーションのコンテンツを解凍し、そのディレクトリの名前を次のように変更します。

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

`+ travellist +`ディレクトリに移動します:

cd travellist

先に進む前に、Laravelフレームワークに必要ないくつかのPHPモジュール、つまり、「+ php-xml 」、「 php-mbstring 」、「 php-xml 」、および「 php-bcmath +」をインストールする必要があります。 `。 これらのパッケージをインストールするには、次を実行します。

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

アプリケーションの依存関係をインストールするには、次を実行します。

composer install

次のような出力が表示されます。

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.

これで、アプリケーションの依存関係がインストールされました。 次に、管理対象MySQLデータベースに接続するようにアプリケーションを構成します。

`+ .env +`設定ファイルを作成し、App Keyを設定する

次に、環境ごとにLaravelアプリケーションを設定するために使用される変数を含む `+ .env +`ファイルを作成します。 アプリケーションには、環境設定を反映するために値をコピーして変更できるサンプルファイルが含まれています。

`+ .env.example `ファイルを ` .env +`という名前の新しいファイルにコピーします。

cp .env.example .env

次に、アプリケーションキーを設定する必要があります。 このキーはセッションデータの暗号化に使用され、一意の32文字の文字列に設定する必要があります。 `+ artisan +`ツールでこのキーを自動的に生成できます:

php artisan key:generate

環境設定ファイルを編集して、データベースの詳細を設定しましょう。 任意のコマンドラインエディターを使用して、 `+ .env `ファイルを開きます。 ここでは、 ` nano +`を使用します。

nano .env

データベース資格情報セクションを探します。 次の変数には注意が必要です。

+ DB_HOST +:管理されたMySQLサーバーホスト。 + + DB_PORT +:管理されているMySQLサーバーのポート。 + + DB_DATABASE +:link:#step-2-%E2%80%94-creating-a-new-mysql-user-and-database [ステップ2]で作成したアプリケーションデータベースの名前。 + + DB_USERNAME +:link:#step-2-%E2%80%94-creating-a-new-mysql-user-and-database [ステップ2]で作成したデータベースユーザー。 + + DB_PASSWORD +:link:#step-2-%E2%80%94-creating-a-new-mysql-user-and-database [ステップ2]で定義したデータベースユーザーのパスワード。

独自の管理されたMySQL情報と資格情報で強調表示された値を更新します。

...
DB_CONNECTION=mysql
DB_HOST=
DB_PORT=
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
...

編集が完了したら、「+ CTRL + X 」、次に「 Y 」、「 ENTER +」と入力して、ファイルを保存して閉じます。

アプリケーションがMySQLデータベースに接続するように設定されたので、Laravelのコマンドラインツール「+ artisan +」を使用してデータベーステーブルを作成し、サンプルデータを入力できます。

データベースの移行とデータ投入

Laravel Migrationsおよびhttps://laravel.com/docs/5.8/seeding[database seeds]を使用して、アプリケーションテーブルをセットアップします。 これは、データベース構成が期待どおりに機能するかどうかを判断するのに役立ちます。

アプリケーションが使用するテーブルを作成する移行スクリプトを実行するには、次を実行します。

php artisan migrate

次のような出力が表示されます。

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)

データベースにサンプルデータを入力するには、次を実行します。

php artisan db:seed

次のような出力が表示されます。

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

これで、アプリケーションテーブルが作成され、サンプルデータが入力されました。

ストレージリンクのセットアップ

アプリケーションのセットアップを完了するには、アプリケーションで使用している旅行写真をホストするパブリックストレージフォルダーへのシンボリックリンクも作成する必要があります。 `+ artisan +`ツールを使用してそれを行うことができます:

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

これにより、「+ public」ディレクトリ内に「+ storage / app / public」を指すシンボリックリンクが作成され、ここに旅行写真が保存されます。 リンクが作成されたことと、それが指す場所を確認するには、次を実行します。

ls -la public/

次のような出力が表示されます。

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

-rw-rw-r--  1 sammy sammy 1194 Oct 25 06:29 web.config

テストサーバーの実行(オプション)

`+ artisan serve +`コマンドを使用して、アプリケーション内ですべてが正しくセットアップされていることをすばやく確認してから、Nginxのようなフル機能のWebサーバーを設定して、長期にわたってアプリケーションを提供できます。

ポート `+ 8000 +`を使用して、テストのためにアプリケーションを一時的に提供します。 サーバーでUFWファイアウォールを有効にしている場合は、最初に以下を使用してこのポートへのアクセスを許可する必要があります。

sudo ufw allow 8000

ここで、Laravelが `+ artisan +`ツールを通じて公開する組み込みのPHPサーバーを実行するには、次を実行します。

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

このコマンドは、 `+ CTRL + C `で中断されるまで端末をブロックします。 ポート ` 8000 +`を使用して、組み込みのPHP Webサーバーを使用して、すべてのネットワークインターフェイスでテスト目的でアプリケーションを提供します。

ブラウザに移動して、ポート `+ 8000 +`でサーバーのドメイン名またはIPアドレスを使用してアプリケーションにアクセスします。

http://:8000

次のページが表示されます。

画像:https://assets.digitalocean.com/articles/laravel_at_scale/travellist_version1-0.png [旅行リストv1.0]

このページが表示された場合、アプリケーションは構成済みの管理されたデータベースから場所と写真に関するデータを正常にプルしています。 画像ファイルは引き続きローカルディスクに保存されますが、このガイドの次のステップでこれを変更します。

アプリケーションのテストが終了したら、 `+ CTRL + C `を押すことで ` serve +`コマンドを停止できます。

サーバーでUFWを実行している場合は、ポート `+ 8000 +`を再度閉じることを忘れないでください。

sudo ufw deny 8000

ステップ4-アプリケーションを提供するためのNginxの構成

組み込みのPHP Webサーバーは、開発およびテストの目的には非常に役立ちますが、PHPアプリケーションを提供する長期的なソリューションとして使用することを意図したものではありません。 Nginxなどのフル機能のWebサーバーを使用することをお勧めします。

はじめに、アプリケーションフォルダーを `+ / var / www `に移動します。これは、Nginxで実行されるWebアプリケーションの通常の場所です。 まず、 ` mv `コマンドを使用して、アプリケーションフォルダーとそのすべてのコンテンツを ` / var / www / travellist +`に移動します。

sudo mv ~/ /var/www/

次に、Webサーバーのユーザーに、Laravelがアプリケーション生成ファイルを保存する「+ storage」および「+ bootstrap / cache」フォルダーへの書き込みアクセス権を付与する必要があります。 これらのアクセス許可は、ファイルとフォルダーのより堅牢できめ細かいアクセス許可設定を可能にするコマンドラインユーティリティ「+ setfacl +」を使用して設定します。

必要なディレクトリに対するWebサーバーユーザーへの読み取り、書き込み、実行(rwx)権限を含めるには、次を実行します。

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

これでアプリケーションファイルが整いましたが、コンテンツを提供するためにNginxを構成する必要があります。 これを行うために、 `+ / etc / nginx / sites-available +`に新しい仮想ホスト設定ファイルを作成します:

sudo nano /etc/nginx/sites-available/

次の構成ファイルには、Nginx上のLaravelアプリケーションのhttps://laravel.com/docs/5.8/deployment#server-configuration [推奨]設定が含まれています。

/ etc / nginx / sites-available / travellist

server {
   listen 80;
   server_name ;
   root /var/www//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;
   }
}

このコンテンツを `+ / etc / nginx / sites-available / +`ファイルにコピーし、強調表示された値を調整して独自の設定に合わせます。 編集が完了したら、ファイルを保存して閉じます。

新しい仮想ホスト設定ファイルを有効にするには、 `+ sites-enabled `で ` travellist +`へのシンボリックリンクを作成します。

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

構成に構文エラーが含まれていないことを確認するには、次を使用できます。

sudo nginx -t

次のような出力が表示されます。

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

変更を適用するには、次を使用してNginxをリロードします。

sudo systemctl reload nginx

今すぐブラウザをリロードすると、アプリケーションイメージが破損します。 これは、アプリケーションディレクトリをサーバー内の新しい場所に移動したために発生します。そのため、アプリケーションストレージフォルダーへのシンボリックリンクを再作成する必要があります。

古いリンクを削除します:

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

ここで、もう一度 `+ artisan +`コマンドを実行して、ストレージリンクを生成します。

php artisan storage:link

ブラウザに移動して、設定ファイルの `+ server_name +`ディレクティブで定義されているサーバーのドメイン名またはIPアドレスを使用してアプリケーションにアクセスします。

http://

画像:https://assets.digitalocean.com/articles/laravel_at_scale/travellist_version1-0.png [旅行リストv1.0]

次のステップでは、オブジェクトストレージサービスをアプリケーションに統合します。 これにより、旅行写真に使用されている現在のローカルディスクストレージが置き換えられます。

ステップ5-S3互換オブジェクトストレージをアプリケーションに統合する

インデックスページに表示されている旅行写真を保存するために、S3互換オブジェクトストレージサービスを使用するようにアプリケーションを設定します。 アプリケーションには既にいくつかのサンプル写真がローカルディスクに保存されているため、https://s3tools.org/s3cmd [+ s3cmd +]ツールを使用して、既存のローカル画像ファイルをリモートオブジェクトストレージにアップロードします。

Laravel用のS3ドライバーのセットアップ

Laravelは、「+ league / flysystem 」を使用します。これは、Laravelアプリケーションがローカルディスクやクラウドサービスを含む複数のストレージソリューションを使用および結合できるようにするファイルシステム抽象化ライブラリです。 ` s3 `ドライバーを使用するには追加のパッケージが必要です。 ` composer require +`コマンドを使用してこのパッケージをインストールできます。

アプリケーションディレクトリにアクセスします。

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

次のような出力が表示されます。

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
...

必要なパッケージがインストールされたので、アプリケーションを更新してオブジェクトストレージに接続できます。 最初に、 `+ .env +`ファイルを再度開いて、オブジェクトストレージサービスのキー、バケット名、リージョンなどの構成の詳細を設定します。

`+ .env +`ファイルを開きます:

nano .env

以下の環境変数を含めて、強調表示された値をオブジェクトストアの構成の詳細に置き換えます。

/var/www/travellist/.env

DO_SPACES_KEY=
DO_SPACES_SECRET=
DO_SPACES_ENDPOINT=
DO_SPACES_REGION=
DO_SPACES_BUCKET=

完了したら、ファイルを保存して閉じます。 次に、 `+ config / filesystems.php +`ファイルを開きます。

nano config/filesystems.php

このファイル内で、 `+ disks `配列に新しい_disk_エントリを作成します。 このディスクに「 spaces 」という名前を付け、「。env 」ファイルで設定した環境変数を使用して新しいディスクを構成します。 次のエントリを ` disks +`配列に含めます:

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'),
],

まだ同じファイル内で、 `+ cloud `エントリを見つけ、それを変更して新しい ` spaces +`ディスクをデフォルトのクラウドファイルシステムディスクとして設定します。

config / filesystems.php

'cloud' => env('FILESYSTEM_CLOUD', ''),
編集が完了したら、ファイルを保存して閉じます。 コントローラから、デフォルトの `+ cloud `ディスクにアクセスするためのショートカットとして ` Storage

cloud()+`メソッドを使用できるようになりました。 このように、アプリケーションは複数のストレージソリューションを使用するために柔軟性を維持し、環境ごとにプロバイダーを切り替えることができます。

アプリケーションはオブジェクトストレージを使用するように設定されましたが、新しい写真をアプリケーションにアップロードするコードを更新する必要があります。

最初に、 `+ PhotoController `クラスにある現在の ` uploadPhoto +`ルートを調べてみましょう。 テキストエディターを使用してファイルを開きます。

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->save();

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

このメソッドは `+ POST`リクエストを受け入れ、photosテーブルに新しい写真エントリを作成します。 まず、写真アップロードフォームで既存の場所が選択されているかどうかを確認し、そうでない場合は、提供された情報を使用して新しい場所を作成します。 場所は「+ visited 」に設定され、データベースに保存されます。 その後、関連付けが作成され、新しい写真が指定された場所にリンクされます。 その後、画像ファイルは ` public +`ディスクのルートフォルダーに保存されます。 最後に、写真がデータベースに保存されます。 次に、ユーザーはアプリケーションのインデックスページであるメインルートにリダイレクトされます。

このコードで強調表示されている行は、私たちが興味を持っているものです。 その行では、画像ファイルは + store +`メソッドを使用してディスクに保存されます。 `+ store`メソッドは、 + filesystem.php`設定ファイルで定義されたディスクのいずれかにファイルを保存するために使用されます。 この場合、アップロードされた画像を保存するためにデフォルトのディスクを使用しています。

この動作を変更して、イメージがローカルディスクではなくオブジェクトストアに保存されるようにします。 そのためには、 + store +`メソッド呼び出しで `+ public`ディスクを + space`ディスクに置き換える必要があります。 また、アップロードしたファイルの可視性が_private_ではなく_public_に設定されていることを確認する必要があります。

次のコードには、更新された `+ uploadPhoto `メソッドを含む完全な ` PhotoController +`クラスが含まれています。

app / Http / Controllers / PhotoController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Photo;
use App\Place;


class PhotoController extends Controller
{
  public function uploadForm()
  {
      $places = Place::all();

      return view('upload_photo', [
          'places' => $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->save();

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

更新されたコードを独自の `+ PhotoController +`にコピーして、強調表示された変更を反映させます。 編集が完了したら、ファイルを保存して閉じます。

アプリケーションのメインビューを変更して、オブジェクトストレージファイルのURLを使用して画像をレンダリングする必要があります。 `+ travel_list.blade.php +`テンプレートを開きます:

nano resources/views/travel_list.blade.php

ページの `+ footer +`セクションを見つけます。現在は次のようになっています。

resources / views / travel_list.blade.php

@section('footer')
  <h2>Travel Photos <small>[ <a href="{{ route('Upload.form') }}">Upload Photo</a> ]</small></h2>
  @foreach ($photos as $photo)
      <div class="photo">
         <img src="" />
          <p>{{ $photo->place->name }}</p>
      </div>
  @endforeach

@endsection

現在の画像の `+ src `属性を置き換えて、 ` spaces +`ストレージディスクのファイルURLを使用します。

<img src="" />

ブラウザにアクセスしてアプリケーションページをリロードすると、壊れた画像のみが表示されます。 これは、それらの旅行写真の画像ファイルがまだローカルディスクにあるためです。 既存の画像ファイルをオブジェクトストレージにアップロードして、データベースに既に保存されている写真をアプリケーションページに表示できるようにする必要があります。

ローカル画像を `+ s3cmd +`と同期する

`+ s3cmd `ツールを使用して、ローカルファイルをS3互換オブジェクトストレージサービスと同期できます。 ` sync `コマンドを実行して、 ` storage / app / public / photos +`内のすべてのファイルをオブジェクトストレージサービスにアップロードします。

`+ public +`アプリストレージディレクトリにアクセスします。

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

リモートディスクに既に保存されているファイルを見るには、 `+ s3cmd ls +`コマンドを使用できます:

s3cmd ls s3://

次に、 `+ sync +`コマンドを実行して、パブリックストレージフォルダー内の既存のファイルをオブジェクトストレージにアップロードします。

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

これにより、現在のフォルダー( + storage / app / public)がリモートオブジェクトストレージのルートディレクトリと同期されます。 次のような出力が得られます。

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.

これで、 `+ s3cmd ls +`を再度実行すると、オブジェクトストレージバケットのルートフォルダーに3つの新しいファイルが追加されたことがわかります。

s3cmd ls s3://
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

ブラウザに移動して、アプリケーションページをリロードします。 これですべての画像が表示されるはずです。ブラウザデバッグツールを使用してそれらを検査すると、オブジェクトストレージのURLを使用していることがわかります。

統合のテスト

デモアプリケーションは完全に機能し、リモートオブジェクトストレージサービスにファイルを保存し、管理されたMySQLデータベースにデータを保存します。 これで、いくつかの写真をアップロードして設定をテストできます。

ブラウザから `+ / upload +`アプリケーションルートにアクセスします。

http:///upload

次のフォームが表示されます。

image:https://assets.digitalocean.com/articles/laravel_at_scale/upload_form_v1.png [旅行者写真アップロードフォーム]

これで、数枚の写真をアップロードして、オブジェクトストレージの統合をテストできます。 コンピューターから画像を選択した後、ドロップダウンメニューから既存の場所を選択するか、名前とhttps://www.latlong.net/ [地理座標]を指定して読み込んで新しい場所を追加できます。アプリケーションマップで。

ステップ6-読み取り専用ノードを使用したDigitalOcean管理MySQLデータベースのスケールアップ(オプション)

通常、読み取り専用操作はデータベースサーバーでの書き込み操作よりも頻繁に行われるため、複数の読み取り専用ノードをセットアップしてデータベースクラスターをスケールアップするのが一般的です。 これにより、「+ SELECT +」操作によって生成される負荷が分散されます。

このセットアップを示すために、まず2つの読み取り専用ノードをDigitalOcean Managed MySQLクラスターに追加します。 次に、これらのノードを使用するようにLaravelアプリケーションを構成します。

https://cloud.digitalocean.com [DigitalOcean Cloud Panel]にアクセスし、次の指示に従います。

  1. _Databases_に移動して、MySQLクラスターを選択します。

  2. 「アクション」をクリックして、ドロップダウンメニューから「読み取り専用ノードを追加」を選択します。

  3. ノードオプションを設定し、_Create_ボタンを押します。 新しいノードの準備が整うまで数分かかる場合があることに注意してください。

  4. 2つの読み取り専用ノードがあるように、手順1〜4をもう一度繰り返します。

  5. Laravel構成に必要になるため、2つのノードのホストを書き留めます。

読み取り専用ノードの準備ができたら、ターミナルに戻ります。

次に、複数のデータベースノードで動作するようにLaravelアプリケーションを構成します。 完了すると、「+ INSERT」や「+ UPDATE」などのクエリがプライマリクラスタノードに転送され、すべての「+ SELECT +」クエリが読み取り専用ノードにリダイレクトされます。

まず、サーバー上のアプリケーションのディレクトリに移動し、選択したテキストエディターを使用して `+ .env +`ファイルを開きます。

cd /var/www/travellist
nano .env

MySQLデータベース設定を見つけて、 `+ DB_HOST +`行をコメントアウトします。

/var/www/travellist/.env

DB_CONNECTION=mysql

DB_PORT=MANAGED_MYSQL_PORT
DB_DATABASE=MANAGED_MYSQL_DB
DB_USERNAME=MANAGED_MYSQL_USER
DB_PASSWORD=MANAGED_MYSQL_PASSWORD

完了したら、ファイルを保存して閉じます。 テキストエディタで `+ config / database.php +`を開きます。

nano config/database.php

+ connections in`配列内の + mysql`エントリを探します。 この構成配列には、「+ read」、「+ write」、および「+ sticky」という3つの新しい項目を含める必要があります。 `+ read `と ` write `エントリはクラスターノードを設定し、 ` sticky `オプションを ` true `に設定すると ` write `接続が再利用されるため、データベースに書き込まれたデータはすぐに同じ要求サイクル。 この動作が望ましくない場合は、「 false +」に設定できます。

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

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

編集が完了したら、ファイルを保存して閉じます。 すべてが期待どおりに機能することをテストするために、データベースからいくつかのデータを取得し、使用されている接続に関する詳細を表示するために、 `+ routes / web.php +`内に一時的なルートを作成できます。 これにより、読み取り専用ノード間でリクエストがどのように負荷分散されているかを確認できます。

`+ routes / web.php +`ファイルを開きます:

nano routes/web.php

次のルートを含めます。

/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;
});

ブラウザに移動して、 `+ / mysql-test +`アプリケーションルートにアクセスします。

http:///mysql-test

次のようなページが表示されます。

image:https://assets.digitalocean.com/articles/laravel_at_scale/mysql_test_page.png [mysqlノードテストページ]

ページを数回リロードすると、 `+ Server ID +`の値が変更され、リクエストが2つの読み取り専用ノード間でランダムに分散されていることがわかります。

結論

このガイドでは、可用性の高いスケーラブルな環境向けにLaravel 6アプリケーションを準備しました。 データベースシステムを外部の管理されたMySQLサービスにアウトソースし、S3互換オブジェクトストレージサービスをアプリケーションに統合して、ユーザーがアップロードしたファイルを保存しました。 最後に、追加の読み取り専用クラスターノードをアプリの構成ファイルに含めることで、アプリケーションのデータベースをスケールアップする方法を見てきました。

このガイドで行われたすべての変更を含む更新されたデモアプリケーションコードは、Githubのアプリケーションリポジトリのhttps://github.com/do-community/travellist-laravel-demo/tree/2.1[2.1 tag]内にあります。

ここから、https://www.digitalocean.com/community/tutorials/an-introduction-to-load-balancers-comic [Load Balancer]をセットアップして、複数のノード間で負荷を分散し、アプリケーションをスケーリングできます。 この設定を活用してhttps://www.digitalocean.com/community/tutorials/the-docker-ecosystem-an-overview-of-containerization [コンテナ化された環境]を作成し、Dockerでアプリケーションを実行することもできます。