DockerでLaravelの開発環境を作ってみる(5回目練習Ver)
わけわからない素人がDockerでLaravelの開発環境を作る5回目です。 4回目でdocker-composeを使って複数のコンテナを作成しましたが、まだ使い物にならないため素人なりに改良してみます。
作業環境は
- OS Ubuntu 20.04.2 LTS
- Docker version 20.10.7
- docker-compose version 1.29.2
です。
PHPアプリコンテナを作る
今まで通りPHPコンテナから作ります。
以下のようにディレクトリとファイルを作成します。
lwd-5
├─ docker
│ └─ php
│ │ Dockerfile ← phpコンテナの定義ファイル
│ └
│ docker-compose.yml ← 構成ファイル
└─ src
Composerのインストール方法
前回の"Dockerfile"内でComposerをインストールしているのですが、ハッシュ値を固定で記述していました。 このためファイルが更新されてしまったら動作しなくなります。
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
&& php composer-setup.php \
&& php -r "unlink('composer-setup.php');" \
&& mv composer.phar /usr/local/bin/composer
Docker17.05以降に使えるようになったマルチステージビルドという機能で、直接composerのDockerイメージから持ってくることにします。 2021年7月8日現在では2.1.3が最新でしたのでこれを使用します。
https://hub.docker.com/_/composer
マルチステージビルドの方法は上記のページにあるので、それにタグ「2.1.3」を指定します。
COPY --from=composer:2.1.3 /usr/bin/composer /usr/bin/composer
Dockerfile
# FROM : これから作るイメージの元ととなるイメージ
# Debian 10でphp8.0.7のFastCGI実装イメージを元に作成する
FROM php:8.0.7-fpm-buster
# マルチステージビルドでComposerをインストールする
COPY --from=composer:2.1.3 /usr/bin/composer /usr/bin/composer
# Laravelのインストール
RUN apt-get update \
&& apt-get install -y \
git \
unzip \
&& composer global require laravel/installer \
&& docker-php-ext-install pdo_mysql
docker-compose.yml
version: "3.8" # Docker Engin 19.03.0以降
services:
# PHP サービス
php:
build: ./docker/php # Dockerファイルの場所を指定
volumes:
- ./src/:/var/www # Laravelアプリの配置ディレクトリ
networks:
- examnet
# Dockerネットワーク
networks:
# コンテナ同士はホストから独立したネットワークで通信し、"appnet"という名前をつける
appnet:
driver: bridge
Composerが使えるか確認するためコンテナを実行します。
$ cd lwd-5
~/lwd-5$ docker-compose up -d
docker-compose ps
でコンテナが実行されているか確認することができます。
~/lwd-5$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------
lwd-5_php_1 docker-php-entrypoint php-fpm Up 9000/tcp
phpコンテナが起動していることが確認できたので、中に入ってComposerのバージョンを確認してみます。
~/lwd-5$ docker-compose exec php /bin/bash
root@92b9e4539390:/var/www/html# composer --version
Composer version 2.1.3 2021-06-09 16:31:20
バージョン2.1.3と表示されました。
Composerのインストールまではできたのでexit
コマンドでコンテナから脱出します。
apt-getのキャッシュを削除
Dockerの「Dockerfileを書くためのベストプラクティス」ページによると、aptキャッシュのクリアがイメージサイズの減少になるそうです。
まず作成したコンテナのファイルサイズを確認してみます。
~/lwd-5$ docker-compose images
Container Repository Tag Image Id Size
-----------------------------------------------------------
lwd-5_php_1 lwd-5_php latest 38fc1932dbd8 466.7 MB
DebianとUbuntuの公式イメージでは自動的にapt-get clean
が実行されるようですが、PHPイメージなので一応下記のように追加しました。
&& apt-get clean && rm -rf /var/lib/apt/lists/*
修正したDockerfileは以下になります。
# FROM : これから作るイメージの元ととなるイメージ
# Debian 10でphp8.0.7のFastCGI実装イメージを元に作成する
FROM php:8.0.7-fpm-buster
# マルチステージビルドでComposerをインストールする
COPY --from=composer:2.1.3 /usr/bin/composer /usr/bin/composer
# Laravelのインストール
RUN apt-get update \
&& apt-get install -y \
unzip \
git \
&& composer global require laravel/installer \
&& docker-php-ext-install pdo_mysql \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
今のコンテナを削除し、再作成してみます。
~/lwd-5$ docker-compose down
~/lwd-5$ docker image rm lwd-5_php
~/lwd-5$ docker-compose up -d
コンテナが作成されたのでサイズを確認して見ます。
~/lwd-5$ docker-compose images
Container Repository Tag Image Id Size
-----------------------------------------------------------
lwd-5_php_1 lwd-5_php latest 10b311c5b775 449.1 MB
466.7 MBから449.1 MBに17.6 MB小さくなりました。
UNIXドメインソケットを使用する
前回まではphpとnginxのコンテナ間通信にTCPを使用していました。 ですが、UNIXドメインソケットの方が効率が良いと言うので変更します。
下記のようにディレクトリと設定ファイルを作ります。
lwd-5
├─ docker
│ ├─ nginx ← 作成するディレクトリ
│ │ │ default.conf ← nginxの設定ファイル
│ │ └
│ └─ php
│ │ Dockerfile ← phpコンテナの定義ファイル
│ └ php-fpm.d ← 作成するディレクトリ
│ │ zzz-www.conf ← Unixドメインソケットの設定ファイル
│ └
│ docker-compose.yml ← 構成ファイル
└─ src
PHPコンテナで使用するUnixドメインソケットの設定ファイルを作成します。
https://www.php.net/manual/en/install.fpm.configuration.php
設定ファイル名を"zzz-www.conf"にしているのは、公式イメージにある設定を上書きするためです。
公式イメージの内容をdocker history
コマンドで確認すると。
$ docker history --no-trunc php:8.0.7-fpm-buster
・・・中略・・・
<missing> 5 weeks ago /bin/sh -c set -eux; cd /usr/local/etc; if [ -d php-fpm.d ]; then sed 's!=NONE/!=!g' php-fpm.conf.default | tee php-fpm.conf > /dev/null; cp php-fpm.d/www.conf.default php-fpm.d/www.conf; else mkdir php-fpm.d; cp php-fpm.conf.default php-fpm.d/www.conf; { echo '[global]'; echo 'include=etc/php-fpm.d/*.conf'; } | tee php-fpm.conf; fi; { echo '[global]'; echo 'error_log = /proc/self/fd/2'; echo; echo '; https://github.com/docker-library/php/pull/725#issuecomment-443540114'; echo 'log_limit = 8192'; echo; echo '[www]'; echo '; if we send this to /proc/self/fd/1, it never appears'; echo 'access.log = /proc/self/fd/2'; echo; echo 'clear_env = no'; echo; echo '; Ensure worker stdout and stderr are sent to the main error log.'; echo 'catch_workers_output = yes'; echo 'decorate_workers_output = no'; } | tee php-fpm.d/docker.conf; { echo '[global]'; echo 'daemonize = no'; echo; echo '[www]'; echo 'listen = 9000'; } | tee php-fpm.d/zz-docker.conf
・・・省略・・・
“zz-docker.conf"ファイルで’listen = 9000’と設定されています。
zzz-www.conf
[www]
; FastCGI リクエストを受け入れるアドレス
listen = /var/run/php-fpm/php-fpm.sock
; unix ソケットを使う場合に、そのパーミッションを設定します。
; Webサーバーからの接続ができるように設定します。
listen.owner = www-data
listen.group = www-data
listen.mode = 0666
; プロセスマネージャが子プロセスの数を制御する方法を選択します。
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
PHPのDockerfileに設定ファイルのコピー処理を追加します。
# FROM : これから作るイメージの元ととなるイメージ
# Debian 10でphp8.0.7のFastCGI実装イメージを元に作成する
FROM php:8.0.7-fpm-buster
# マルチステージビルドでComposerをインストールする
COPY --from=composer:2.1.3 /usr/bin/composer /usr/bin/composer
# Laravelのインストール
RUN apt-get update \
&& apt-get install -y \
unzip \
git \
&& composer global require laravel/installer \
&& docker-php-ext-install pdo_mysql \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Unixドメインソケットを使うための設定ファイルをコピー
COPY ./php-fpm.d/zzz-www.conf /usr/local/etc/php-fpm.d/zzz-www.conf
nginxのPHPサーバーとの通信方法を変更します。
“default.conf"ファイル。
server {
listen 80;
server_name example.com;
root /var/www/example-app/public;
add_header X-Frame-Options "SAMEORIGIN";
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$ {
# PHP FastCGI サーバーとUnixドメインソケットで通信する
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
“docker-compose.yml"ファイルにnginxコンテナを追記します。
version: "3.8" # Docker Engin 19.03.0以降
services:
# PHP サービス名:php
php:
build: ./docker/php # Dockerファイルの場所を指定
volumes:
# Laravelアプリの配置ディレクトリ
- ./src/:/var/www
# unixドメインソケット通信で使用
- php-fpm-socket:/var/run/php-fpm
networks:
- appnet
# nginx Webサーバー サービス名:web
web:
# 作成元イメージ
image: nginx:1.21.0-alpine
# nginxコンテナのポート80を外部にポート8080として公開する
ports:
- 8080:80
# nginxコンテナはPHPのコンテナに依存 先にphpコンテナを起動する
depends_on:
- php
volumes:
# アプリディレクトリ
- ./src:/var/www
# nginxの設定ファイルを置き換える
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
# unixドメインソケット通信で使用
- php-fpm-socket:/var/run/php-fpm
networks:
- appnet
# Dockerネットワーク
networks:
# コンテナ同士はホストから独立したネットワークで通信し、"appnet"という名前をつける
appnet:
driver: bridge
volumes:
# phpとnginxがunixドメインソケットで通信するために使用
php-fpm-socket:
定義ファイルを作成したら前に作ったイメージを削除し、コンテナを再実行します。
~/lwd-5$ docker image rm lwd-5_php
~/lwd-5$ docker-compose up -d
phpとnginxのコンテナが実行中になります。
~/lwd-5$ docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------------------
lwd-5_php_1 docker-php-entrypoint php-fpm Up 9000/tcp
lwd-5_web_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8080->80/tcp,:::8080->80/tcp
phpコンテナに入りLaravelアプリを新規作成します。
~/lwd-5$ docker-compose exec php /bin/bash
root@92b9e4539390:/var/www/html# export PATH="$HOME/.composer/vendor/bin:$PATH"
root@92b9e4539390:/var/www/html# cd ..
root@92b9e4539390:/var/www# laravel new example-app
root@c6c4226fd32e:/var/www# chmod o+w example-app/storage/logs
root@c6c4226fd32e:/var/www# chmod o+w example-app/storage/framework/sessions
root@c6c4226fd32e:/var/www# chmod o+w example-app/storage/framework/views
次にブラウザで"http://127.0.0.1:8080/“を開けばいつもの画面が表示されます。
MySQLコンテナを作る
MySQLのデータ置き場を前回はホストのディレクトリに割り当てていましたが、これをDocker Enginが管理するボリュームに変更します。
lwd-5
├─ docker
│ ├─ nginx
│ │ │ default.conf
│ │ └
│ └─ php
│ │ Dockerfile
│ └ php-fpm.d
│ │ zzz-www.conf
│ └
│ docker-compose.yml ← MySqlコンテナを追加する
└─ src
└─ example-app
│ .env ← MySQLへの接続設定する
└─
元からある.envファイルにMySqlへの接続情報を設定します。
~/lwd-5/src/example-app/.envファイルの下記の箇所を修正します。
・・・省略・・・
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laraveldb
DB_USERNAME=user4th
DB_PASSWORD=pwuser4th
・・・省略・・・
“docker-compose.yml"ファイルにMySQLコンテナの定義を追記します。 PHPコンテナの接続設定で使用した値を環境変数に設定します。
version: "3.8" # Docker Engin 19.03.0以降
services:
# PHP サービス名:php
php:
build: ./docker/php # Dockerファイルの場所を指定
volumes:
# Laravelアプリの配置ディレクトリ
- ./src/:/var/www
# unixドメインソケット通信で使用
- php-fpm-socket:/var/run/php-fpm
networks:
- appnet
# nginx Webサーバー サービス名:web
web:
# 作成元イメージ
image: nginx:1.21.0-alpine
# nginxコンテナのポート80を外部にポート8080として公開する
ports:
- 8080:80
# nginxコンテナはPHPのコンテナに依存 先にphpコンテナを起動する
depends_on:
- php
volumes:
# アプリディレクトリ
- ./src:/var/www
# nginxの設定ファイルを置き換える
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
# unixドメインソケット通信で使用
- php-fpm-socket:/var/run/php-fpm
networks:
- appnet
# MySQL データベースコンテナ サービス名:mysql
mysql:
image: mysql/mysql-server:8.0.25
# MySQLコンテナで使用する環境変数
# コンテナ作成時にこの内容で初期化さされます
# laraveldbデータベース、user5thユーザーがpwuser5thパスワードで作成され
# rootユーザーバスワードはmy-root-pwになります
environment:
MYSQL_DATABASE: laraveldb
MYSQL_USER: user5th
MYSQL_PASSWORD: pwuser5th
MYSQL_ROOT_PASSWORD: my-root-pw
# ホストのディレクトリをコンテナに割り当てる
# そうしないとコンテナを終了したらデータが残らない
volumes:
- .mysql-data:/var/lib/mysql
networks:
- appnet
# Dockerネットワーク
networks:
# コンテナ同士はホストから独立したネットワークで通信し、"appnet"という名前をつける
appnet:
driver: bridge
volumes:
# phpとnginxがunixドメインソケットで通信するために使用
php-fpm-socket:
# MySqlデータの保管場所
mysql-data:
今まで作成したコンテナはいらないのでdocker-compose down
コマンドで削除し、docker-compose up -d
でまとめて再作成します。
~/lwd-5$ docker-compose down
~/lwd-5$ docker-compose up -d
php、nginx、mysqlの3つのコンテナが作成されました。
~/lwd-5$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------------------
lwd-5_mysql_1 /entrypoint.sh mysqld Up (healthy) 3306/tcp, 33060/tcp, 33061/tcp
lwd-5_php_1 docker-php-entrypoint php-fpm Up 9000/tcp
lwd-5_web_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8080->80/tcp,:::8080->80/tcp
phpコンテナに入り、アプリのディレクトリへ移動して、migrate
コマンドを実行します。
~/lwd-5$ docker-compose exec php /bin/bash
root@a67c48298462:/var/www/html# cd /var/www/example-app
root@a67c48298462:/var/www/example-app# php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (696.94ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (542.47ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (535.14ms)
正常に終わったようなので、mysqlコンテナを確認してみます。
~/lwd-5$ docker-compose exec mysql /bin/bash
bash-4.4# mysql -u user5th -p
Enter password:
mysql> use laraveldb;
mysql> show tables;
+---------------------+
| Tables_in_laraveldb |
+---------------------+
| failed_jobs | ← phpコンテナからテーブルが作成されています
| migrations |
| password_resets |
| users |
+---------------------+
4 rows in set (0.00 sec)
phpからMySQLへの接続ができていることを確認できました。