序章

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 を使用しますが、選択したプロバイダーを自由に使用できます。
  • The s3cmd オブジェクトストレージドライブに接続するためにインストールおよび構成されたツール。 DigitalOcean Spacesでこれを設定する方法については、製品ドキュメントを参照してください。

ステップ1—MySQL8クライアントのインストール

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

WebブラウザのMySQLAPTリポジトリページに移動することから始めます。 右下隅にあるダウンロードボタンを見つけて、クリックして次のページに進みます。 このページでは、OracleWebアカウントにログインまたはサインアップするように求められます。 それをスキップして、代わりにというリンクを探すことができます。いいえ、ダウンロードを開始してください。 リンクアドレスをコピーして、ターミナルウィンドウに戻ります。

このリンクは .deb サーバーにMySQLAPTリポジトリをセットアップするパッケージ。 インストール後、ご利用いただけるようになります apt MySQLの最新リリースをインストールします。 使用します curl このファイルを一時的な場所にダウンロードします。

サーバーに移動します tmp フォルダ:

  1. cd /tmp

今すぐパッケージをダウンロードしてください curl MySQLAPTリポジトリページからコピーしたURLを使用します。

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

ダウンロード終了後、ご利用いただけます dpkg パッケージをインストールするには:

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

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

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

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

  1. sudo apt update

これで、最終的にMySQL8クライアントを次のようにインストールできます。

  1. sudo apt install mysql-client

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

  1. mysql --version

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

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

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

ステップ2—新しいMySQLユーザーとデータベースを作成する

この記事の執筆時点では、ネイティブMySQLPHPライブラリ mysqlnd はサポートしていません caching_sha2_authentication、MySQL8のデフォルトの認証方法。 を使用して新しいユーザーを作成する必要があります mysql_native_password LaravelアプリケーションをMySQL8サーバーに接続できるようにするための認証方法。 また、デモアプリケーション専用のデータベースを作成します。

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

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

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

まず、アプリケーション用の新しいデータベースを作成します。 次のコマンドを実行して、という名前の新しいデータベースを作成します travellist:

  1. CREATE DATABASE travellist;

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

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

次に、アプリケーションデータベースに対するこのユーザー権限を付与する必要があります。

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

これで、次のコマンドでMySQLプロンプトを終了できます。

  1. exit;

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

このガイドでは、 LaravelMigrationsデータベースシードを使用してアプリケーションテーブルを設定します。 既存のローカルデータベースをDigitalOceanマネージドMySQLデータベースに移行する必要がある場合は、MySQLデータベースをDigitalOceanマネージドデータベースにインポートする方法に関するドキュメントを参照してください。

ステップ3—デモアプリケーションのセットアップ

開始するには、デモLaravelアプリケーションをGithubリポジトリからフェッチします。 次のコマンドを実行する前に、アプリケーションの内容を自由に調べてください。

デモアプリケーションは、 Ubuntu18.04でLEMPを使用してLaravelをインストールおよび構成する方法に関するガイドで最初に開発されたトラベルバケットリストアプリです。 更新されたアプリには、訪問者がアップロードできる旅行写真や世界地図などの視覚的な改善が含まれています。 また、データベース移行スクリプトとデータベースシードを導入して、アプリケーションテーブルを作成し、それらにサンプルデータを入力します。 artisan コマンド。

このチュートリアルと互換性のあるアプリケーションコードを入手するには、Githubのプロジェクトのリポジトリから1.1リリースをダウンロードします。 ダウンロードしたzipファイルを次のように保存します travellist.zip ホームディレクトリ内:

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

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

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

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

  1. cd travellist

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

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

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

  1. composer install

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

Output
Loading 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 設定ファイルとアプリキーの設定

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

をコピーします .env.example ファイルを名前の付いた新しいファイルに .env:

  1. cp .env.example .env

次に、アプリケーションキーを設定する必要があります。 このキーはセッションデータの暗号化に使用され、32文字の一意の文字列に設定する必要があります。 このキーは、 artisan 道具:

  1. php artisan key:generate

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

  1. 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 それから YENTER 編集が終わったら。

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

によって提供されるデータベースツールを実行する前に artisan コマンドを実行するには、アプリケーションで使用している旅行の写真をホストするパブリックストレージフォルダーへのシンボリックリンクを作成する必要があります。 これが必要なのは、データベースシードスクリプトがこれらのサンプル写真に依存してデータを挿入するためです。 places テーブル。

次のコマンドは、内部にシンボリックリンクを作成します public ディレクトリ。Webサーバーを介して公開され、アプリケーションの内部ストレージディレクトリを指します。 storage/app/public:

  1. php artisan storage:link
Output
The [public/storage] directory has been linked.

リンクが作成され、それが指している場所を確認するには、次のコマンドを実行します。

  1. ls -la public/

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

Output
total 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データベースシードを使用してアプリケーションテーブルを設定します。 これは、データベース構成が期待どおりに機能するかどうかを判断するのに役立ちます。

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

  1. php artisan migrate

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

Output
Migration 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)

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

  1. php artisan db:seed

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

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

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

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

あなたは使用することができます artisan serve 長期間アプリケーションにサービスを提供するためにNginxなどのフル機能のWebサーバーを構成する前に、アプリケーション内ですべてが正しくセットアップされていることをすばやく確認するコマンド。

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

  1. sudo ufw allow 8000

次に、Laravelが公開する組み込みのPHPサーバーを実行します。 artisan ツール、実行:

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

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

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

http://server_domain_or_IP:8000

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

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

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

ポートを閉じることを忘れないでください 8000 サーバーでUFWを実行している場合も、次のようになります。

  1. sudo ufw deny 8000

ステップ4—アプリケーションにサービスを提供するようにNginxを構成する

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

開始するには、アプリケーションフォルダをに移動します /var/www、これはNginxで実行されているWebアプリケーションの通常の場所です。 まず、 mv アプリケーションフォルダとそのすべての内容をに移動するコマンド /var/www/travellist:

  1. sudo mv ~/travellist /var/www/travellist

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

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

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

これでアプリケーションファイルは正常になりましたが、コンテンツを提供するようにNginxを構成する必要があります。 これを行うには、次の場所に新しい仮想ホスト構成ファイルを作成します。 /etc/nginx/sites-available:

  1. 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 ファイルを作成し、強調表示された値を調整して、独自の構成に合わせます。 編集が完了したら、ファイルを保存して閉じます。

新しい仮想ホスト構成ファイルをアクティブ化するには、次のシンボリックリンクを作成します。 travellistsites-enabled:

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

:以前に同じように構成された別の仮想ホストファイルがある場合 server_name で使用される travellist 仮想ホストの場合、内部の対応するシンボリックリンクを削除して、古い構成を非アクティブ化する必要がある場合があります /etc/nginx/sites-enabled/.

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

  1. sudo nginx -t

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

  1. Output
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
  2. nginx: configuration file /etc/nginx/nginx.conf test is successful

変更を適用するには、次のコマンドでNginxをリロードします。

  1. sudo systemctl reload nginx

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

次のコマンドで古いリンクを削除します。

  1. cd /var/www/travellist
  2. rm -f public/storage

今もう一度実行します artisan ストレージリンクを生成するコマンド:

  1. php artisan storage:link

次に、ブラウザに移動し、サーバーのドメイン名またはIPアドレスを使用してアプリケーションにアクセスします。 server_name 構成ファイルのディレクティブ:

http://server_domain_or_IP

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

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

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

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

Laravelは league/flysystem、Laravelアプリケーションがローカルディスクやクラウドサービスを含む複数のストレージソリューションを使用および組み合わせることができるようにするファイルシステム抽象化ライブラリ。 を使用するには、追加のパッケージが必要です s3 運転者。 このパッケージは、 composer require 指図。

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

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

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

Output
Using 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 ファイル:

  1. 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 ファイル:

  1. nano config/filesystems.php

このファイル内に、新しいdiskエントリを作成します。 disks 配列。 このディスクに名前を付けます 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 ディスク。 このように、アプリケーションは複数のストレージソリューションを使用する柔軟性を維持し、環境ごとにプロバイダーを切り替えることができます。

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

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

  1. 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 方法。 The store メソッドは、で定義されたディスクのいずれかにファイルを保存するために使用されます filesystem.php 構成ファイル。 この場合、アップロードされた画像を保存するためにデフォルトのディスクを使用しています。

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

次のコードには完全なものが含まれています PhotoController 更新されたものを含むクラス uploadPhoto 方法:

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 テンプレート:

  1. 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 からのファイルURLを使用する属性 spaces ストレージディスク:

<img src="{{ Storage::disk('spaces')->url($photo->image) }}" />

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

ローカル画像との同期 s3cmd

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

アクセスする public アプリのストレージディレクトリ:

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

リモートディスクにすでに保存されているファイルを確認するには、 s3cmd ls 指図:

  1. s3cmd ls s3://your_bucket_name

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

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

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

Output
upload: './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つの新しいファイルが追加されたことがわかります。

  1. s3cmd ls s3://your_bucket_name
Output
2019-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 にアクセスし、次の手順に従います。

  1. データベースに移動し、MySQLクラスターを選択します。
  2. クリック Actions と選択します Add a read-only node ドロップダウンメニューから。
  3. ノードオプションを設定し、作成ボタンを押します。 新しいノードの準備ができるまでに数分かかる場合があることに注意してください。
  4. 手順1〜4をもう一度繰り返して、読み取り専用ノードを2つ作成します。
  5. Laravel構成で必要になるため、2つのノードのホストを書き留めます。

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

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

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

  1. cd /var/www/travellist
  2. 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 テキストエディタで:

  1. nano config/database.php

探してください mysql 内部のエントリ connections 配列。 この構成配列に3つの新しいアイテムを含める必要があります。 read, write、 と sticky. The readwrite エントリはクラスタノードを設定し、 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 ファイル:

  1. 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でアプリケーションを実行することもできます。