管理対象データベースとオブジェクトストレージを使用してスケーラブルなLaravel6アプリケーションをセットアップする方法
序章
Webアプリケーションを水平方向にスケーリングする場合、通常直面する最初の問題は、ファイルストレージとデータの永続性の処理です。 これは主に、複数のアプリケーションノード間で可変データの一貫性を維持することが難しいという事実によるものです。 あるノードで作成されたデータをクラスター内の他のノードですぐに利用できるようにするには、適切な戦略を立てる必要があります。
整合性の問題を解決する実際的な方法は、管理対象データベースおよびオブジェクトストレージシステムを使用することです。 前者はデータの永続性を管理対象データベースにアウトソーシングし、後者は静的ファイルやユーザーがアップロードした画像などの可変コンテンツを保持できるリモートストレージサービスを提供します。 その後、各ノードはアプリケーションレベルでこれらのサービスに接続できます。
次の図は、PHPアプリケーションのコンテキストで、このようなセットアップを水平方向のスケーラビリティーに使用する方法を示しています。
このガイドでは、既存のLaravel 6アプリケーションを更新して、管理対象のMySQLデータベースに接続し、ユーザーが生成したファイルを保存するようにS3互換のオブジェクトストアを設定することで、水平方向のスケーラビリティに備えます。 最終的に、Nginx +PHP-FPMWebサーバーで旅行リストアプリケーションを実行できるようになります。
注:このガイドでは、 DigitalOcean ManagedMySQLおよびSpacesを使用して、管理対象データベースとオブジェクトストレージを使用したスケーラブルなアプリケーションセットアップを示します。 ここに含まれる手順は、他のサービスプロバイダーでも同様に機能するはずです。
前提条件
このチュートリアルを開始するには、最初に次の前提条件が必要です。
- sudo権限を持つ非rootユーザーとしてUbuntu18.04サーバーにアクセスし、サーバーにアクティブなファイアウォールをインストールします。 これらを設定するには、 Ubuntu18.04の初期サーバー設定ガイドを参照してください。
- Ubuntu18.04にLEMPをインストールする方法の手順1および3で説明されているように、NginxおよびPHP-FPMがサーバーにインストールおよび構成されています。 MySQLがインストールされているステップはスキップする必要があります。
- Ubuntu18.04にComposerをインストールして使用する方法の手順1および2で説明されているように、サーバーにComposerがインストールされています。
- 管理対象のMySQL8データベースへの管理者クレデンシャル。 このガイドでは、 DigitalOcean Managed MySQL クラスターを使用しますが、ここでの手順は、他のマネージドデータベースサービスでも同様に機能するはずです。
- S3互換のオブジェクトストレージサービスへの読み取りおよび書き込み権限を持つAPIキーのセット。 このガイドでは、 DigitalOcean Spaces を使用しますが、選択したプロバイダーを自由に使用できます。
s3cmd
ツールは、オブジェクトストレージドライブに接続するようにインストールおよび構成されています。 DigitalOcean Spacesでこれを設定する方法については、製品ドキュメントを参照してください。
ステップ1—MySQL8クライアントのインストール
デフォルトのUbuntuaptリポジトリにはMySQL5クライアントが付属していますが、これはこのガイドで使用するMySQL8サーバーと互換性がありません。 互換性のあるMySQLクライアントをインストールするには、Oracleが提供するMySQLAPTリポジトリを使用する必要があります。
WebブラウザのMySQLAPTリポジトリページに移動することから始めます。 右下隅にあるダウンロードボタンを見つけて、クリックして次のページに進みます。 このページでは、OracleWebアカウントにログインまたはサインアップするように求められます。 それをスキップして、代わりにというリンクを探すことができます。いいえ、ダウンロードを開始してください。 リンクアドレスをコピーして、ターミナルウィンドウに戻ります。
このリンクは、サーバーにMySQLAPTリポジトリをセットアップする.deb
パッケージを指している必要があります。 インストール後、apt
を使用してMySQLの最新リリースをインストールできるようになります。 curl
を使用して、このファイルを一時的な場所にダウンロードします。
サーバーのtmp
フォルダーに移動します。
cd /tmp
次に、curl
を含むパッケージをダウンロードし、MySQLAPTリポジトリページからコピーしたURLを使用します。
curl -OL https://dev.mysql.com/get/mysql-apt-config_0.8.13-1_all.deb
ダウンロードが完了したら、dpkg
を使用してパッケージをインストールできます。
sudo dpkg -i mysql-apt-config_0.8.13-1_all.deb
デフォルトとして選択するMySQLバージョンと、関心のあるMySQLコンポーネントを選択できる画面が表示されます。
デフォルトのオプションでは必要なリポジトリがインストールされるため、ここでは何も変更する必要はありません。 「OK」を選択すると、設定が完了します。
次に、apt
キャッシュを次のように更新する必要があります。
sudo apt update
これで、最終的にMySQL8クライアントを次のようにインストールできます。
sudo apt install mysql-client
そのコマンドが終了したら、ソフトウェアのバージョン番号をチェックして、最新のリリースであることを確認します。
mysql --version
次のような出力が表示されます。
Outputmysql Ver 8.0.18 for Linux on x86_64 (MySQL Community Server - GPL)
次のステップでは、MySQLクライアントを使用して管理対象のMySQLサーバーに接続し、アプリケーション用のデータベースを準備します。
ステップ2—新しいMySQLユーザーとデータベースを作成する
この記事の執筆時点では、ネイティブMySQLPHPライブラリmysqlnd
は、MySQL8のデフォルトの認証方法であるcaching_sha2_authentication
をサポートしていません。 LaravelアプリケーションをMySQL8サーバーに接続できるようにするには、mysql_native_password
認証方式で新しいユーザーを作成する必要があります。 また、デモアプリケーション専用のデータベースを作成します。
開始するには、管理者アカウントを使用してサーバーにログインします。 強調表示された値を独自のMySQLユーザー、ホスト、およびポートに置き換えます。
mysql -u MYSQL_USER -p -h MYSQL_HOST -P MYSQL_PORT
プロンプトが表示されたら、管理者ユーザーのパスワードを入力します。 ログインすると、MySQL8サーバーのコマンドラインインターフェイスにアクセスできるようになります。
まず、アプリケーション用の新しいデータベースを作成します。 次のコマンドを実行して、travellist
という名前の新しいデータベースを作成します。
CREATE DATABASE travellist;
次に、このユーザーのデフォルトの認証方法としてmysql_native_password
を使用して、新しいユーザーを作成し、パスワードを設定します。 強調表示された値を独自の値に置き換え、強力なパスワードを使用することをお勧めします。
CREATE USER 'travellist-user'@'%' IDENTIFIED WITH mysql_native_password BY 'MYSQL_PASSWORD';
次に、アプリケーションデータベースに対するこのユーザー権限を付与する必要があります。
GRANT ALL ON travellist.* TO 'travellist-user'@'%';
これで、次のコマンドでMySQLプロンプトを終了できます。
exit;
これで、Laravelアプリケーションから接続するための専用データベースと互換性のあるユーザーができました。 次のステップでは、アプリケーションコードを取得して構成の詳細を設定し、アプリが管理対象のMySQLデータベースに接続できるようにします。
このガイドでは、 LaravelMigrationsとデータベースシードを使用してアプリケーションテーブルを設定します。 既存のローカルデータベースをDigitalOceanマネージドMySQLデータベースに移行する必要がある場合は、MySQLデータベースをDigitalOceanマネージドデータベースにインポートする方法に関するドキュメントを参照してください。
ステップ3—デモアプリケーションのセットアップ
開始するには、デモLaravelアプリケーションをGithubリポジトリからフェッチします。 次のコマンドを実行する前に、アプリケーションの内容を自由に調べてください。
デモアプリケーションは、 Ubuntu18.04でLEMPを使用してLaravelをインストールおよび構成する方法に関するガイドで最初に開発されたトラベルバケットリストアプリです。 更新されたアプリには、訪問者がアップロードできる旅行写真や世界地図などの視覚的な改善が含まれています。 また、artisan
コマンドを使用して、アプリケーションテーブルを作成し、サンプルデータを入力するためのデータベース移行スクリプトとデータベースシードも紹介します。
このチュートリアルと互換性のあるアプリケーションコードを入手するには、Githubのプロジェクトのリポジトリから1.1リリースをダウンロードします。 ダウンロードした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
構成ファイルの作成とアプリキーの設定
次に、環境ごとに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
:ステップ2で作成したアプリケーションデータベースの名前。 DB_USERNAME
:ステップ2で作成したデータベースユーザー。 DB_PASSWORD
:ステップ2で定義したデータベースユーザーのパスワード。
強調表示された値を独自の管理対象MySQL情報とクレデンシャルで更新します。
... 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 ...
編集が完了したら、CTRL+X
、Y
、ENTER
の順に入力して、ファイルを保存して閉じます。
アプリケーションがMySQLデータベースに接続するように構成されたので、Laravelのコマンドラインツールartisan
を使用してデータベーステーブルを作成し、サンプルデータを入力できます。
ストレージリンクの設定
artisan
コマンドで提供されるデータベースツールを実行する前に、アプリケーションで使用している旅行の写真をホストするパブリックストレージフォルダーへのシンボリックリンクを作成する必要があります。 これが必要なのは、データベースシードスクリプトがこれらのサンプル写真に依存してplaces
テーブルにデータを挿入するためです。
次のコマンドは、public
ディレクトリ内にシンボリックリンクを作成します。このリンクは、アプリケーションの内部ストレージディレクトリstorage/app/public
を指し、Webサーバーを通じて公開されます。
php artisan storage:link
OutputThe [public/storage] directory has been linked.
リンクが作成され、それが指している場所を確認するには、次のコマンドを実行します。
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 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
データベースの移行と入力
次に、 LaravelMigrationsとデータベースシードを使用してアプリケーションテーブルを設定します。 これは、データベース構成が期待どおりに機能するかどうかを判断するのに役立ちます。
アプリケーションが使用するテーブルを作成する移行スクリプトを実行するには、次のコマンドを実行します。
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 serve
コマンドを使用すると、アプリケーション内ですべてが正しくセットアップされていることをすばやく確認できます。その後、Nginxなどのフル機能のWebサーバーを構成して、アプリケーションを長期間提供する必要があります。
ポート8000
を使用して、テスト用のアプリケーションを一時的に提供します。 サーバーでUFWファイアウォールを有効にしている場合は、最初に次の方法でこのポートへのアクセスを許可する必要があります。
sudo ufw allow 8000
ここで、Laravelがartisan
ツールを介して公開する組み込みのPHPサーバーを実行するには、次のコマンドを実行します。
php artisan serve --host=0.0.0.0 --port=8000
このコマンドは、CTRL+C
で中断されるまで端末をブロックします。 組み込みのPHPWebサーバーを使用して、ポート8000
を使用して、すべてのネットワークインターフェイスでテスト目的でアプリケーションを提供します。
次に、ブラウザに移動し、ポート8000
でサーバーのドメイン名またはIPアドレスを使用してアプリケーションにアクセスします。
http://server_domain_or_IP:8000
次のページが表示されます。
このページが表示されている場合は、アプリケーションが構成済みの管理対象データベースから場所と写真に関するデータを正常に取得していることを意味します。 イメージファイルは引き続きローカルディスクに保存されますが、このガイドの次の手順で変更します。
アプリケーションのテストが終了したら、CTRL+C
を押してserve
コマンドを停止できます。
サーバーでUFWを実行している場合は、ポート8000
を再度閉じることを忘れないでください。
sudo ufw deny 8000
ステップ4—アプリケーションにサービスを提供するようにNginxを構成する
組み込みのPHPWebサーバーは、開発とテストの目的で非常に役立ちますが、PHPアプリケーションを提供するための長期的なソリューションとして使用することを目的としたものではありません。 Nginxのようなフル機能のWebサーバーを使用することをお勧めします。
まず、アプリケーションフォルダーを/var/www
に移動します。これは、Nginxで実行されているWebアプリケーションの通常の場所です。 まず、mv
コマンドを使用して、アプリケーションフォルダーとそのすべての内容を/var/www/travellist
に移動します。
sudo mv ~/travellist /var/www/travellist
次に、Webサーバーユーザーにstorage
およびbootstrap/cache
フォルダーへの書き込みアクセスを許可する必要があります。Laravelはアプリケーションで生成されたファイルを保存します。 これらのアクセス許可は、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/travellist
次の構成ファイルには、Nginx上のLaravelアプリケーションの推奨設定が含まれています。
/ 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; } }
このコンテンツを/etc/nginx/sites-available/travellist
ファイルにコピーし、強調表示された値を調整して、独自の構成に合わせます。 編集が完了したら、ファイルを保存して閉じます。
新しい仮想ホスト構成ファイルをアクティブ化するには、sites-enabled
にtravellist
へのシンボリックリンクを作成します。
sudo ln -s /etc/nginx/sites-available/travellist /etc/nginx/sites-enabled/
注:travellist
仮想ホストで使用されているのと同じserver_name
に対して以前に構成された別の仮想ホストファイルがある場合は、削除して古い構成を非アクティブ化する必要があります。 /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/travellist rm -f public/storage
次に、artisan
コマンドをもう一度実行して、ストレージリンクを生成します。
php artisan storage:link
次に、ブラウザに移動し、構成ファイルのserver_name
ディレクティブで定義されているように、サーバーのドメイン名またはIPアドレスを使用してアプリケーションにアクセスします。
http://server_domain_or_IP
次のステップでは、オブジェクトストレージサービスをアプリケーションに統合します。 これにより、旅行の写真に使用されている現在のローカルディスクストレージが置き換えられます。
ステップ5—S3互換のオブジェクトストレージをアプリケーションに統合する
次に、S3互換のオブジェクトストレージサービスを使用して、インデックスページに表示された旅行の写真を保存するようにアプリケーションを設定します。 アプリケーションにはすでにローカルディスクに保存されているサンプル写真がいくつかあるため、 s3cmd ツールを使用して、既存のローカル画像ファイルをリモートオブジェクトストレージにアップロードします。
Laravel用のS3ドライバーのセットアップ
Laravelはleague/flysystem
を使用します。これは、Laravelアプリケーションがローカルディスクやクラウドサービスを含む複数のストレージソリューションを使用および組み合わせることができるようにするファイルシステム抽象化ライブラリです。 s3
ドライバーを使用するには、追加のパッケージが必要です。 このパッケージは、composer require
コマンドを使用してインストールできます。
アプリケーションディレクトリにアクセスします。
cd /var/www/travellist
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=EXAMPLE7UQOTHDTF3GK4 DO_SPACES_SECRET=exampleb8e1ec97b97bff326955375c5 DO_SPACES_ENDPOINT=https://ams3.digitaloceanspaces.com DO_SPACES_REGION=ams3 DO_SPACES_BUCKET=sammy-travellist
完了したら、ファイルを保存して閉じます。 次に、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', 'spaces'),
編集が完了したら、ファイルを保存して閉じます。 コントローラから、Storage::cloud()
メソッドをショートカットとして使用して、デフォルトの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->image = $request->image->store('/', 'public'); $photo->save(); return redirect()->route('Main'); }
このメソッドは、POST
リクエストを受け入れ、写真テーブルに新しい写真エントリを作成します。 まず、写真アップロードフォームで既存の場所が選択されているかどうかを確認します。選択されていない場合は、提供された情報を使用して新しい場所を作成します。 次に、場所がvisited
に設定され、データベースに保存されます。 その後、新しい写真が指定された場所にリンクされるように関連付けが作成されます。 その後、イメージファイルはpublic
ディスクのルートフォルダに保存されます。 最後に、写真がデータベースに保存されます。 次に、ユーザーは、アプリケーションのインデックスページであるメインルートにリダイレクトされます。
このコードで強調表示されている行は、私たちが関心を持っているものです。 その行で、イメージファイルはstore
メソッドを使用してディスクに保存されます。 store
メソッドは、filesystem.php
構成ファイルで定義されたディスクのいずれかにファイルを保存するために使用されます。 この場合、アップロードされた画像を保存するためにデフォルトのディスクを使用しています。
この動作を変更して、イメージがローカルディスクではなくオブジェクトストアに保存されるようにします。 そのためには、store
メソッド呼び出しでpublic
ディスクをspaces
ディスクに置き換える必要があります。 また、アップロードされたファイルの可視性がprivateではなくpublicに設定されていることを確認する必要があります。
次のコードには、更新されたuploadPhoto
メソッドを含む完全なPhotoController
クラスが含まれています。
app / Http / Controllers / PhotoController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Photo; use App\Place; use Illuminate\Support\Facades\Storage; 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->image = $request->image->store('/', 'spaces'); Storage::setVisibility($photo->image, 'public'); $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="{{ asset('storage') . '/' . $photo->image }}" /> <p>{{ $photo->place->name }}</p> </div> @endforeach @endsection
現在のイメージsrc
属性を置き換えて、spaces
ストレージディスクのファイルURLを使用します。
<img src="{{ Storage::disk('spaces')->url($photo->image) }}" />
今すぐブラウザにアクセスしてアプリケーションページをリロードすると、壊れた画像のみが表示されます。 これは、これらの旅行写真の画像ファイルがまだローカルディスクにのみ存在するために発生します。 データベースにすでに保存されている写真をアプリケーションページに正常に表示できるように、既存の画像ファイルをオブジェクトストレージにアップロードする必要があります。
ローカル画像をs3cmd
と同期する
s3cmd
ツールを使用して、ローカルファイルをS3互換のオブジェクトストレージサービスと同期できます。 sync
コマンドを実行して、storage/app/public/photos
内のすべてのファイルをオブジェクトストレージサービスにアップロードします。
public
アプリストレージディレクトリにアクセスします。
cd /var/www/travellist/storage/app/public
リモートディスクにすでに保存されているファイルを確認するには、s3cmd ls
コマンドを使用できます。
s3cmd ls s3://your_bucket_name
次に、sync
コマンドを実行して、パブリックストレージフォルダー内の既存のファイルをオブジェクトストレージにアップロードします。
s3cmd sync ./ s3://your_bucket_name --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://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
ブラウザに移動して、アプリケーションページをリロードします。 これですべての画像が表示されるはずです。ブラウザのデバッグツールを使用して画像を調べると、すべての画像がオブジェクトストレージのURLを使用していることがわかります。
統合のテスト
これで、デモアプリケーションは完全に機能し、リモートオブジェクトストレージサービスにファイルを保存し、管理対象のMySQLデータベースにデータを保存します。 これで、セットアップをテストするためにいくつかの写真をアップロードできます。
ブラウザから/upload
アプリケーションルートにアクセスします。
http://server_domain_or_IP/upload
次のフォームが表示されます。
これで、いくつかの写真をアップロードして、オブジェクトストレージの統合をテストできます。 コンピューターから画像を選択した後、ドロップダウンメニューから既存の場所を選択するか、名前と地理座標を指定して新しい場所を追加し、アプリケーションマップに読み込むことができます。
ステップ6—読み取り専用ノードを使用したDigitalOceanマネージドMySQLデータベースのスケールアップ(オプション)
通常、読み取り専用操作はデータベースサーバーでの書き込み操作よりも頻繁に行われるため、複数の読み取り専用ノードを設定してデータベースクラスターをスケールアップするのが一般的な方法です。 これにより、SELECT
操作によって生成された負荷が分散されます。
このセットアップを示すために、最初に2つの読み取り専用ノードをDigitalOceanマネージドMySQLクラスターに追加します。 次に、これらのノードを使用するようにLaravelアプリケーションを構成します。
DigitalOcean Cloud Panel にアクセスし、次の手順に従います。
- データベースに移動し、MySQLクラスターを選択します。
Actions
をクリックし、ドロップダウンメニューからAdd a read-only node
を選択します。- ノードオプションを設定し、作成ボタンを押します。 新しいノードの準備ができるまでに数分かかる場合があることに注意してください。
- 手順1〜4をもう一度繰り返して、読み取り専用ノードを2つ作成します。
- Laravel構成で必要になるため、2つのノードのホストを書き留めます。
読み取り専用ノードの準備ができたら、ターミナルに戻ります。
次に、複数のデータベースノードで動作するようにLaravelアプリケーションを構成します。 終了すると、INSERT
やUPDATE
などのクエリがプライマリクラスターノードに転送され、すべてのSELECT
クエリが読み取り専用ノードにリダイレクトされます。
まず、サーバー上のアプリケーションのディレクトリに移動し、選択したテキストエディタを使用して.env
ファイルを開きます。
cd /var/www/travellist nano .env
MySQLデータベース構成を見つけて、DB_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
完了したら、ファイルを保存して閉じます。 次に、テキストエディタでconfig/database.php
を開きます。
nano config/database.php
connections
アレイ内のmysql
エントリを探します。 この構成配列には、3つの新しいアイテムread
、write
、およびsticky
を含める必要があります。 read
およびwrite
エントリはクラスターノードをセットアップし、sticky
オプションをtrue
に設定すると、write
接続が再利用されます。データベースに書き込まれたデータは、同じ要求サイクルですぐに利用できます。 この動作を望まない場合は、false
に設定できます。
/var/www/travel_list/config/database.php
... 'mysql' => [ 'read' => [ 'host' => [ 'READONLY_NODE1_HOST', 'READONLY_NODE2_HOST', ], ], 'write' => [ 'host' => [ 'MANAGED_MYSQL_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://server_domain_or_IP/mysql-test
次のようなページが表示されます。
ページを数回リロードすると、Server ID
の値が変化し、2つの読み取り専用ノード間でリクエストがランダムに分散されていることがわかります。
結論
このガイドでは、高可用性でスケーラブルな環境向けのLaravel6アプリケーションを用意しました。 データベースシステムを外部のマネージドMySQLサービスにアウトソーシングし、S3互換のオブジェクトストレージサービスをアプリケーションに統合して、ユーザーがアップロードしたファイルを保存しました。 最後に、アプリの構成ファイルに追加の読み取り専用クラスターノードを含めることで、アプリケーションのデータベースをスケールアップする方法を確認しました。
このガイドで行われたすべての変更を含む更新されたデモアプリケーションコードは、Githubのアプリケーションのリポジトリにある2.1タグ内にあります。
ここから、ロードバランサーをセットアップして、負荷を分散し、アプリケーションを複数のノードにスケーリングできます。 この設定を利用して、コンテナー化された環境を作成し、Dockerでアプリケーションを実行することもできます。