[Laravel]MySQL+Nginx+PHPの開発環境をDockerで構築する
はじめに
MySQL、Nginx、PHPを使用したLaravelの開発環境をDockerで構築していきます。
環境
Docker Desktop
PHP 8.x
MySQL 8.x
Nginx
tl;dr
- Dockerfileを作成する
- Nginxの設定ファイルを作成する
- docker-compose.ymlを作成する
- PHPの設定ファイルを作成する
- Composerの設定ファイルを作成する
- コンテナをビルドする
- 新規Laravelプロジェクトを作成する
- npmをインストールする
- artisanコマンドを実行する
ディレクトリーの構造:
project-root/
|-- docker-compose.yml
|-- nginx/
| `-- default.conf
|-- src/
|-- public/
| |-- app/
| `-- ...
|-- .gitignore
|-- composer.json
|-- phpunit.xml
|-- server.php
|-- php.Dockerfile
|-- nginx.Dockerfile
|-- mysql/
nginx.Dockerfile
を作成する
FROM nginx:stable-alpine
ENV NGINXUSER=laravel
ENV NGINXGROUP=laravel
RUN mkdir -p /var/www/html/public
ADD nginx/default.conf /etc/nginx/conf.d/default.conf
RUN sed -i "s/user www-data/user laravel/g" /etc/nginx/nginx.conf
RUN adduser -g ${NGINXGROUP} -s /bin/sh -D ${NGINXUSER}
Nginxの公式イメージ(nginx:stable-alpine
)をベースにし、laravelユーザーとlaravelグループを作成し、Nginxの設定を調整しています。
FROM nginx:stable-alpine
: Nginxの安定したAlpine Linux版をベースとして使用します。
ENV NGINXUSER=laravel
: Nginxが使用するユーザー名をlaravel
に設定します。
ENV NGINXGROUP=laravel
: Nginxが使用するグループ名をlaravel
に設定します。
RUN mkdir -p /var/www/html/public
: Laravelアプリケーションの公開ディレクトリを作成します。
ADD nginx/default.conf /etc/nginx/conf.d/default.conf
: Nginx設定ファイル(default.conf
)をNginxの設定ディレクトリに追加します。
RUN sed -i "s/user www-data/user laravel/g" /etc/nginx/nginx.conf
: Nginxのメインの設定ファイルであるnginx.conf
内のwww-data
ユーザーをlaravel
に変更します。
RUN adduser -g ${NGINXGROUP} -s /bin/sh -D ${NGINXUSER}
: laravel
ユーザーとそのグループを作成します。
これにより、Nginxのユーザーとグループがlaravel
に変更され、NginxがLaravelアプリケーションの公開ディレクトリを正しくサーブできるようになります。
nginx/nginx.conf
を作成する
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
listen 80;
: サーバーブロックはポート80でリクエストを待ち受けます。
index index.php index.html;
: indexファイルのデフォルト設定を指定しています。index.php
が存在する場合はそれが優先され、存在しない場合はindex.html
が試されます。
server_name localhost;
: サーバーの名前をlocalhost
に設定しています。
error_log /var/log/nginx/error.log;
とaccess_log /var/log/nginx/access.log;
: エラーログとアクセスログの場所を指定しています。
root /var/www/html/public;
: ドキュメントルートをLaravelアプリケーションのpublic
ディレクトリに設定します。
docker-compose.yml
を作成する
version: '3.9'
services:
nginx:
build:
context: .
dockerfile: nginx.Dockerfile
ports:
- 80:80
volumes:
- ./src:/var/www/html
depends_on:
- mysql
- php
mysql:
image: mysql:8.0
ports:
- 3306:3306
environment:
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
volumes:
- ./mysql:/var/lib/mysql
php:
build:
context: .
dockerfile: php.Dockerfile
volumes:
- ./src:/var/www/html
使用するサービスを定義しています。
-
nginx
:- Nginxのビルドは、カレントディレクトリの
nginx.Dockerfile
を使用します。 - ホストのポート80をコンテナのポート80にマッピングします。
-
./src
ディレクトリをコンテナ内の/var/www/html
にマウントします。 - 依存しているサービスとして
mysql
とphp
を指定しています。
- Nginxのビルドは、カレントディレクトリの
-
mysql
:- MySQLの公式イメージ(
mysql:8.0
)を使用します。 - ホストのポート3306をコンテナのポート3306にマッピングします。
-
MYSQL_DATABASE
、MYSQL_USER
、MYSQL_PASSWORD
、MYSQL_ROOT_PASSWORD
を環境変数として指定しています。 -
./mysql
ディレクトリをコンテナ内の/var/lib/mysql
にマウントします。(プロジェクトのルートにmysqlディレクトリーを作成します。)
- MySQLの公式イメージ(
-
php
:- PHPのビルドは、カレントディレクトリの
php.Dockerfile
を使用します。 -
./src
ディレクトリをコンテナ内の/var/www/html
にマウントします。これはLaravelアプリのルートディレクトリです。
- PHPのビルドは、カレントディレクトリの
-
composer
:-
./src:/var/www/html
は、ホストマシンの./src
ディレクトリをコンテナ内の/var/www/html
にマウントします。Composerはこのディレクトリ内で依存関係を解決します。 -
working_dir: /var/www/html
: コンテナ内の作業ディレクトリを指定します。
-
php.Dockerfile
を作成する
FROM php:8-fpm-alpine
ENV PHPGROUP=laravel
ENV PHPUSER=laravel
RUN adduser -g ${PHPGROUP} -s /bin/sh -D ${PHPUSER}
RUN sed -i "s/user = www-data = ${PHPUSER}/g" /usr/local/etc/php-fpm.d/www.conf
RUN sed -i "s/group = www-group = ${PHPGROUP}/g" /usr/local/etc/php-fpm.d/www.conf
RUN mkdir -p /var/www/html/public
RUN docker-php-ext-install pdo pdo_mysql
CMD ["php-fpm", "-F", "-y", "/usr/local/etc/php-fpm.conf", "-R"]
ENV PHPGROUP=laravel
と ENV PHPUSER=laravel
: ユーザーとグループの名前を設定しています。
RUN adduser -g ${PHPGROUP} -s /bin/sh -D ${PHPUSER}
:
-
adduser
コマンドを使用して、指定したグループとユーザーを追加します。 -
-g
オプションはグループを指定し、-s
オプションはデフォルトのシェルを指定します。 -
-D
オプションはユーザーにパスワードを設定しないようにします。
RUN sed -i "s/user = www-data = ${PHPUSER}/g" /usr/local/etc/php-fpm.d/www.conf
と RUN sed -i "s/group = www-data = ${PHPGROUP}/g" /usr/local/etc/php-fpm.d/www.conf
:
-
sed
コマンドを使用して、www.conf
ファイル内のユーザーとグループをlaravel
に変更します。 -
${PHPUSER}
と${PHPGROUP}
はENV
ディレクティブで設定された変数です。
RUN mkdir -p /var/www/html/public
: 必要なディレクトリ構造を作成します。これはLaravelプロジェクトのpublic
ディレクトリに対応しています。
RUN docker-php-ext-install pdo pdo_mysql
: pdo
とpdo_mysql
拡張機能をPHPに追加します。これらはLaravelがデータベースとの通信に使用する拡張機能です。
CMD ["php-fpm", "-F", "-y", "/usr/local/etc/php-fpm.conf", "-R"]
:
- コンテナが起動したときに実行されるコマンドを設定します。
-
php-fpm
を-F
(フロントモード)で実行し、-y
で別のphp-fpm設定ファイルを指定し、-R
でリクエストを拒否せずに終了します。
composer.Dockerfile
を作成する
FROM composer:2
ENV COMPOSERUSER=laravel
ENV COMPOSERGROUP=laravel
RUN adduser -g ${COMPOSERGROUP} -s /bin/sh -D ${COMPOSERUSER}
ENV COMPOSERUSER=laravel
と ENV COMPOSERGROUP=laravel
: laravel
というユーザーとグループの環境変数を設定しています。
RUN adduser -g ${COMPOSERGROUP} -s /bin/sh -D ${COMPOSERUSER}
:
- この行は、
laravel
という名前のグループ (-g ${COMPOSERGROUP}
) とユーザー (-D ${COMPOSERUSER}
) を作成します。 -
-s /bin/sh
は、ユーザーに/bin/sh
シェルを割り当てるオプションです。
これにより、Composer コンテナ内に laravel
という名前のユーザーが作成され、Composer プロジェクトを実行するときにこのユーザーが使用されます。
Docker コンテナのビルドと起動
docker-compose up -d --build
[+] Running 12/12
✔ mysql 11 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 21.2s
✔ 8e0176adc18c Pull complete 4.6s
✔ a6b6bf6e5d0f Pull complete 4.6s
✔ c17b83f8620f Pull complete 4.6s
✔ b2e259cd9b6c Pull complete 5.0s
✔ 366131ab00d1 Pull complete 5.0s
✔ 2f99ba83a3cb Pull complete 5.0s
✔ f7c88955f01f Pull complete 7.1s
✔ 577fb415d7f8 Pull complete 7.1s
✔ 29160ed46eb1 Pull complete 17.5s
✔ 69ce9884ce5d Pull complete 17.5s
✔ 848f0dceb14c Pull complete
[+] Building 28.8s (29/29) FINISHED
=> [php internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [php internal] load build definition from php.Dockerfile 0.0s
=> => transferring dockerfile: 477B 0.0s
=> [php internal] load metadata for docker.io/library/php:8-fpm-alpine 2.6s
=> [composer internal] load build definition from composer.Dockerfile 0.0s
=> => transferring dockerfile: 178B 0.0s
=> [composer internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [composer internal] load metadata for docker.io/library/composer:2 2.6s
=> [composer auth] library/composer:pull token for registry-1.docker.io 0.0s
=> [php auth] library/php:pull token for registry-1.docker.io 0.0s
=> [php 1/6] FROM docker.io/library/php:8-fpm-alpine@sha256:9a1f2a7dba5605e05926ad8d3e837609c17acc7 0.0s
=> CACHED [php 2/6] RUN adduser -g laravel -s /bin/sh -D laravel 0.0s
=> [php 3/6] RUN sed -i "s/user = www-data/user = laravel/g" /usr/local/etc/php-fpm.d/www.conf 0.4s
=> [composer 1/2] FROM docker.io/library/composer:2@sha256:fb3c5a283f2dc08e08841048498e8a82c3864648 0.0s
=> CACHED [composer 2/2] RUN adduser -g laravel -s /bin/sh -D laravel 0.0s
=> [composer] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:40093d96c788f7ce5eec06fd6f0be79cc07b8beddf6f1ed301f926e1f0bda6bc 0.0s
=> => naming to docker.io/library/lara-docker-composer 0.0s
=> [php 4/6] RUN sed -i "s/group = www-data/group = laravel/g" /usr/local/etc/php-fpm.d/www.conf 0.3s
=> [php 5/6] RUN mkdir -p /var/www/html/public 0.3s
=> [php 6/6] RUN docker-php-ext-install pdo pdo_mysql 18.8s
=> [php] exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:24786a20832c3323f75e5ca0ea39cfcb8875df3d87c6a6b2a0941b776967d951 0.0s
=> => naming to docker.io/library/lara-docker-php 0.0s
=> [nginx internal] load build definition from nginx.Dockerfile 0.0s
=> => transferring dockerfile: 330B 0.0s
=> [nginx internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [nginx internal] load metadata for docker.io/library/nginx:stable-alpine 2.9s
=> [nginx auth] library/nginx:pull token for registry-1.docker.io 0.0s
=> [nginx 1/5] FROM docker.io/library/nginx:stable-alpine@sha256:62cabd934cbeae6195e986831e4f745ee1 2.4s
=> => resolve docker.io/library/nginx:stable-alpine@sha256:62cabd934cbeae6195e986831e4f745ee1646c17 0.0s
=> => sha256:e6295d4bbc4559ee7ed2e93830f4228a08af4114d7914db140a026f84e69adbb 16.32kB / 16.32kB 0.0s
=> => sha256:a352ab20253014461883d177aacee4ee6a2f82b3976d65015665bf4e0c05478a 625B / 625B 0.2s
=> => sha256:a4896b78e8db1b60c583e7bf115527dea0f1cc0207047cc318e6bab726a44765 3.85MB / 3.85MB 0.4s
=> => sha256:62cabd934cbeae6195e986831e4f745ee1646c1738dbd609b1368d38c10c5519 1.65kB / 1.65kB 0.0s
=> => sha256:e06ffa63074d69b12c7f7712d7aebc4cc72d25217e55788d54160a2bd77182f4 1.78kB / 1.78kB 0.0s
=> => sha256:9398808236ffac29e60c04ec906d8d409af7fa19dc57d8c65ad167e9c4967006 3.38MB / 3.38MB 0.4s
=> => sha256:b9258afd06398fe15821fa84d20d293de602601e8f3c3f607eb0fb82077933a1 956B / 956B 0.4s
=> => extracting sha256:9398808236ffac29e60c04ec906d8d409af7fa19dc57d8c65ad167e9c4967006 0.2s
=> => sha256:8799ab366479fb72b00d08daefe94af71814b80c946ba8a3a3262129f4ab6688 773B / 773B 0.6s
=> => sha256:07bc104f8702005e2c6acc3f3932ce08d11442367a62fd133a67157e7e5a8e6e 1.40kB / 1.40kB 0.6s
=> => sha256:8afc9a751a90c1bc306e89a586c8e7b759a620814cb85a3584bd8c7833b4e9e4 11.67MB / 11.67MB 0.8s
=> => extracting sha256:a4896b78e8db1b60c583e7bf115527dea0f1cc0207047cc318e6bab726a44765 0.5s
=> => extracting sha256:a352ab20253014461883d177aacee4ee6a2f82b3976d65015665bf4e0c05478a 0.0s
=> => extracting sha256:b9258afd06398fe15821fa84d20d293de602601e8f3c3f607eb0fb82077933a1 0.0s
=> => extracting sha256:8799ab366479fb72b00d08daefe94af71814b80c946ba8a3a3262129f4ab6688 0.0s
=> => extracting sha256:07bc104f8702005e2c6acc3f3932ce08d11442367a62fd133a67157e7e5a8e6e 0.0s
=> => extracting sha256:8afc9a751a90c1bc306e89a586c8e7b759a620814cb85a3584bd8c7833b4e9e4 0.6s
=> [nginx internal] load build context 0.0s
=> => transferring context: 635B 0.0s
=> [nginx 2/5] RUN mkdir -p /var/www/html/public 0.3s
=> [nginx 3/5] ADD nginx/default.conf /etc/nginx/conf.d/default.conf 0.0s
=> [nginx 4/5] RUN sed -i "s/user www-data/user laravel/g" /etc/nginx/nginx.conf 0.2s
=> [nginx 5/5] RUN adduser -g laravel -s /bin/sh -D laravel 0.2s
=> [nginx] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f63eda8d884745b3a30572e1890028aeff9174706f1463f2319938958ec8be38 0.0s
=> => naming to docker.io/library/lara-docker-nginx 0.0s
[+] Running 5/5
✔ Network lara-docker_default Created 0.1s
✔ Container lara-docker-php-1 Started 0.8s
✔ Container lara-docker-composer-1 Started 0.8s
✔ Container lara-docker-mysql-1 Started 0.8s
✔ Container lara-docker-nginx-1 Started 0.9s
php, nginxとmysqlが起動されていることを確認します。
docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
lara-docker-mysql-1 mysql:8.0 "docker-entrypoint.s…" mysql About a minute ago Up 59 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp
lara-docker-nginx-1 lara-docker-nginx "/docker-entrypoint.…" nginx About a minute ago Up 59 seconds 0.0.0.0:80->80/tcp
lara-docker-php-1 lara-docker-php "docker-php-entrypoi…" php About a minute ago Up 59 seconds 9000/tcp
新規Laravelプロジェクトを作成する
Composerコマンドを使って新規Laravelプロジェクトを作成します。
➜ docker-compose run --rm composer create-project laravel/laravel .
[+] Building 0.0s (0/0)
[+] Building 0.0s (0/0)
Creating a "laravel/laravel" project at "./"
Installing laravel/laravel (v10.2.9)
- Downloading laravel/laravel (v10.2.9)
- Installing laravel/laravel (v10.2.9): Extracting archive
Created project in /var/www/html/.
> @php -r "file_exists('.env') || copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies
....
> @php artisan vendor:publish --tag=laravel-assets --ansi --force
INFO No publishable resources for tag [laravel-assets].
No security vulnerability advisories found.
> @php artisan key:generate --ansi
INFO Application key set successfully.
新しい Laravel プロジェクトが ./src
ディレクトリ内に作成されたことを確認します。
localhost
にアクセスすると、Laravelアプリが実行されていることを確認します。
ComposerパッケージのインストールもComposerコンテナの実行と同じようにdocker-compose run --rm
をつけます。
そうするとコンテナの実行が完了したらコンテナが削除されます。
docker-compose run --rm composer require ***/***
DBの環境変数を設定する
docker-compose.yml
に設定したDBのユーザー名とパスワードを追加します。
また、ローカルのmysqlではなく、mysqlコンテナを使用するため、HOST名をサービス名に変えます。
- DB_HOST=127.0.0.1
- DB_USERNAME=root
- DB_PASSWORD=
+ DB_HOST=mysql
+ DB_USERNAME=laravel
+ DB_PASSWORD=password
npmをインストールする
docker-compose.yml
にnpm
のイメージを使います。
services:
npm:
image: node:current-alpine
volumes:
- ./src:/var/www/html
entrypoint: ["npm"]
working_dir: /var/www/html
npmをインストールします。
docker-compose run --rm npm install
[+] Building 0.0s (0/0)
[+] Building 0.0s (0/0)
added 20 packages, and audited 21 packages in 7s
5 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
npm notice
npm notice New patch version of npm available! 10.2.3 -> 10.2.4
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.2.4
npm notice Run npm install -g npm@10.2.4 to update!
npm notice
アセットをコンパイルします。
docker-compose run --rm npm run dev
[+] Building 0.0s (0/0)
[+] Building 0.0s (0/0)
> dev
> vite
VITE v4.5.0 ready in 778 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h to show help
LARAVEL v10.32.1 plugin v0.8.1
➜ APP_URL: http://localhost
artisanコマンドを実行する
Docker Composeを使用すると、各サービス(PHPやMySQL)ごとに独自のコンテナが作成され、それぞれのコンテナにはLaravelプロジェクトと依存関係があります。
そのため、artisan
コマンドを実行するには、docker-compose run artisan ...
という形式で、artisan
サービスを指定してDockerコンテナ内で実行する必要があります。
docker-compose.yml
ファイルでartisan
サービスを設定することで、このコマンドを簡単に実行でき、Docker環境内でLaravelアプを管理できます。
services:
artisan:
build:
context: .
dockerfile: php.Dockerfile
volumes:
- ./src:/var/www/html
working_dir: /var/www/html
depends_on:
- mysql
entrypoint: ["php", "/var/www/html/artisan"]
artisan
: サービスの名前。このサービスは Laravel アプリケーション内で artisan
コマンドを実行します。
build
: コンテナをビルドする設定。context
は Dockerfile
が存在するディレクトリを指定します。
volumes
: ホストマシンの ./src
ディレクトリをコンテナ内の /var/www/html
にマウントします。アプリのコードがホストマシンとコンテナ間で共有されます。
working_dir
: コンテナ内での作業ディレクトリを指定します。/var/www/html
は Laravel アプリのルートディレクトリです。
depends_on
: mysql
サービスが起動するのを待ってからコンテナを起動します。これにより、Laravel アプリケーションが MySQL データベースに依存する場合に、データベースの起動を待つことができます。
entrypoint
: コンテナが起動されたときに実行されるコマンドを指定します。["php", "/var/www/html/artisan"]
は php
コマンドで /var/www/html/artisan
を実行します。
マイグレーションを実行してみます。
docker-compose run --rm artisan migrate
[+] Building 0.0s (0/0)
[+] Creating 1/0
✔ Container lara-docker-mysql-1 Running 0.0s
[+] Building 0.0s (0/0)
INFO Preparing database.
Creating migration table .................................................................... 74ms DONE
INFO Running migrations.
2014_10_12_000000_create_users_table ........................................................ 74ms DONE
2014_10_12_100000_create_password_reset_tokens_table ........................................ 86ms DONE
2019_08_19_000000_create_failed_jobs_table .................................................. 53ms DONE
2019_12_14_000001_create_personal_access_tokens_table ....................................... 65ms DONE
artisanコマンドを使えるようになりました。
docker-compose run --rm artisan tinker
[+] Building 0.0s (0/0)
[+] Creating 1/0
✔ Container lara-docker-mysql-1 Running 0.0s
[+] Building 0.0s (0/0)
Psy Shell v0.11.22 (PHP 8.2.12 — cli) by Justin Hileman
> User::all();
= Illuminate\Database\Eloquent\Collection {#7011
all: [],
}
終わりに
DockerでのLaravel開発環境を構築してみした。
Nginx Dockerイメージ
PHP Dockerイメージ
MySQL Dockerイメージ
Composer Dockerイメージ
Composer Dockerイメージ
参考した記事
Discussion