ブログに戻る

Docker Composeを使用したLaravel、Nginx、MySQLのデプロイ

Docker Composeを使用したLaravel、Nginx、MySQLのデプロイ

はじめに

継続的インテグレーション(CI)と継続的デリバリー(CD)は、現在ソフトウェア開発において最もトレンドとなっているトピックの一部です。ソフトウェアアーキテクチャのCI/CDの側面を実現するために、開発者はコンテナを利用します。コンテナは、軽量で仮想化された、ポータブルな、ソフトウェア定義の環境です。コンテナ内では、物理ホストマシン上で動作している他のソフトウェアから隔離された状態でソフトウェアを実行できます。このチュートリアルでは、コンテナプラットフォームであるDockerを使用して、Webアプリケーションをデプロイおよび実行することに焦点を当てています。Dockerは、Webサーバースタックのセットアッププロセスを合理化するのに役立ちます。このチュートリアルでは、LEMPスタックを使用してLaravelアプリケーションを配信します。

LEMPスタックは、オペレーティングシステムとしてのLinux、NginxをWebサーバー、MySQLをデータベース、そしてPHP言語をスクリプティングおよび動的処理のために組み合わせたものです。私たちのUbuntuにLEMPスタックをインストールして設定する方法に関するチュートリアルを参考にしてください。Laravelは、Webアプリケーションを開発するためのトップクラスのPHPフレームワークの1つです。

Dockerは、Docker Composeと呼ばれる、Dockerコンテナのセットアッププロセスを定義するためのツールを提供しています。Docker Composeを使用すると、開発者はアプリケーションのインフラストラクチャ、サービス、ボリューム、ネットワーク、および依存関係を、docker-composeファイルと呼ばれる1つのファイルで定義できます。docker container createやdocker container runなどのコマンドを通じて、複数のDockerコンテナを管理できます。

このチュートリアルでは、Dockerコンテナ内でNginxとMySQLを使用してLaravel Webアプリケーションをデプロイする方法を学びます。スタック全体の構成は、docker-composeファイルのほか、PHP、MySQL、Nginxの他の構成ファイル内に定義されます。それでは始めましょう!

はじめに確認すること

に従ってDocker Composeをインストールする必要があります。

ステップ1:Laravelのダウンロードと依存関係のインストールGitHub上にある公式のLaravelリポジトリから最新バージョンをクローンします。このリポジトリには、PHP用のアプリケーションレベルの依存関係マネージャーであるcomposerファイルが含まれています。すべてをDockerコンテナ内で実行したいため、Dockerのcomposerイメージを使用して依存関係をインストールします。これにより、実際のホストマシンにcomposerをグローバルにインストールする必要もなくなります。次に、ターミナルを起動します。

ホームディレクトリに移動します:

次のコマンドを入力して、laravel-webというディレクトリにリポジトリをクローンします。名前は自由に変更して構いません。このリポジトリの執筆時点では、このコマンドを実行するとLaravelバージョン8がプルされます。コマンドを実行すると、おそらく新しいバージョンが見つかるでしょう:

次に、リポジトリをクローンしたディレクトリに移動します:

Dockerのcomposerイメージ:

docker runコマンドの-vおよび–rmフラグは、削除される前に現在のディレクトリにバインドマウントされる一時的なコンテナを作成します。このコマンドは、~/laravel-webの内容をコンテナにコピーし、composerによって作成されたvendorフォルダが現在のディレクトリにコピーし戻されるようにします。

次に、laravel-web ディレクトリの所有権を非ルートユーザーに変更する必要があります。これにより、非ルートユーザーとしてアプリケーションコードを操作し、以降のステップでコンテナ内でプロセスを実行できるようになります。所有権を変更するには、次のコマンドを入力します。

これでアプリケーションコードが配置されました。ディレクトリは非ルートユーザーが所有しているため、docker-compose ファイルでアプリケーションサービスを定義する手順に進むことができます。

ステップ 2: Docker Compose ファイルの作成

Docker Compose は、アプリケーションのビルドとデプロイのプロセスを簡素化します。設定とサービスを定義すれば、アプリケーションの依存関係を心配することなく、Docker と Docker Compose がインストールされている任意のホストマシンにアプリケーションを簡単にデプロイできます。最も重要なのは、これらをたった1つの Docker Compose コマンドで実行できることです。これについては、ステップ 9.

このステップでは、Laravel アプリをデプロイするために必要なウェブサーバー、データベース、およびアプリケーションサービスの設定を含む Docker Compose ファイルを定義します。

Docker Compose ファイルは、YAML 拡張子 .yml で保存されるファイルです。有効な Docker Compose ファイルにするには、適切なインデントが必要であることに注意してください。次のコマンドを入力して、編集用に nano でファイルを作成して開きます。

次に、このファイルで app、webserver、db の3つのサービスを定義します。db セクションはアプリケーションのデータベース資格情報を定義するため、強力な mysql_root_password を選択して、そのセクションで置き換えてください。次のコードをコピーして貼り付けます。

以下に、上記のコードのサービス定義の説明を示します:

  • app: Laravel アプリケーションを定義し、ステップ 4で定義するカスタム Docker イメージ cloudsigma.com/php を実行します。また、コンテナ内の Step 4。また、コンテナ内の working_dir を /var/www/html に設定します。
  • webserver: Docker から nginx:alpine イメージをプルし、ポート 80443.
  • db: Docker から mysql:5.7.32 イメージ をプルし、いくつかの環境変数を定義します。これには、アプリケーション用の laravel_web という名前のデータベースと、データベースのルートパスワードが含まれます。データベースの名前は任意のものに変更できます。 MYSQL_ROOT_PASSWORD プロパティを強力なパスワードに置き換えることを忘れないでください。このサービスは、ホスト上のポート 3306 をコンテナ上のポート 3306 にマッピングします。

各サービスにおける container_name プロパティは、そのサービスに対応するコンテナの名前を定義します。このプロパティを定義しない場合、Docker は各コンテナに対してランダムな名前を選択します。

networks プロパティは、ブリッジネットワークと呼ばれる、コンテナ間の通信を容易にする app-network を定義します。ブリッジネットワークは、同じネットワークブリッジ上のコンテナ間のみの通信を許可するソフトウェアブリッジによって制御されます。ブリッジソフトウェアコントローラーは、異なるブリッジネットワーク上のコンテナが直接通信するのを防ぐドライバーをインストールします。これにより、関連するサービスのみが直接通信できるようになるため、高いレベルのセキュリティが確保されます。関連する機能に接続する複数のサービスやネットワークを定義することもできます。

ステップ 3: データを永続化する方法

ウェブアプリケーションは、ユーザーへのデータの処理や提供を行います。このステップでは、アプリケーションのデータを永続化するために、サービス定義でボリュームとバインドマウントを定義する方法を説明します。Docker は、データを永続化し、アプリケーションの設定ファイルを保存するための、バインドマウントボリュームといった素晴らしい機能を提供しています。これらを使用して、Docker で Laravel アプリをセットアップします。

ボリュームは、バックアップの提供やコンテナのライフサイクルを超えたデータの永続化など、さまざまな理由から好まれます。バインドマウントは通常、ホストマシン上の実際のディレクトリを参照します。ボリュームを作成すると、Docker によって管理される Docker のストレージディレクトリ内に新しいディレクトリが作成されます。バインドマウントを作成すると、ホストマシン内のファイルまたはディレクトリがコンテナにマウントされます(絶対パスで参照されます)。これは、ホストマシン上のコードに変更を加えると、すぐにコンテナに反映されるため、ウェブアプリケーションにとって非常に重要です。

バインドマウントを使用する際は注意してください。Docker コンテナ内で実行されているプロセスは、ホストのファイルシステムに変更を加え、ホストシステム上で実行されている Docker 以外のプロセスに影響を与える可能性があります。Docker マウントは強力な機能ですが、これらのセキュリティ上の影響に注意してください。

それを踏まえた上で、セットアップでこれら2つの機能をどのように使用できるかを見てみましょう。まず、MySQL データベースを永続化するためのボリュームを定義します。作成した Docker Compose ファイルの db サービスの下に、以下のようにハイライトされた volumes プロパティを追加します。

定義されているように、ボリューム dbdata は /var/lib/mysql の内容を永続化します。これにより、バックアップが容易になり、データを失うことなくサービスを再起動できます。次に、Docker Compose ファイルの最後に volumes 定義を追加して、サービス間で利用できるようにする必要があります。ファイルの最下部に次のコードスニペットを入力します。

MySQL データベースに接続するには、資格情報を提供する必要があります。そのためには、db サービスの volumes プロパティの下に、以下のようにハイライトされたコードスニペットを追加して、バインドマウントを定義します。

このコードは、~/laravel-web/mysql/my.cnf をコンテナ内の /etc/mysql/my.cnf にバインドします。バインドされたファイルは、ステップ 7.

で作成する MySQL 設定ファイルです。コンテナは、アプリケーションコードを提供するために Nginx サーバーを使用する必要があります。したがって、この目的のために、webserver サービスの下に2つのバインドマウント(1つは Nginx 設定ファイル用、もう1つはアプリケーションコード用)を定義します。webserver サービスの下に、ボリューム定義のための次のコードスニペットを追加します。

この行 – ./:/var/www/html は、~/laravel-web ディレクトリ内のアプリケーションコードをコンテナ内の /var/www/html ディレクトリにバインドします。2つ目のバインドマウントでは、Nginxの設定ファイルが ~/laravel-web/nginx/conf.d/ に作成されます。これはコンテナ内の /etc/nginx/conf.d/ にマウントされます。したがって、必要に応じてホストマシン上の設定ファイルを更新できます。Nginxの設定ファイルは、ステップ6.

コードの変更をコンテナに自動的に反映させるために、アプリケーションコードをコンテナにバインドマウントします。これにより、デプロイプロセスが高速化されます。したがって、以下のハイライトされたコードスニペットを app サービスに追加します。

2行目は、ステップ5 で作成する ~/laravel-web/php/laravel.ini ファイル内のPHP設定ファイルを、コンテナ内の /usr/local/etc/php/conf.d/laravel.ini にバインドします。

これで、完成した Docker Compose ファイルは次のようになります。

すべて問題がなければ、Ctrl + O を押してファイルを保存します。次に、Ctrl + X を押してエディタを終了します。この時点で、Docker Compose ファイルを使用してアプリケーション用のカスタム Docker イメージをビルドできるようになります。

ステップ4: Dockerfileの作成

Dockerfileには、DockerがカスタムDockerイメージをビルドするために使用できる命令が含まれています。また、必要なソフトウェアをインストールし、アプリケーションに必要な設定を行うこともできます。これらは、アプリケーションコードをホストするコンテナ内の環境を指定します。作成したイメージは、共有のためにdocker hubにプッシュするか、他のプライベートレジストリに配置することができます。

Laravelアプリケーションイメージをビルドするための指示を指定するDockerfileを作成します。nanoを使用して、~/laravel-webディレクトリにDockerfileを作成します。

開いたエディタに、次のコードを追加します。

Dockerfileは、まずphp:7.4-fpm Dockerイメージに基づいてイメージを作成します。これは、PHP FastCGI実装(PHP-FPM)がインストールされたDebianベースのイメージです。Laravelが正常に動作するには、mcrypt、pdo_mysql、mbstring、imagickなどの他のPHP拡張機能が利用可能である必要があり、スクリプトはこれらをインストールします。その後、composer PHPパッケージマネージャーをインストールします。コンテナはこれを使用してLaravelのPHP依存関係をインストールします。

RUNディレクティブを使用すると、コンテナ内でのインストール、アップデート、設定の構成などのコマンドを定義できます。また、ユーザー権限も割り当てます。WORKDIRディレクティブは作業ディレクトリを指定します(この場合は/var/www/html)。スクリプトはCHOWNコマンドを実行して、/var/www/htmlディレクトリの権限をwww-dataユーザーに割り当てます。

最終的にイメージをビルドする前に、コンテナ内で実行されているアプリケーションへのアクセスを許可するためにポートを公開する必要があります。EXPOSEコマンドは、php-fpmサーバー用にポート9000を公開します。実行する最後のコマンドはCMDディレクティブです。これはphp-fpmを実行してサーバーを起動します。

Ctrl + Oを押してファイルを保存できます。その後、Ctrl + Xを押してエディタを終了します。

ステップ5:PHPの設定

このステップでは、Nginxからのリクエストを処理するようにphpサービスを設定します。phpディレクトリ内にlaravel.iniファイルを作成します。このファイルにはPHPの設定を記述します。これは、コンテナ内の/usr/local/etc/php/conf.d/laravel.iniにバインドマウントしたファイルです(ステップ3を参照)。このファイルの設定は、PHPの起動時に通常読み込まれるデフォルトのphp.iniファイルを上書きします。次のコマンドを入力して、phpディレクトリを作成します:

次のコマンドを入力して、phpディレクトリ内にlaravel.iniファイルを作成して開きます:

デフォルトの php.ini ファイルでは、アップロード制限が2Mに設定されています。例として、より大きなファイルをアップロードしたい場合に備えて、許可されるアップロード制限の値を変更してPHPの設定を調整および設定する方法を示します。ファイル内に次のコード行を入力します:

これによりアップロード制限が設定され、合計サイズが80MB以下のファイルをアップロードできるようになります。デフォルトのPHP設定を上書きするために、laravel.iniファイル内に他のPHP設定を追加することもできます。ここで、ファイルを保存して閉じます。

ステップ6:Nginxの設定

このステップでは、先ほど定義したphpサービスを使用するようにNginxを設定します。動的コンテンツを提供するためのPHP-FPM として FastCGIサーバー を使用します。FastCGIサーバーは、インタラクティブなプログラムがWebサーバーとインターフェースできるようにするソフトウェアです。

のdocker-composeファイルで定義したように、ステップ3、~/laravel-web/nginx/conf.d/ディレクトリ内にNginx設定ファイルapp.confを作成します。まず、次のコマンドを入力してディレクトリを作成します:

次に、次のコマンドを入力して、nanoを使用してapp.confファイルを作成して開きます:

ファイルに次のNginx設定コードを追加します:

Nginxは、URLに基づいてWebサイトの訪問者にどのディレクトリを提供すべきかを知るために、サーバーブロックと呼ばれる設定ファイルを読み込みます。詳細については、のチュートリアル「UbuntuへのNginxのインストール18.04」でサーバーブロックの設定についてお読みください。定義されているディレクティブは、次の目的を果たします:

  • listen – サーバーが着信リクエストをリッスンするポートを定義します。通常はポート80です。
  • error_log & access_log – アプリケーションログを書き込むためのファイルを定義します。
  • root – ウェブルートのパス、つまりインターネットからサーバーへのリクエストを処理するディレクトリを定義します。

phpのlocationブロックでは、fastcgi_passディレクティブが、appサービスがポート9000のTCPソケットでリッスンしていることを指定しています(これはDockerfileで定義されています)。これにより、PHP-FPMサーバーはUnixソケットではなくネットワーク経由でリッスンするようになります。UnixソケットはTCPソケットよりも速度面でわずかに有利な場合がありますが、ネットワークプロトコルがないため、ネットワークスタックをスキップします。

ホストが1台のマシン上にあるシナリオでは、Unixソケットの方が適しています。しかし、異なるホストでサービスが実行されている場合、TCPソケットには分散されたサービスを接続できるという利点があります。今回のケースでは、アプリコンテナはウェブサーバーコンテナとは異なるホストで実行されています。したがって、私たちの構成にはTCPソケットが最も適しています。

これで、Ctrl + Oを押してファイルを保存し、Ctrl + Xを押してエディタを終了できます。nginx/conf.d/ディレクトリに加えられた変更は、Docker Composeファイルに追加したバインドマウントのおかげで、ウェブサーバーコンテナに自動的に反映されます。これはステップ3.

ステップ7:MySQLの設定

NginxがPHPと連携するように設定できたので、次はMySQLを設定して動的データを保存し、PHPに提供できるようにします。すでにDocker Composeファイルで、PHPとMySQLの通信に必要な拡張機能をインストールするように設定しています。mysqlフォルダ内にMySQLの設定ファイルmy.cnfを作成します。これは、Docker Composeのdbサービスセクションで定義したように、/etc/mysql/my.cnfにバインドマウントされます。これはステップ3.

MySQLの設定や変更は、いつでもmy.cnfファイルに対して行うことができます。これらはすぐにコンテナ内に反映されます。まず、次のコマンドを入力してディレクトリを作成します。

次に、以下のコマンドを入力してnanoでファイルを作成し、開きます。

クエリログを有効にし、クエリログファイルの場所を指定するために、次のコードスニペットを入力します。

general_logプロパティを1に定義することで、一般的なログを許可します。general_log_fileプロパティは、ログファイルの場所を指定します。Ctrl + Oを押してファイルを保存し、Ctrl + Xを押してエディタを終了します。

ステップ8:Laravelの環境変数の設定

ここまでの時点で、すべてのサービスと設定が完了しました。したがって、コンテナをデプロイすることができます。しかし、ウェブアプリケーションを実際に使用できるようにする前に、完了しなければならない重要なステップがあります。それが環境変数です。Laravelフレームワークは、環境を定義するために.envというファイルを必要とします。デフォルトでは、Laravelには.env.exampleが付属しており、これを.envにコピーして、実際の詳細情報で変数を変更できます。次のコマンドを入力してファイルをコピーします。

コピーが完了したら、nanoを使用してファイルを開き、編集します。

以下は、ファイルがどのように表示されるかのスクリーンショットです。

screenshot of what the file

ファイル内で、次のステップは、これまでに設定した構成に合わせてDB_CONNECTIONブロックの下の変数を変更することです。以下のように更新します。

  • DB_HOST は、db データベースコンテナです。
  • DB_DATABASE は、laravel_web.
  • DB_USERNAME はデータベースのユーザー名です。お好みの名前を選択してください。このチュートリアルでは、laraveldocker.
  • DB_PASSWORD は、上記のユーザーがデータベースにログインするために使用する強力なパスワードです。強力なパスワードを選択してください。 ステップ10で、ここで選択したパスワードを使用してこのユーザーを作成します。

値を更新すると、DB_CONNECTIONは以下のようになります。

DB_CONNECTION

ファイルを保存して閉じます。

ステップ9:Dockerコンテナの実行

この段階で、すべてのサービスと設定がDocker Composeファイルに定義されています。すべてのコンテナを起動し、ボリュームを作成し、ネットワークを接続し、アプリケーションをセットアップしてビルドするために必要なコマンドは1つだけです。ターミナルに次のコマンドを入力します。

docker-compose upコマンドを初めて実行すると、必要なすべてのDockerイメージがダウンロードされます。ローカルコンピューター上にインフラストラクチャをセットアップしている場合、完了までに時間がかかることがあります。イメージがダウンロードされると、Composeはコンテナを作成します。-dフラグは、Dockerにコンテナをバックグラウンドで実行するよう指示します。プロセスが正常に完了すると、ターミナルに以下のような内容が表示されるはずです。

terminal

実行中のすべてのコンテナを一覧表示するには、ターミナルで次のコマンドを入力します。

以下のスクリーンショットのように、app、webserver、dbコンテナの詳細が表示されるはずです。

screenshot details

  • CONTAINER ID – 各コンテナの一意の識別子。
  • NAMES – Docker Composeファイルで定義されている、各コンテナに関連付けられたサービス名。(コンテナにアクセスするには、コンテナIDまたは名前のいずれかを使用できます)。
  • IMAGE – 各コンテナのイメージ名。
  • STATUS – コンテナの状態に関する情報を表示します(停止、実行中、または再起動中の可能性があります)。
  • PORTS – コンテナが公開しているポートを示します。

Docker Composeは、コンテナ内でターミナルコマンドを実行したり、コマンドラインにアクセスしたりするために使用できるexecというコマンドを提供しています。まず、Laravelアプリを実行しているコンテナであるappコンテナ内でいくつかのコマンドを実行します。

Dockerは、コンテナのコマンドラインにアクセスするためのコマンドを提供しています。その構文は次のとおりです:docker-compose exec container_name bash。appコンテナのコマンドラインにアクセスするには、次のコマンドを入力します。

コンテナのコマンドラインに入ったら、いくつかのLaravel Artisan 設定コマンドを実行できます。次のコマンドを入力してlaravelキーを生成し、.envファイルに保存します。

環境キーが設定されたら、次のコマンドを実行して設定をキャッシュできます。

設定はコンテナ内の /var/www/html/bootstrap/cache/config.php ファイルに保存されます。Ctrl + D キーを押すと、コンテナのターミナルを終了できます。

Laravelアプリがデプロイされ、実行されていることを確認するには、ブラウザでサーバー’のパブリックIP(http://your_server_public_ip)にアクセスします。新しいLaravelインストールのウェルカムページが表示されるはずです。

laravel screenshot

ステップ10:MySQLユーザーの設定

このステップでは、docker-composeファイルで指定したMySQLデータベースlaravel_web用のデータベースユーザーを作成します。コンテナ構築コマンドを実行したStep 9において、MySQLはインストールされましたが、データベースに対して無制限の権限を持つデフォルトのroot管理者アカウントのみが作成されました。rootユーザーの使用を避けるため、アプリケーションで使用する専用のユーザーlaraveldockerを作成します。これは、次の手順の環境変数で指定したユーザーです:Step 8。次のコマンドを入力して、ターミナル内のコマンドラインにアクセスします。

コンテナ内に入ったら、次のコマンドを入力してMySQLにログインします。

パスワードのプロンプトが表示されたら、次の手順のdocker-composeファイルのdbサービスで設定したパスワードを入力します:Step 2.

。MySQLプロンプトにログインしたら、次のSQLコマンドを入力して、docker-composeファイルで指定したデータベースが表示されるか確認します。

laravel_webデータベース、またはセットアップで指定した名前が表示されるはずです。

Laravel

次に、laravel_webデータベースのユーザーとパスワードを作成します。これは、次の手順の.envファイルで指定した詳細と同じである必要があります:Step 8。次のコマンドを入力してユーザーとパスワードを作成し、このユーザーにすべての権限を付与します。

変更をすぐに有効にするには、次のコマンドを入力して権限をフラッシュします:

これでMySQLユーザーの設定は完了です。exitと入力してEnterキーを押し、MySQLプロンプトを終了します。最後に、Ctrl + Dを押してdbコンテナを終了します。

ステップ11:LaravelアプリケーションコードとMySQLデータベース間の通信をテストする

ここまでのステップで、すべてが正常に動作しています。しかし、appコンテナ内のLaravelコードがdbコンテナ内のMySQLデータベースと通信できることを確認する必要があります。まず、次のコマンドを入力してappコンテナのターミナルにアクセスします:

次に、テーブルを作成するlaravel migrationコマンドを実行します:

Laravelがデフォルトのテーブルを作成する際、ターミナルにマイグレーションプロセスが表示されるはずです:

migration process

次に、Laravelからデータベースにアクセスできるかどうかをテストします。LaravelにはデフォルトでTinkerが付属しており、データベースへのアクセス、ジョブの実行、eloquent ORMなど、コマンドラインからアプリケーション全体とやり取りすることができます。Tinkerを使用してmigrationsテーブルのデータを表示できます。次のコマンドを入力してTinkerにアクセスします:

Tinkerプロンプトが表示されたら、以下を入力してmigrateコマンドによって作成されたテーブルを一覧表示できます:

以下のスクリーンショットは、現在laravel_webデータベースにあるテーブルの出力を示しています:

laravel_web database

テーブル名を指定することで、テーブル内のデータを取得できます。たとえば、次のコマンドを入力してmigrationsテーブルのデータを取得できます:

コマンドは以下を出力します:

comman output

上記の出力から、Laravelアプリケーションが適切に設定され、データベースと通信できていることがわかります。モデルの作成やジョブの実行など、さらに多くのコマンドを試すことができます。Ctrl + Dを押すことで、Tinkerプロンプトを終了できます。

まとめ

このチュートリアルでは、Dockerコンテナ内にLEMPスタックのLaravelアプリケーションをデプロイしました。Webインターフェースにアクセスし、Laravel Tinkerを介してデータベースに接続することで、アプリケーションをテストしました。Docker Composeの強力さを体験できたかと思います。これにより、1つのファイルで定義されたDockerコンテナのグループを作成し、単一のコマンドだけで実行できるようになります。

コンテナについてさらに詳しく知りたい場合は、当社のDockerリソース(イメージ、コンテナ、ボリューム)をクリーンアップする方法を示すチュートリアルや、Kubernetesツールの詳細な概要.

をご覧ください。また、ブログでDockerと継続的インテグレーションおよび継続的デプロイ.

Happy Computing!

author

Pranay Kapgate

著者 · CloudSigma

Preslav DobrevはCloudSigmaのクリエイティブデザイナーであり、従来型および革新的なマーケティングチャネルを活用した一貫性のあるビジネスアイデンティティに注力しています。彼は芸術的なビジョンと戦略的マーケティングを融合させ、インパクトのあるブランドナラティブを生み出すことに長けています。

コメント

コメントはまだありません。最初のコメントを投稿しましょう。