- 投稿日:2022-01-31T19:00:34+09:00
【Laravel 8】ユーザー真偽をして表示/非表示
はじめに Laravel 初学者の私が学習した内容をアウトプットしていく記事になります。 冗長している点や軽い書き方などあれば御指南をお願いいたします。。。? ユーザー真偽をして表示/非表示 実装する内容 今回は、ユーザー自身のポートフォリオをBootstrap tabを使用して、ユーザー自身のマイページならタブを表示 / 他ユーザーのページに行ったらタブを消す仕様です。 詰まったこと 条件をどう分岐させるか的を得てない。 今回の解決策はこれ!URL の id と ログインユーザーが一緒なら ture URL に注目していなかった。根本的にロジックが立てられていない状態なので、そこに着眼点を置くことができていませんでした。 if (Auth::id() === $user->id) 「訪れているページが自分か他人か」 このロジックが今回は正解でした。 今思えば、なに詰まることが事があるんだと恥ずかしくなります。 該当コードが以下のものになります。 UserController.php public function show(User $user, Request $request) { $user->load('portfolios.technologies', 'portfolios.user'); $introduction = ReplaceClickableUrl($user->user_self_introduction); $currentUser = Auth::user(); $isPublished = $request->input('is_published'); $isPublished = (bool)$isPublished; $portfolios = Portfolio::where('is_published', $isPublished)->orderBy('created_at', 'desc')->where('user_id', $user->id)->get(); $portfolios->load('portfolioLikes'); if (Auth::guard('company')->check()) { return view('user.profiles.show', compact('user', 'portfolios', 'introduction', 'currentUser')); } return view('user.profiles.show', compact('user', 'portfolios', 'introduction', 'currentUser','isPublished')); } 最初は、$portfolios に ->get() していたので first() に変更してとか試してました。しかし、下の条件分岐で count メソッドがあるので、複数ある場合はエラーを吐かれるそう。 今回は、 controller 側で完結だったのでだいぶ蛇足を踏みました。。。 show.blade.php <div class="row justify-content-center mt-5"> <div class="col-md-10"> @if (Auth::id() === $user->id) <nav> <div class="nav nav-tabs" id="nav-tab" role="tablist"> <a class="nav-item nav-link inline-block text-gray-500 hover:text-gray-600 hover:border-gray-300 rounded-t-lg px-4 text-sm font-medium text-center border-transparent border-b-2 dark:text-gray-400 dark:hover:text-gray-300 {{ $isPublished ? 'active' : '' }}" id="nav-published-tab" data-tab-item="published" href="?is_published=1"> 公開 </a> <a class="nav-item nav-link inline-block text-gray-500 hover:text-gray-600 hover:border-gray-300 rounded-t-lg px-4 text-sm font-medium text-center border-transparent border-b-2 dark:text-gray-400 dark:hover:text-gray-300 {{ !$isPublished ? 'active' : '' }}" id="nav-draft-tab" data-tab-item="draft" href="?is_published=0"> 下書き </a> </div> </nav> @endif @include('components.mypageTab') </div> </div> mypageTab.php div class="tab-content" id="nav-tabContent"> <div class="tab-pane fade show active" id="nav-published" role="tabpanel" aria-labelledby="nav-published-tab"> <div class="row text-center pt-3"> @if (count($portfolios) !== 0) @foreach ($portfolios as $portfolio) @include('components.portfolio-card') @endforeach @else <div class="col-12 mb-3 mt-5"> <p>現在、まだポートフォリオの投稿はありません。</p> </div> @endif </div> </div> </div> こんなことで躓くのか。。ハぁ?と悔しかったです。しかし、これからもいろんな事象を解決できるようにインプットをしていきたいと思います。 これからも、アウトプットを続けていきます!! 最後まで、読んでいてだきありがとうございました??♂️
- 投稿日:2022-01-31T13:59:41+09:00
SQLSTATE[HY000] [2002] Connection refused が出た時の対処方法
エラー内容 このような内容でした SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.tables where table_schema = laravel and table_name = migrations and table_type = 'BASE TABLE') at vendor/laravel/framework/src/Illuminate/Database/Connection.php:712 708▕ // If an exception occurs when attempting to run a query, we'll format the error 709▕ // message to include the bindings with SQL, which will make this exception a 710▕ // lot more helpful to the developer instead of just the database's errors. 711▕ catch (Exception $e) { ➜ 712▕ throw new QueryException( 713▕ $query, $this->prepareBindings($bindings), $e 714▕ ); 715▕ } 716▕ } +36 vendor frames 37 artisan:37 Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) 対処法 php artisan tinkerで.envファイルの内容がちゃんと反映されてるか確かて見たところ、反映されていなかったためこれが原因だったようです。 root@8dae87ded68a:/var/www/app# php artisan tinker Psy Shell v0.11.1 (PHP 8.0.15 — cli) by Justin Hileman >>> config('database') => [ ../ "mysql" => [ "driver" => "mysql", "url" => null, "host" => "127.0.0.1", #要注意 "port" => "3306", "database" => "laravel",#要注意 "username" => "root",#要注意 "password" => "",#要注意 "unix_socket" => "", "charset" => "utf8mb4", "collation" => "utf8mb4_unicode_ci", "prefix" => "", "prefix_indexes" => true, "strict" => true, "engine" => null, "options" => [], ], ../ なので.envファイルを適用させればいいのですが、php artisan config:clearコマンドで内容を適用させればいらしいんですが、私の場合これではうまく適用されずrm app/.envでファイルを削除させもう一度復元させたら成功しました。 まとめ ファイルを消さないと適用されないところを治したい
- 投稿日:2022-01-31T11:48:01+09:00
Laravel-uiと認証について その2
はじめに この記事は、「なんとなく理解できた」を目的としているため、正確性、具体性に欠ける表現がございます。 精度の高い情報を求めている方には向かないので、ご理解ください。 前回の続きなので、まだのひとが下のリンクからどうぞ Login画面が登場! laravel-uiがインストールされた状態で、Larabelのホームページを見ると、ログインと登録機能が、右上に追加されていた。 これが、laravel-uiの機能だと予想できる。 composer require laravel/ui:^1.0 --dev
- 投稿日:2022-01-31T11:33:54+09:00
Laravel-uiと認証について
はじめに この記事は、「なんとなく理解できた」を目的としているため、正確性、具体性に欠ける表現がございます。 精度の高い情報を求めている方には向かないので、ご理解ください。 Laravel-ui 以前は、Laravelに標準搭載されていたが、var6.0から、切り離された。 なので、使いたい場合は、Laravelのインストールとは別で、laravel-uiをインストールしなければならない。 Laravel-uiをインストールすると、スカフォールドというものも、同時にインストールされる。(英語で足場という意味...どんな役割があるのかはよくわからない) Laravel-uiのインストール手順 1.0と、バージョンが指定されているが、Laravelのver6だと、バージョン指定をしてあげないとエラーが発生するので、必須。 1.0と書いてあるが、^を付ける事で、1.Xの最新バージョンがインストールされるという意味になる。(今回の場合は、1.2になった。) composer require laravel/ui:^1.0 --dev 基本的なスカフォールドの作成 bootstrap,vue,reactが、スカフォールドの一種っぽい。 // 基本的なスカフォールドを生成 php artisan ui bootstrap php artisan ui vue php artisan ui react // ログイン/ユーザー登録スカフォールドを生成 php artisan ui bootstrap --auth php artisan ui vue --auth php artisan ui react --auth フロントエイドのスカフォールドは、bootstrap,vue,reactの3つにわかられる。 教材に方では、bootstrapがインストールされていた。 Bootstrapについて bootstrapをインストールしたら、認証関連のファイルがインストールされていたことから、bootstrap=認証関連のスカフォールドという説が濃厚です。 bootstrapをインストールしたことで、Routeにあるweb.phpに、 Auth::routes(); という文が追加された。 それから、app/Http/Controllerの中に、Authという名前のフォルダが作成されていた。 その中に、ファイルがいくつか格納されていた。 これらのファイルは、認証に関連するものという説明があった。 ここまでのまとめ 情報が多くなってきたので、いったんまとめてみる。 ここまでをまとめると、bootstrapが、認証関連のスカフォールドで、Authという関数?を使用する。 で、Controllerの中に、認証関連のbootstrapファイルが、authという名前でまとめられているという解釈でよさそう。
- 投稿日:2022-01-31T11:33:54+09:00
Laravel-uiと認証について その1
はじめに この記事は、「なんとなく理解できた」を目的としているため、正確性、具体性に欠ける表現がございます。 精度の高い情報を求めている方には向かないので、ご理解ください。 Laravel-ui 以前は、Laravelに標準搭載されていたが、var6.0から、切り離された。 なので、使いたい場合は、Laravelのインストールとは別で、laravel-uiをインストールしなければならない。 Laravel-uiをインストールすると、スカフォールドというものも、同時にインストールされる。(英語で足場という意味...どんな役割があるのかはよくわからない) Laravel-uiのインストール手順 1.0と、バージョンが指定されているが、Laravelのver6だと、バージョン指定をしてあげないとエラーが発生するので、必須。 1.0と書いてあるが、^を付ける事で、1.Xの最新バージョンがインストールされるという意味になる。(今回の場合は、1.2になった。) composer require laravel/ui:^1.0 --dev 基本的なスカフォールドの作成 bootstrap,vue,reactが、スカフォールドの一種っぽい。 // 基本的なスカフォールドを生成 php artisan ui bootstrap php artisan ui vue php artisan ui react // ログイン/ユーザー登録スカフォールドを生成 php artisan ui bootstrap --auth php artisan ui vue --auth php artisan ui react --auth フロントエイドのスカフォールドは、bootstrap,vue,reactの3つにわかられる。 教材に方では、bootstrapがインストールされていた。 Bootstrapについて bootstrapをインストールしたら、認証関連のファイルがインストールされていたことから、bootstrap=認証関連のスカフォールドという説が濃厚です。 bootstrapをインストールしたことで、Routeにあるweb.phpに、 Auth::routes(); という文が追加された。 それから、app/Http/Controllerの中に、Authという名前のフォルダが作成されていた。 その中に、ファイルがいくつか格納されていた。 これらのファイルは、認証に関連するものという説明があった。 ここまでのまとめ 情報が多くなってきたので、いったんまとめてみる。 bootstrapが、認証関連のスカフォールドで、Authという関数?を使用する。 で、Controllerの中に、認証関連のbootstrapファイルが、authという名前でまとめられているという解釈でよさそう。 長くなってきたので、続きは、part2に記載する
- 投稿日:2022-01-31T08:28:14+09:00
Dockerでnginx + PHP(Laravel)+ MySQLのLEMP環境を構築する
概要 Docker, Docker Compose を使って、nginx + PHP(Laravel)+ MySQLのLEMP環境を構築する記事です。 検索するとDockerfileやdocker-compose.ymlの書き方については色んな方が記事を書いてくださっていて、動く環境を作ること自体は難しくありませんでした。 ですが、筆者はひとつコンテナを作っては動作確認していくという過程を経てすごく理解が深まったなと思うので、ファイルの書き方だけでなく動作確認したことやその結果を含めて記事に残しておきたいと思います。 全体像 最終的なディレクトリ構成は以下の通りです。 全コンテナを管理するdocker-compose.ymlがトップレベルにあり、同じくトップレベルにあるdockerディレクトリ配下に各コンテナのDockerfileや設定ファイルを置いています。 tree docker_sample/ ├── src // Laravelプロジェクトのソースコード ├── docker │ ├── app // PHPコンテナ │ │ ├── Dockerfile │ │ └── php.ini │ ├── db // MySQLコンテナ │ │ ├── Dockerfile │ │ └── my.cnf │ └── web // nginxコンテナ │ ├── Dockerfile │ └── default.conf └── docker-compose.yml // 全コンテナの管理 早速一つずつコンテナを作っていきます。 PHPのコンテナ(Laravelの開発環境) まずはLaravelの開発環境を構築するための、PHPのコンテナを作成します。 docker-compose.ymlへの記述 PHPコンテナ用のDockerfile PHPコンテナ用の設定ファイル(php.ini) について順に説明します。 docker-compose.yml(PHP) docker-compose.ymlのうち、PHPコンテナについての記述は以下の通りです。 ※docker-compose.ymlはインデントが意味を持つので注意。 docker-compose.yml version: "3.9" services: app: // サービス名 build: context: . dockerfile: ./docker/app/Dockerfile volumes: - ./src/:/app version: これはPHPコンテナについてではなく docker-compose.yml の先頭に書く設定ですが、Composeファイルのバージョンを表しています。 今回は最新の 3.9 を使います。(最新のバージョンは下記の公式サイトを参照) Compose file build: ビルドコンテキストを指定します。 context:ビルドコンテキスト(buildを実行する場所)の設定 dockerfile:buildするDockerfileまでのパス(docker-compose.ymlから見た相対パス) 参考記事: docker-compose.ymlのbuild設定はとりあえずcontextもdockerfileも埋めとけって話 - Qiita volumes: ホスト側の ./src/をコンテナ側の /app にマウントするという意味になります。 ※ここで services: の中に書いているこの volumes: は バインドマウント を行っています。 参考記事:Dockerのマウント3種類についてわかったことをまとめる - Qiita 何が起きているかは実際の挙動を見てみた方が分かりやすいと思うので、後ほどまた動作確認します。 Dockerfile(PHP) Dockerfileはテキストファイルであり、Dockerイメージを作り上げるために実行する命令をこのファイルに書きます。 まず作成するDockerfileの全文がこちらです。 /docker/app/Dockerfile FROM php:8.0-fpm ENV TZ Asia/Tokyo RUN apt-get update && \ apt-get install -y git unzip libzip-dev libicu-dev libonig-dev && \ docker-php-ext-install intl pdo_mysql zip bcmath COPY ./docker/app/php.ini /usr/local/etc/php/php.ini COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer WORKDIR /app 一つずつ説明します。 FROM php:8.0-fpm FROMではイメージをビルドするためのベースイメージを設定します。 書き方は FROM イメージ名:タグ名 です。 ここではDocker HubからPHP公式のイメージをベースとして指定しています。 Php - Official Image | Docker Hub ENV TZ Asia/Tokyo ENVはコンテナ内のサーバー環境変数を設定します。 RUN apt-get update && \ apt-get install -y git unzip libzip-dev libicu-dev libonig-dev && \ docker-php-ext-install intl pdo_mysql zip bcmath RUN にはコンテナビルド時に実行するコマンドを書きます。 && で複数のコマンドをつなぎ、 \ で改行します。 ※ && と \ を使うことで複数コマンドを1レイヤーにまとめることができ、公式でもベストプラクティスのTipsとして挙げられています。 Intro Guide to Dockerfile Best Practices - Docker Blog apt-get update :インストール可能なパッケージの「一覧」を更新 apt-get -y install:パッケージをインストール docker-php-ext-install:PHPの拡張ライブラリをインストール ※Laravelのインストールや開発に必要な(もしくは便利な)パッケージや拡張ライブラリをインストールしています。 ※試しにこれらを全くインストールせず手順を進めてみると、コンテナを起動することはできますが、その後のLaravelプロジェクトを作成する時に大量のエラーに遭遇しました(笑) COPY ./docker/app/php.ini /usr/local/etc/php/php.ini ローカルで(後ほど)作成する php.ini (PHPの設定ファイル)をDockerコンテナ内にコピーします。 書き方は COPY [ローカル側のパス] [コンテナ側のパス]です。 ※ローカル側のパスは、Dockerfileから見てではなくbuildコマンドを実行するディレクトリから見た相対パスです。今回はDocker composeを使ってイメージビルドを行うので、docker-compose.ymlから見た相対パスになっています。 COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer Laravelを使うためComposerをインストールします。 この書き方によりマルチステージビルドという方法でインストールされます。 ※マルチステージビルドという方法はイメージの軽量化に役立つようです。 公式ドキュメント:Use multi-stage builds WORKDIR /app コンテナを起動している時に $ docker-compose exec コンテナ名 bash というコマンドを実行すると、コンテナの中でbashを実行することができるのですが、 WORKDIRはその時のカレントディレクトリを指定しています。 設定ファイル(php.ini) COPY ./docker/app/php.ini /usr/local/etc/php/php.ini で出てきたPHPの設定ファイル php.iniを作成します。 作成したファイルの中身がこちらです。 /docker//app/php.ini zend.exception_ignore_args = off expose_php = on max_execution_time = 30 max_input_vars = 1000 upload_max_filesize = 64M post_max_size = 128M memory_limit = 256M error_reporting = E_ALL display_errors = on display_startup_errors = on log_errors = on error_log = /var/log/php/php-error.log default_charset = UTF-8 [Date] date.timezone = Asia/Tokyo [mysqlnd] mysqlnd.collect_memory_statistics = on [Assertion] zend.assertions = 1 [mbstring] mbstring.language = Japanese こちらの記事の開発用php.iniをまるっとお借りしました。 開発用 / 本番用の設定例と、項目ごとの説明も載っていて面白かったので、ぜひご覧ください。 参考記事:PHP7.4 ぼくのかんがえたさいきょうのphp.ini - Qiita PHPコンテナを起動する ここまででPHPのコンテナの準備が出来たので、実際に起動してみます。 docker-sompose.ymlのあるディレクトリで以下のコマンドを実行します。 $ docker-compose up -d --build docker compose up は docker-compose.yml に定義したサービスを起動します。 -d 「デタッチド」モードでコンテナを起動します。 (デフォルトは「アタッチド」モードで全てのコンテナログを画面上に表示する。「デタッチド」モードではバックグラウンドで動作する。) -build コンテナの開始前にイメージをビルドします。 (特に変更がない場合はキャッシュが使用される。) ※ $ docker-compose build → $ docker-compose up -d を順に行うのと同じです。 起動したコンテナを確認する 以下のコマンドで起動中のコンテナを一覧で確認することができます。 $ docker-compose ps NAME COMMAND SERVICE STATUS PORTS docker_sample-app-1 "docker-php-entrypoi…" app running 9000/tcp STATUSがrunningになっていれば正常に起動しています。 今はPHPのコンテナしか作っていないので1つだけ表示されていますが、この後nginx, MySQLのコンテナを作り、最終的に3つのコンテナが表示されるようにします。 ここで今作業しているディレクトリの構成を確認してみます。 $ tree . ├── src // 作成された! ├── docker │ ├── app │ │ ├── Dockerfile │ │ └── php.ini └── docker-compose.yml するとdocker-compose.ymlに書いたバインドマウントの以下の部分を受けて、コンテナを起動したときに自動でsrcディレクトリが作成されたことが確認できます。(同様にコンテナ内にもappディレクトリが作成されています。) volumes: - ./src/:/app コンテナの中に入ってみる コンテナを起動中に以下のコマンドを実行すると、コンテナの中に入ってbashを実行することができます。 $ docker-compose exec app bash // appの部分はサービス名を指定する これで今コンテナの中に入れたので、Dockerfileの記述通りにコンテナが作られているか、またPHP・Composer・インストールした拡張機能が使えるか確認していきます。 // Dockerfileの「WORKDIR /app」で指定したカレントディレクトリ通りか確認 [app]:/app$ pwd /app // PHPのバージョン確認 [app]:/app$ php -v PHP 8.0.15 (cli) (built: Jan 26 2022 17:38:36) ( NTS ) Copyright (c) The PHP Group Zend Engine v4.0.15, Copyright (c) Zend Technologies // Composerのバージョン確認 [app]:/app$ composer -v ______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ /_/ Composer version 2.0.14 2021-05-21 17:03:37 // gitのバージョン確認 [app]:/app$ git --version git version 2.30.2 // インストール済の拡張機能の一覧 [app]:/app$ php -m [PHP Modules] bcmath intl pdo_mysql zip // たくさん出てくるので他は省略 // php.iniがコピー出来ているか確認 [app]:/app$ cat /usr/local/etc/php/php.ini zend.exception_ignore_args = off expose_php = on max_execution_time = 30 max_input_vars = 1000 upload_max_filesize = 64M post_max_size = 128M memory_limit = 256M error_reporting = E_ALL display_errors = on display_startup_errors = on log_errors = on error_log = /var/log/php/php-error.log default_charset = UTF-8 [Date] date.timezone = Asia/Tokyo [mysqlnd] mysqlnd.collect_memory_statistics = on [Assertion] zend.assertions = 1 [mbstring] mbstring.language = Japaneseroot@0e3ba825df88 確認できたのでコンテナを抜けます。 $ exit // もしくは ctrl + d コンテナの外からコマンドを実行する 上記のコンテナの中で実行したコマンドは、 $ docker-compose exec サービス名 実行したいコマンド でコンテナの外から実行することもできます。(コンテナが起動中に限る) バインドマウントの挙動を確認する コンテナの外からコマンドが実行できるという確認も兼ねて、バインドマウントの動きを見る為、試しに以下のコマンドを実行してみます。 // コンテナ内の/app配下にファイルを作ってみる $ docker-compose exec app touch sample.php $ docker-compose exec app pwd /app $ docker-compose exec app ls sample.php コンテナ内の/app配下にファイルを作成しました。 この/appという場所は、docker-compose.ymlに書いた以下の記述の通りにバインドマウントされています。 volumes: - ./src/:/app これにより、プロジェクトディレクトリ配下の/srcにもsample.phpが作成されています。 $ ls src sample.php 以上より、コンテナ内の /app に対して行ったことが、プロジェクトの /src に反映していることが分かりました。 では次に /src への変更がコンテナ内の /app に対しても反映するか試してみます。 /src/sample.php をエディタで開いてファイルに hello と書きこみ、以下のコマンドを実行します。 $ docker-compose exec app cat sample.php hello // この時permission errorが出たら権限を変更する $ sudo chmod -R 777 ./src するとコンテナ内の ./app/sample.php も編集されていることがわかります。 このようにバインドマウントにより、ホスト側のディレクトリがコンテナ内へマウント出来ていることも確認できました。 試しに作成したファイルは不要なので消しておきます。 $ rm src/sample.php nginxのコンテナ(webサーバー) webサーバーとなるnginxのコンテナを作成します。 PHPコンテナのときと同じく、 docker-compose.ymlへの記述 nginxコンテナ用のDockerfile nginxコンテナ用の設定ファイル(default.conf) の流れで説明します。 docker-compose.yml(nginx) 既に作成しているdocker-compose.ymlに、nginxのコンテナについての部分を追記します。 docker-compose.yml services: api: // 中略 web: // サービス名 build: context: . dockerfile: ./docker/web/Dockerfile ports: - 8081:80 depends_on: - app volumes: - ./src/:/app 解説していきます。 build: ・volumes: ここはPHPコンテナと同様なので説明は省きます。 ports: ホスト側とコンテナ間のポート番号の対応付けを設定します。 書き方は ホスト側のポート番号 : コンテナのポート番号です。 ※今回ホスト側(自分のPC)は既に他の開発で使っているポートとの兼ね合いで 8081 を使いました。コンテナ側はnginxのデフォルトのポート番号である 80 にしています。 depends_on: サービスの起動順序を制御します。 web の depends_on に app と書いているので、 app → web の順に起動するように指定しています。 ※但しこの記述なしで $ docker-compose up -d --build をしてみても私の環境では全く問題なく動きました。が、サービス同士の依存関係を明示的に記すという意味でも書いておくに越したことはないという判断で書いています。 ※ nginxとphp間でTCPによるfpm接続についてや、depends_on オプションについては以下の記事がすごく勉強になったので是非読んでみてください。 参考記事:【docker-compose】depends_onとサービス名解決にまつわるエトセトラ - Qiita Dockerfile(nginx) 作成するDockerfileの全文はこちらです。 /docker/web/Dockerfile FROM nginx:1.20-alpine ENV TZ Asia/Tokyo COPY ./docker/web/default.conf /etc/nginx/conf.d/default.conf FROM , ENV , COPY の意味はPHPコンテナのDockerfileと同様なので詳しい説明は省略し、このファイルで設定していることを簡単にまとめます。 nginx公式のイメージ(Alpineベース)をベースイメージに使用 Nginx - Official Image | Docker Hub 参考記事:Dockerでよく利用されているAlpineは他のLinuxディストリビューションと比べて、どれだけ軽量なのか - プログラミングは芸術だ! 環境変数のタイムゾーンを設定する nginxの設定ファイル(default.conf)をコンテナ内にバインドマウント ※ちなみにnginxは1.18, 1.20などの偶数バージョンが安定バージョンであり、安定バージョンの使用を推奨されています。 公式ドキュメント:Installing NGINX Open Source 設定ファイル(default.conf) ./docker/web/default.confを作成します。 Laravel公式に用意されているnginxの設定例をべースに使います。 Laravel 8.x デプロイ root とfastcgi_passの設定のみ、このプロジェクトに合わせて書き換えています。 /docker/web/default.conf server { listen 80; server_name example.com; root /app/public; // 書き換え add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; index 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 app:9000; // 書き換え fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } root リクエストのルートディレクトリです。 root /app/public; と書いたので、 localhost:8081(docker-compose.ymlで設定したポート番号)にアクセスすると /app/publicを見に行きます。 fastcgi_pass FastCGIサーバーのアドレスです。 ※FastCGI:Webサーバ上で動くプログラムを一度起動したらしばらく待機させることによって、プログラムの開始と終了にかかる手間を減らし、動きを速くしたりWebサーバの負荷を軽減することができる仕組み。 app:9000; と書いたので、appコンテナの9000番ポートを指定しています。 nginxコンテナを起動する nginxのコンテナの準備が出来たので、また実際に起動してみます。 docker-sompose.ymlのあるディレクトリで以下のコマンドを実行します。 $ docker-compose up -d --build $ docker-compose ps NAME COMMAND SERVICE STATUS PORTS docker_sample-app-1 "docker-php-entrypoi…" app running 9000/tcp docker_sample-web-1 "/docker-entrypoint.…" web running 0.0.0.0:8081->80/tcp api(PHPのコンテナ)、web(nginxのコンテナ)の2つが起動できました。 またdocker_sample-web-1の PORTS が 0.0.0.0:8081->80/tcp となっており、ホスト上の8081番ポートをコンテナの80番ポートへ割り当てられていることも確認できます。 コンテナの動作確認 nginxのバージョンを確認します。 $ docker-compose exec web nginx -v nginx version: nginx/1.20.2 コンテナの中に入ってみます。 $ docker-compose exec web bash OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "bash": executable file not found in $PATH: unknown するとエラーになりました。 Alpineをベースとすると bash は使えず、 ash や sh は使えるようです。 $ docker-compose exec web ash [web]:/ $ pwd / 無事コンテナの中に入れました。 webサーバーとしての動作確認 リクエストに対してファイルを返しブラウザで表示できる nginxのコンテナからPHPのコンテナへphpを実行させることができる 上記2点を確認します。 $ mkdir src/public $ touch src/public/test.php test.phpを以下のように編集します。 /src/public/test.php <?php echo 'test.phpです'; phpinfo(); http://localhost:8081/test.php にアクセスすると以下のように表示され、webサーバーが正しく動作していることが確認できます。 試しに作成したファイルは不要なので消しておきます。 $ rm -rf src/* MySQLのコンテナ(データベース) データベースのMySQLコンテナを作成します。 以下の流れで説明します。 docker-compose.ymlへの記述 MySQLコンテナ用のDockerfile MySQLコンテナ用の設定ファイル(my.conf) docker-compose.yml(MySQL) 既に作成しているdocker-compose.ymlに、MySQLのコンテナについての部分を追記します。 docker-compose.yml services: // 中略 db: // サービス名 build: context: . dockerfile: ./docker/db/Dockerfile ports: - 3306:3306 environment: MYSQL_DATABASE: database MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password TZ: 'Asia/Tokyo' volumes: - mysql-volume:/var/lib/mysql volumes: mysql-volume: build: ・ ports: 既出の通りです。 enviroment: 環境変数の設定です。 ※名前やDB名・ユーザー名・パスワードは好きなものを設定します。 ※実際のプロジェクト管理では、環境変数は .env に書いて .gitignore にするなどして、重要な情報が公開されないようにします。 MYSQL_DATABASE:DB名 MYSQL_USER:ユーザー名 MYSQL_PASSWORD:パスワード MYSQL_ROOT_PASSWORD:ルート権限のパスワード TZ:時間設定(Time Zone) volumes: 考え方はPHPやnginxのコンテナ同様ですが、先ほどまではホスト側のディレクトリを書いていたところに mysql-volume と書いています。 これにより mysql-colume という名前で作成した名前付きボリュームとコンテナ内を紐づけています。 Docker Volume Volumeとは、コンテナを破棄してもデータを永続的に保存できるように、コンテナ外に提供されているデータの保存領域です。 Dockerの管理下でホスト上にストレージ領域を確保しており、Linux なら /var/lib/docker/volumes/以下にあります。 参考記事:Docker、ボリューム(Volume)について真面目に調べた - Qiita なぜVolumeが必要なのか? コンテナが起動している間はDBのレコードは保存された状態が続きますが、例えば以下のようなコマンドでコンテナを新しく作り直したとするとデータベースの情報はゼロに戻ってしまいます。 // コンテナ削除 $ docker-compose down // コンテナ起動 $ docker-compose up -d これでは困るのでコンテナを破棄してもデータを残したい、、、というときにVolumesを使ってデータの永続化を行います。 ※ボリュームには名前付きボリュームと匿名ボリュームがありますが、通常は管理しやすい名前付きボリュームを使うと良いかと思います。 名前付きボリュームを作成する場合は、データの永続化対象のコンテナに対して volumes: オプションでバインドマウントを行うだけでなく、以下のようにdocker-compose.ymlのトップレベルでボリューム名を定義します。 docker-compose.yml volumes: - mysql-volume: Dockerfile(MySQL) 作成するDockerfileの全文はこちらです。 /docker/db/Dockerfile FROM mysql:8.0 COPY ./docker/db/my.cnf /etc/my.cnf 内容を簡単にまとめると、 公式のMySQLイメージをベースイメージに使用 Mysql - Official Image | Docker Hub MySQLの設定ファイル(my.cnf)をコンテナ内にバインドマウント ※ここで使用しているイメージではM1 Macでは動作しないという情報が見られました。どうやらOracleのMySQLチームがメンテしている mysql/mysql-server のイメージだと動作するようです。 mysql-server | Docker Hub 設定ファイル(my.conf) ./dicker/db/my.cnfを作成します。 色んな記事で作成されているmy.cnfを参考にさせていただきながら書きました。 参考記事:【Docker】docker-composeでmysqlのコンテナを立てる 文字コード タイムゾーン ログ の設定を行っています。 /docker/db/my.conf [mysqld] # character character_set_server = utf8mb4 collation_server = utf8mb4_0900_ai_ci # timezone default-time-zone = SYSTEM log_timestamps = SYSTEM # Error Log log-error = mysql-error.log # Slow Query Log slow_query_log = 1 slow_query_log_file = mysql-slow.log long_query_time = 1.0 log_queries_not_using_indexes = 0 # General Log general_log = 1 general_log_file = mysql-general.log [mysql] default-character-set = utf8mb4 [client] default-character-set = utf8mb4 MySQLコンテナを起動する MySQLのコンテナの準備が出来たので、また実際に起動してみます。 docker-sompose.ymlのあるディレクトリで以下のコマンドを実行します。 $ docker-compose up -d --build $ docker-compose ps NAME COMMAND SERVICE STATUS PORTS docker_sample-app-1 "docker-php-entrypoi…" app running 9000/tcp docker_sample-db-1 "docker-entrypoint.s…" db running 0.0.0.0:3306->3306/tcp docker_sample-web-1 "/docker-entrypoint.…" web running 0.0.0.0:8081->80/tcp api(PHPのコンテナ)、web(nginxのコンテナ)、db(MySQLのコンテナ)の3つが起動できました。 コンテナの動作確認 MySQLのバージョンを確認します。 $ docker compose exec db mysql -V mysql Ver 8.0.28 for Linux on x86_64 (MySQL Community Server - GPL) ※この後Laravelのプロジェクトを作成したら、このDBとLaravelを接続します。 そしてマイグレーションを行ってDBにテーブルを作成してから、MySQLにログインしてDBを使う動作確認をしたいと思います。 Laravelのインストール Laravelプロジェクトの作成 LEMP環境が構築できたので、Laravelのアプリケーションを作っていきます。 appコンテナに入り、Laravelをインストールします。 $ docker compose exec app bash [app]:/app$ composer create-project --prefer-dist "laravel/laravel=8.*" . [app]:/app$ php artisan -v Laravel Framework 8.81.0 コンテナ内の/app配下にLaravelのプロジェクトが新規作成され、ホスト側の/src配下にも同じくLaravelのプロジェクトが出来ました。 localhost:8081にアクセスして、ブラウザでもLaravelのウェルカムページが表示できることを確認します。 DB接続 appコンテナ(Laravel)からdbコンテナ(MySQL)へ接続する設定を行います。 Laravelではデータベースへの接続設定を .env ファイルに定義しているので、 /src/.env のDBの部分を以下のように修正します。 /src/.env DB_CONNECTION=mysql DB_HOST=db // MySQLコンテナのサービス名 DB_PORT=3306 DB_DATABASE=database DB_USERNAME=root DB_PASSWORD=passwor DB_HOST にはMySQLコンテナのサービス名を指定します。 その他の項目もMySQLコンテナで設定した値(今回はdocker-compose.ymlのenviromentで定義)と同じ値を指定します。 DBに接続出来ているか確認する為、以下のコマンドを実行してマイグレーションを行います。 $ docker compose exec app bash [app]:/app$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (55.42ms) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (51.11ms) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (45.12ms) Migrating: 2019_12_14_000001_create_personal_access_tokens_table Migrated: 2019_12_14_000001_create_personal_access_tokens_table (75.74ms) MySQLを使ってみる MySQLのコンテナに入ってDBを確認してみます。 $ docker-compose exec db bash [db]:/$ mysql -u root -p // パスワードを求められるので入力 [db] mysql> use database; [db] mysql> show tables; +------------------------+ | Tables_in_database | +------------------------+ | failed_jobs | | migrations | | password_resets | | personal_access_tokens | | users | +------------------------+ 5 rows in set (0.00 sec) 先ほどマイグレーションを実行したので、Laravelのデフォルトで用意されているマイグレーションファイル通りにテーブルが作成されていることが確認できました。 最後に これでDocker(Docker Compose)を使ったLEMP環境の構築が完了です。 今回作成した環境は非常にシンプルなものなので、業務で使うとなるともっと設定を細やかに行ったり、開発環境・ステージング環境・本番環境それぞれの設定ファイルを用意して設定を切り替えたりといった作業が必要になるかと思いますが、仕組みが分かればあとは全てこの延長にあるのかなと思います。 またいずれ環境ごとの設定ファイル切り替えだったり、あとはNodeのコンテナを使ってNext.jsの環境構築もやってみたいです。 参考記事
- 投稿日:2022-01-31T08:28:14+09:00
DockerでPHP(Laravel)+ nginx + MySQLのLEMP環境を構築する
概要 Docker, Docker Compose を使って、PHP(Laravel) + nginx + MySQLのLEMP環境を構築する記事です。 検索するとDockerfileやdocker-compose.ymlの書き方については色んな方が記事を書いてくださっていて、動く環境を作ること自体は難しくありませんでした。 ですが、筆者はひとつコンテナを作っては動作確認していくという過程を経てすごく理解が深まったなと思うので、ファイルの書き方だけでなく動作確認したことやその結果を含めて記事に残しておきたいと思います。 ↓ 完成後のリポジトリはこちらです。 全体像 最終的なディレクトリ構成は以下の通りです。 全コンテナを管理するdocker-compose.ymlがトップレベルにあり、同じくトップレベルにあるdockerディレクトリ配下に各コンテナのDockerfileや設定ファイルを置いています。 tree docker_sample/ ├── src // Laravelプロジェクトのソースコード ├── docker │ ├── app // PHPコンテナ │ │ ├── Dockerfile │ │ └── php.ini │ ├── db // MySQLコンテナ │ │ ├── Dockerfile │ │ └── my.cnf │ └── web // nginxコンテナ │ ├── Dockerfile │ └── default.conf └── docker-compose.yml // 全コンテナの管理 早速一つずつコンテナを作っていきます。 PHPのコンテナ(Laravelの開発環境) まずはLaravelの開発環境を構築するための、PHPのコンテナを作成します。 docker-compose.ymlへの記述 PHPコンテナ用のDockerfile PHPコンテナ用の設定ファイル(php.ini) について順に説明します。 docker-compose.yml(PHP) docker-compose.ymlのうち、PHPコンテナについての記述は以下の通りです。 ※docker-compose.ymlはインデントが意味を持つので注意。 docker-compose.yml version: "3.9" services: app: // サービス名 build: context: . dockerfile: ./docker/app/Dockerfile volumes: - ./src/:/app version: これはPHPコンテナについてではなく docker-compose.yml の先頭に書く設定ですが、Composeファイルのバージョンを表しています。 今回は最新の 3.9 を使います。(最新のバージョンは下記の公式サイトを参照) Compose file build: ビルドコンテキストを指定します。 context:ビルドコンテキスト(buildを実行する場所)の設定 dockerfile:buildするDockerfileまでのパス(docker-compose.ymlから見た相対パス) 参考記事: docker-compose.ymlのbuild設定はとりあえずcontextもdockerfileも埋めとけって話 - Qiita volumes: ホスト側の ./src/をコンテナ側の /app にマウントするという意味になります。 ※ここで services: の中に書いているこの volumes: は バインドマウント を行っています。 参考記事:Dockerのマウント3種類についてわかったことをまとめる - Qiita 何が起きているかは実際の挙動を見てみた方が分かりやすいと思うので、後ほどまた動作確認します。 Dockerfile(PHP) Dockerfileはテキストファイルであり、Dockerイメージを作り上げるために実行する命令をこのファイルに書きます。 まず作成するDockerfileの全文がこちらです。 /docker/app/Dockerfile FROM php:8.0-fpm ENV TZ Asia/Tokyo RUN apt-get update && \ apt-get install -y git unzip libzip-dev libicu-dev libonig-dev && \ docker-php-ext-install intl pdo_mysql zip bcmath COPY ./docker/app/php.ini /usr/local/etc/php/php.ini COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer WORKDIR /app 一つずつ説明します。 FROM php:8.0-fpm FROMではイメージをビルドするためのベースイメージを設定します。 書き方は FROM イメージ名:タグ名 です。 ここではDocker HubからPHP公式のイメージをベースとして指定しています。 Php - Official Image | Docker Hub ENV TZ Asia/Tokyo ENVはコンテナ内のサーバー環境変数を設定します。 RUN apt-get update && \ apt-get install -y git unzip libzip-dev libicu-dev libonig-dev && \ docker-php-ext-install intl pdo_mysql zip bcmath RUN にはコンテナビルド時に実行するコマンドを書きます。 && で複数のコマンドをつなぎ、 \ で改行します。 ※ && と \ を使うことで複数コマンドを1レイヤーにまとめることができ、公式でもベストプラクティスのTipsとして挙げられています。 Intro Guide to Dockerfile Best Practices - Docker Blog apt-get update :インストール可能なパッケージの「一覧」を更新 apt-get -y install:パッケージをインストール docker-php-ext-install:PHPの拡張ライブラリをインストール ※Laravelのインストールや開発に必要な(もしくは便利な)パッケージや拡張ライブラリをインストールしています。 ※試しにこれらを全くインストールせず手順を進めてみると、コンテナを起動することはできますが、その後のLaravelプロジェクトを作成する時に大量のエラーに遭遇しました(笑) COPY ./docker/app/php.ini /usr/local/etc/php/php.ini ローカルで(後ほど)作成する php.ini (PHPの設定ファイル)をDockerコンテナ内にコピーします。 書き方は COPY [ローカル側のパス] [コンテナ側のパス]です。 ※ローカル側のパスは、Dockerfileから見てではなくbuildコマンドを実行するディレクトリから見た相対パスです。今回はDocker composeを使ってイメージビルドを行うので、docker-compose.ymlから見た相対パスになっています。 COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer Laravelを使うためComposerをインストールします。 この書き方によりマルチステージビルドという方法でインストールされます。 ※マルチステージビルドという方法はイメージの軽量化に役立つようです。 公式ドキュメント:Use multi-stage builds WORKDIR /app コンテナを起動している時に $ docker-compose exec コンテナ名 bash というコマンドを実行すると、コンテナの中でbashを実行することができるのですが、 WORKDIRはその時のカレントディレクトリを指定しています。 設定ファイル(php.ini) COPY ./docker/app/php.ini /usr/local/etc/php/php.ini で出てきたPHPの設定ファイル php.iniを作成します。 作成したファイルの中身がこちらです。 /docker//app/php.ini zend.exception_ignore_args = off expose_php = on max_execution_time = 30 max_input_vars = 1000 upload_max_filesize = 64M post_max_size = 128M memory_limit = 256M error_reporting = E_ALL display_errors = on display_startup_errors = on log_errors = on error_log = /var/log/php/php-error.log default_charset = UTF-8 [Date] date.timezone = Asia/Tokyo [mysqlnd] mysqlnd.collect_memory_statistics = on [Assertion] zend.assertions = 1 [mbstring] mbstring.language = Japanese こちらの記事の開発用php.iniをまるっとお借りしました。 開発用 / 本番用の設定例と、項目ごとの説明も載っていて面白かったので、ぜひご覧ください。 参考記事:PHP7.4 ぼくのかんがえたさいきょうのphp.ini - Qiita PHPコンテナを起動する ここまででPHPのコンテナの準備が出来たので、実際に起動してみます。 docker-sompose.ymlのあるディレクトリで以下のコマンドを実行します。 $ docker-compose up -d --build docker compose up は docker-compose.yml に定義したサービスを起動します。 -d 「デタッチド」モードでコンテナを起動します。 (デフォルトは「アタッチド」モードで全てのコンテナログを画面上に表示する。「デタッチド」モードではバックグラウンドで動作する。) --build コンテナの開始前にイメージをビルドします。 (特に変更がない場合はキャッシュが使用される。) ※ $ docker-compose build → $ docker-compose up -d を順に行うのと同じです。 起動したコンテナを確認する 以下のコマンドで起動中のコンテナを一覧で確認することができます。 $ docker-compose ps NAME COMMAND SERVICE STATUS PORTS docker_sample-app-1 "docker-php-entrypoi…" app running 9000/tcp STATUSがrunningになっていれば正常に起動しています。 今はPHPのコンテナしか作っていないので1つだけ表示されていますが、この後nginx, MySQLのコンテナを作り、最終的に3つのコンテナが表示されるようにします。 ここで今作業しているディレクトリの構成を確認してみます。 $ tree . ├── src // 作成された! ├── docker │ ├── app │ │ ├── Dockerfile │ │ └── php.ini └── docker-compose.yml するとdocker-compose.ymlに書いたバインドマウントの以下の部分を受けて、コンテナを起動したときに自動でsrcディレクトリが作成されたことが確認できます。(同様にコンテナ内にもappディレクトリが作成されています。) volumes: - ./src/:/app コンテナの中に入ってみる コンテナを起動中に以下のコマンドを実行すると、コンテナの中に入ってbashを実行することができます。 $ docker-compose exec app bash // appの部分はサービス名を指定する これで今コンテナの中に入れたので、Dockerfileの記述通りにコンテナが作られているか、またPHP・Composer・インストールした拡張機能が使えるか確認していきます。 // Dockerfileの「WORKDIR /app」で指定したカレントディレクトリ通りか確認 [app]:/app$ pwd /app // PHPのバージョン確認 [app]:/app$ php -v PHP 8.0.15 (cli) (built: Jan 26 2022 17:38:36) ( NTS ) Copyright (c) The PHP Group Zend Engine v4.0.15, Copyright (c) Zend Technologies // Composerのバージョン確認 [app]:/app$ composer -v ______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ /_/ Composer version 2.0.14 2021-05-21 17:03:37 // gitのバージョン確認 [app]:/app$ git --version git version 2.30.2 // インストール済の拡張機能の一覧 [app]:/app$ php -m [PHP Modules] bcmath intl pdo_mysql zip // たくさん出てくるので他は省略 // php.iniがコピー出来ているか確認 [app]:/app$ cat /usr/local/etc/php/php.ini zend.exception_ignore_args = off expose_php = on max_execution_time = 30 max_input_vars = 1000 upload_max_filesize = 64M post_max_size = 128M memory_limit = 256M error_reporting = E_ALL display_errors = on display_startup_errors = on log_errors = on error_log = /var/log/php/php-error.log default_charset = UTF-8 [Date] date.timezone = Asia/Tokyo [mysqlnd] mysqlnd.collect_memory_statistics = on [Assertion] zend.assertions = 1 [mbstring] mbstring.language = Japaneseroot@0e3ba825df88 確認できたのでコンテナを抜けます。 $ exit // もしくは ctrl + d コンテナの外からコマンドを実行する 上記のコンテナの中で実行したコマンドは、 $ docker-compose exec サービス名 実行したいコマンド でコンテナの外から実行することもできます。(コンテナが起動中に限る) バインドマウントの挙動を確認する コンテナの外からコマンドが実行できるという確認も兼ねて、バインドマウントの動きを見る為、試しに以下のコマンドを実行してみます。 // コンテナ内の/app配下にファイルを作ってみる $ docker-compose exec app touch sample.php $ docker-compose exec app pwd /app $ docker-compose exec app ls sample.php コンテナ内の/app配下にファイルを作成しました。 この/appという場所は、docker-compose.ymlに書いた以下の記述の通りにバインドマウントされています。 volumes: - ./src/:/app これにより、プロジェクトディレクトリ配下の/srcにもsample.phpが作成されています。 $ ls src sample.php 以上より、コンテナ内の /app に対して行ったことが、プロジェクトの /src に反映していることが分かりました。 では次に /src への変更がコンテナ内の /app に対しても反映するか試してみます。 /src/sample.php をエディタで開いてファイルに hello と書きこみ、以下のコマンドを実行します。 $ docker-compose exec app cat sample.php hello // この時permission errorが出たら権限を変更する $ sudo chmod -R 777 ./src するとコンテナ内の ./app/sample.php も編集されていることがわかります。 このようにバインドマウントにより、ホスト側のディレクトリがコンテナ内へマウント出来ていることも確認できました。 試しに作成したファイルは不要なので消しておきます。 $ rm src/sample.php nginxのコンテナ(webサーバー) webサーバーとなるnginxのコンテナを作成します。 PHPコンテナのときと同じく、 docker-compose.ymlへの記述 nginxコンテナ用のDockerfile nginxコンテナ用の設定ファイル(default.conf) の流れで説明します。 docker-compose.yml(nginx) 既に作成しているdocker-compose.ymlに、nginxのコンテナについての部分を追記します。 docker-compose.yml services: api: // 中略 web: // サービス名 build: context: . dockerfile: ./docker/web/Dockerfile ports: - 8081:80 depends_on: - app volumes: - ./src/:/app 解説していきます。 build: ・volumes: ここはPHPコンテナと同様なので説明は省きます。 ports: ホスト側とコンテナ間のポート番号の対応付けを設定します。 書き方は ホスト側のポート番号 : コンテナのポート番号です。 ※今回ホスト側(自分のPC)は既に他の開発で使っているポートとの兼ね合いで 8081 を使いました。コンテナ側はnginxのデフォルトのポート番号である 80 にしています。 depends_on: サービスの起動順序を制御します。 web の depends_on に app と書いているので、 app → web の順に起動するように指定しています。 ※但しこの記述なしで $ docker-compose up -d --build をしてみても私の環境では全く問題なく動きました。が、サービス同士の依存関係を明示的に記すという意味でも書いておくに越したことはないという判断で書いています。 ※ nginxとphp間でTCPによるfpm接続についてや、depends_on オプションについては以下の記事がすごく勉強になったので是非読んでみてください。 参考記事:【docker-compose】depends_onとサービス名解決にまつわるエトセトラ - Qiita Dockerfile(nginx) 作成するDockerfileの全文はこちらです。 /docker/web/Dockerfile FROM nginx:1.20-alpine ENV TZ Asia/Tokyo COPY ./docker/web/default.conf /etc/nginx/conf.d/default.conf FROM , ENV , COPY の意味はPHPコンテナのDockerfileと同様なので詳しい説明は省略し、このファイルで設定していることを簡単にまとめます。 nginx公式のイメージ(Alpineベース)をベースイメージに使用 Nginx - Official Image | Docker Hub 参考記事:Dockerでよく利用されているAlpineは他のLinuxディストリビューションと比べて、どれだけ軽量なのか - プログラミングは芸術だ! 環境変数のタイムゾーンを設定する nginxの設定ファイル(default.conf)をコンテナ内にバインドマウント ※ちなみにnginxは1.18, 1.20などの偶数バージョンが安定バージョンであり、安定バージョンの使用を推奨されています。 公式ドキュメント:Installing NGINX Open Source 設定ファイル(default.conf) ./docker/web/default.confを作成します。 Laravel公式に用意されているnginxの設定例をべースに使います。 Laravel 8.x デプロイ root とfastcgi_passの設定のみ、このプロジェクトに合わせて書き換えています。 /docker/web/default.conf server { listen 80; server_name example.com; root /app/public; // 書き換え add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; index 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 app:9000; // 書き換え fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } root リクエストのルートディレクトリです。 root /app/public; と書いたので、 localhost:8081(docker-compose.ymlで設定したポート番号)にアクセスすると /app/publicを見に行きます。 fastcgi_pass FastCGIサーバーのアドレスです。 ※FastCGI:Webサーバ上で動くプログラムを一度起動したらしばらく待機させることによって、プログラムの開始と終了にかかる手間を減らし、動きを速くしたりWebサーバの負荷を軽減することができる仕組み。 app:9000; と書いたので、appコンテナの9000番ポートを指定しています。 nginxコンテナを起動する nginxのコンテナの準備が出来たので、また実際に起動してみます。 docker-sompose.ymlのあるディレクトリで以下のコマンドを実行します。 $ docker-compose up -d --build $ docker-compose ps NAME COMMAND SERVICE STATUS PORTS docker_sample-app-1 "docker-php-entrypoi…" app running 9000/tcp docker_sample-web-1 "/docker-entrypoint.…" web running 0.0.0.0:8081->80/tcp api(PHPのコンテナ)、web(nginxのコンテナ)の2つが起動できました。 またdocker_sample-web-1の PORTS が 0.0.0.0:8081->80/tcp となっており、ホスト上の8081番ポートをコンテナの80番ポートへ割り当てられていることも確認できます。 コンテナの動作確認 nginxのバージョンを確認します。 $ docker-compose exec web nginx -v nginx version: nginx/1.20.2 コンテナの中に入ってみます。 $ docker-compose exec web bash OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "bash": executable file not found in $PATH: unknown するとエラーになりました。 Alpineをベースとすると bash は使えず、 ash や sh は使えるようです。 $ docker-compose exec web ash [web]:/ $ pwd / 無事コンテナの中に入れました。 webサーバーとしての動作確認 リクエストに対してファイルを返しブラウザで表示できる nginxのコンテナからPHPのコンテナへphpを実行させることができる 上記2点を確認します。 $ mkdir src/public $ touch src/public/test.php test.phpを以下のように編集します。 /src/public/test.php <?php echo 'test.phpです'; phpinfo(); http://localhost:8081/test.php にアクセスすると以下のように表示され、webサーバーが正しく動作していることが確認できます。 試しに作成したファイルは不要なので消しておきます。 $ rm -rf src/* MySQLのコンテナ(データベース) データベースのMySQLコンテナを作成します。 以下の流れで説明します。 docker-compose.ymlへの記述 MySQLコンテナ用のDockerfile MySQLコンテナ用の設定ファイル(my.conf) docker-compose.yml(MySQL) 既に作成しているdocker-compose.ymlに、MySQLのコンテナについての部分を追記します。 docker-compose.yml services: // 中略 db: // サービス名 build: context: . dockerfile: ./docker/db/Dockerfile ports: - 3306:3306 environment: MYSQL_DATABASE: database MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password TZ: 'Asia/Tokyo' volumes: - mysql-volume:/var/lib/mysql volumes: mysql-volume: build: ・ ports: 既出の通りです。 enviroment: 環境変数の設定です。 ※名前やDB名・ユーザー名・パスワードは好きなものを設定します。 ※実際のプロジェクト管理では、環境変数は .env に書いて .gitignore にするなどして、重要な情報が公開されないようにします。 MYSQL_DATABASE:DB名 MYSQL_USER:ユーザー名 MYSQL_PASSWORD:パスワード MYSQL_ROOT_PASSWORD:ルート権限のパスワード TZ:時間設定(Time Zone) volumes: 考え方はPHPやnginxのコンテナ同様ですが、先ほどまではホスト側のディレクトリを書いていたところに mysql-volume と書いています。 これにより mysql-colume という名前で作成した名前付きボリュームとコンテナ内を紐づけています。 Docker Volume Volumeとは、コンテナを破棄してもデータを永続的に保存できるように、コンテナ外に提供されているデータの保存領域です。 Dockerの管理下でホスト上にストレージ領域を確保しており、Linux なら /var/lib/docker/volumes/以下にあります。 参考記事:Docker、ボリューム(Volume)について真面目に調べた - Qiita なぜVolumeが必要なのか? コンテナが起動している間はDBのレコードは保存された状態が続きますが、例えば以下のようなコマンドでコンテナを新しく作り直したとするとデータベースの情報はゼロに戻ってしまいます。 // コンテナ削除 $ docker-compose down // コンテナ起動 $ docker-compose up -d これでは困るのでコンテナを破棄してもデータを残したい、、、というときにVolumesを使ってデータの永続化を行います。 ※ボリュームには名前付きボリュームと匿名ボリュームがありますが、通常は管理しやすい名前付きボリュームを使うと良いかと思います。 名前付きボリュームを作成する場合は、データの永続化対象のコンテナに対して volumes: オプションでバインドマウントを行うだけでなく、以下のようにdocker-compose.ymlのトップレベルでボリューム名を定義します。 docker-compose.yml volumes: - mysql-volume: Dockerfile(MySQL) 作成するDockerfileの全文はこちらです。 /docker/db/Dockerfile FROM mysql:8.0 COPY ./docker/db/my.cnf /etc/my.cnf 内容を簡単にまとめると、 公式のMySQLイメージをベースイメージに使用 Mysql - Official Image | Docker Hub MySQLの設定ファイル(my.cnf)をコンテナ内にバインドマウント ※ここで使用しているイメージではM1 Macでは動作しないという情報が見られました。どうやらOracleのMySQLチームがメンテしている mysql/mysql-server のイメージだと動作するようです。 mysql-server | Docker Hub 設定ファイル(my.conf) ./docker/db/my.cnfを作成します。 色んな記事で作成されているmy.cnfを参考にさせていただきながら書きました。 参考記事:【Docker】docker-composeでmysqlのコンテナを立てる 文字コード タイムゾーン ログ の設定を行っています。 /docker/db/my.conf [mysqld] # character character_set_server = utf8mb4 collation_server = utf8mb4_0900_ai_ci # timezone default-time-zone = SYSTEM log_timestamps = SYSTEM # Error Log log-error = mysql-error.log # Slow Query Log slow_query_log = 1 slow_query_log_file = mysql-slow.log long_query_time = 1.0 log_queries_not_using_indexes = 0 # General Log general_log = 1 general_log_file = mysql-general.log [mysql] default-character-set = utf8mb4 [client] default-character-set = utf8mb4 MySQLコンテナを起動する MySQLのコンテナの準備が出来たので、また実際に起動してみます。 docker-sompose.ymlのあるディレクトリで以下のコマンドを実行します。 $ docker-compose up -d --build $ docker-compose ps NAME COMMAND SERVICE STATUS PORTS docker_sample-app-1 "docker-php-entrypoi…" app running 9000/tcp docker_sample-db-1 "docker-entrypoint.s…" db running 0.0.0.0:3306->3306/tcp docker_sample-web-1 "/docker-entrypoint.…" web running 0.0.0.0:8081->80/tcp api(PHPのコンテナ)、web(nginxのコンテナ)、db(MySQLのコンテナ)の3つが起動できました。 コンテナの動作確認 MySQLのバージョンを確認します。 $ docker compose exec db mysql -V mysql Ver 8.0.28 for Linux on x86_64 (MySQL Community Server - GPL) ※この後Laravelのプロジェクトを作成したら、このDBとLaravelを接続します。 そしてマイグレーションを行ってDBにテーブルを作成してから、MySQLにログインしてDBを使う動作確認をしたいと思います。 Laravelのインストール Laravelプロジェクトの作成 LEMP環境が構築できたので、Laravelのアプリケーションを作っていきます。 appコンテナに入り、Laravelをインストールします。 $ docker compose exec app bash [app]:/app$ composer create-project --prefer-dist "laravel/laravel=8.*" . [app]:/app$ php artisan -v Laravel Framework 8.81.0 コンテナ内の/app配下にLaravelのプロジェクトが新規作成され、ホスト側の/src配下にも同じくLaravelのプロジェクトが出来ました。 localhost:8081にアクセスして、ブラウザでもLaravelのウェルカムページが表示できることを確認します。 DB接続 appコンテナ(Laravel)からdbコンテナ(MySQL)へ接続する設定を行います。 Laravelではデータベースへの接続設定を .env ファイルに定義しているので、 /src/.env のDBの部分を以下のように修正します。 /src/.env DB_CONNECTION=mysql DB_HOST=db // MySQLコンテナのサービス名 DB_PORT=3306 DB_DATABASE=database DB_USERNAME=root DB_PASSWORD=passwor DB_HOST にはMySQLコンテナのサービス名を指定します。 その他の項目もMySQLコンテナで設定した値(今回はdocker-compose.ymlのenviromentで定義)と同じ値を指定します。 DBに接続出来ているか確認する為、以下のコマンドを実行してマイグレーションを行います。 $ docker compose exec app bash [app]:/app$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (55.42ms) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (51.11ms) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (45.12ms) Migrating: 2019_12_14_000001_create_personal_access_tokens_table Migrated: 2019_12_14_000001_create_personal_access_tokens_table (75.74ms) MySQLを使ってみる MySQLのコンテナに入ってDBを確認してみます。 $ docker-compose exec db bash [db]:/$ mysql -u root -p // パスワードを求められるので入力 [db] mysql> use database; [db] mysql> show tables; +------------------------+ | Tables_in_database | +------------------------+ | failed_jobs | | migrations | | password_resets | | personal_access_tokens | | users | +------------------------+ 5 rows in set (0.00 sec) 先ほどマイグレーションを実行したので、Laravelのデフォルトで用意されているマイグレーションファイル通りにテーブルが作成されていることが確認できました。 最後に これでDocker(Docker Compose)を使ったLEMP環境の構築が完了です。 今回作成した環境は非常にシンプルなものなので、業務で使うとなるともっと設定を細やかに行ったり、開発環境・ステージング環境・本番環境それぞれの設定ファイルを用意して設定を切り替えたりといった作業が必要になるかと思いますが、仕組みが分かればあとは全てこの延長にあるのかなと思います。 またいずれ環境ごとの設定ファイル切り替えだったり、あとはNodeのコンテナを使ってNext.jsの環境構築もやってみたいです。 参考記事