はじめに
最近LaravelのDocker環境を考える機会がありました。
他の環境は作ったことが何度かありましたが、Laravelは立ち上げのコマンドすら知らない状態でDocker環境を構築していったので良い学びになりました。
healthcheck
を使用することにより、DBの準備完了前にLaravelがDBを読み取ろうとする事故をなくすことに成功しています。
コンテナの実行順序を正しく制御することで、terminarl上でDocker構築のログが止まる頃にはアプリが完全に応答する状態を保証しています。
適宜コメントを入れているので、参考にしてください。
私は学生エンジニアですあと2ヶ月くらい...。
至らない点もあるかもしれません。
その点ご了承ください。
前提条件
Docker, Docker Composeの知識
各ファイルの説明
ファイル構成
data/ # Dockerで立てたdatabaseの中身
docker/
db/
conf.d/
- my.cnf
init/
- init.sql # 初回に実行したいsql処理
.env
php/
- .env # Laravelはrootの.envを読み込むので、特段phpコンテナにのみ指定したenvがなければ不要
- Dockerfile
- php.ini
nginx/
- default.conf # enginxの設定ファイル
src/ # Laravel本体 (localのsrcの中でLaravelをセットアップしてください)
.dockerignore
.gitignore
docker-compose.yml
docker/db/conf.d/my.cnf
[mysql]
default-character-set=utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin
[client]
default-character-set=utf8mb4
docker/db/init/init.sql
/* 実行したいsqlを記述 */
/* volumeのマウント先の*.sqlはentrypointにimportされて全て実行される仕組み */
docker/db/.env
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=test
MYSQL_USER=test
MYSQL_PASSWORD=test
docker/nginx/default.conf
server {
listen 80;
root /var/www/html/public; # index.phpが配置されているpublicディレクトリをrootにする
index index.php;
# 特定のURIやパターンに対するサーバーの動作を指定する
location / {
# 左から順に評価
# 存在しなければ最後の指定に従ってindex.phpを返す
root /var/www/html/public;
index index.php;
try_files $uri $uri/ /index.php$query_string;
}
# phpファイルはphp-fpmコンテナにリクエストして処理してもらう
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000; # (Dockerのservice名を使用していることに注意) (php-pfmはwebサーバを9000で受け付けている)
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# statusページの設定
location /status {
access_log off;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php:9000; # (Dockerのservice名を使用していることに注意) (php-pfmはwebサーバを9000で受け付けている)
fastcgi_index status.html;
}
}
docker/php/Dockerfile
# ExpressやRailsと違って、ソースと依存packageが紐づいている
# composer関連ファイルだけ先にコンテナにCOPYしてinstallしようとするとartisanを呼び出してエラーになる
FROM php:8.3.2-fpm-bullseye
WORKDIR /var/www/html
COPY ./src /var/www/html/
# composer use git zip
# apt may change the interface. apt-get would be better now.
# docker-phpext-install pdo_mysql provide driver of mysql
RUN apt-get update && apt-get install -y git zip zlib1g-dev lsof \
&& docker-php-ext-install pdo_mysql
# enable status code page
RUN echo pm.status_path = /status >> /usr/local/etc/php-fpm.d/www.conf
# Composer Install
RUN curl -sS https://getcomposer.org/installer | \
php -- --install-dir=/usr/local/bin --filename=composer
# package install
RUN composer install
COPY ./docker/php/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
CMD ["php-fpm"]
docker/php/entrypoint.sh
#!/bin/bash
set -e
# chown -R www-data:www-data ./
# chmod -R 777 storage bootstrap/cache
php artisan migrate
exec "$@"
docker/php/.env
# 指定したい環境変数(外部に晒したくない)があればここで指定する
# Laravelはプロジェクトのroot(今回だとsrc/)に存在する.envを読み込むので、それ以外でコンテナに付与したければここで記載する
docker/php/php.ini
# phpが利用しているphp.iniは php --iniで検索できる
# 複数出てくるが、Loaded Configuration Fileが利用しているphp.ini
# デフォルトはnoneで、php.iniを指定の場所に置くことで設定できる
[Date]
date.timezone = "Asia/Tokyo"
[opcache]
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1
docker-compose.yml
version: "3.8"
services:
php: # phpコンテナはnginxが実行できないphpの処理をするために存在する # webサーバーからのリクエストは9000で受け付ける
build:
context: .
dockerfile: ./docker/php/Dockerfile
env_file: ./docker/php/.env
tty: true
healthcheck: # healthcheck
test: ["CMD", "lsof", "-i:9000"]
start_period: 5s
timeout: 20s
retries: 10
depends_on:
db:
condition: service_healthy # dbコンテナの構築が完了(healthcheckに合格する)まで待つ
volumes:
- ./docker/php/php.ini:/usr/local/etc/php/php.ini
- ./src/:/var/www/html
environment:
- TZ=Asia/
nginx:
image: nginx:latest
depends_on:
db:
condition: service_healthy
php:
condition: service_healthy
ports:
- 8080:80
volumes:
- ./src:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf # 設定ファイルをnginxの指定位置にマウント
db:
image: mysql:8.0.31
platform: linux/amd64
env_file: ./docker/db/.env
command: --default-authentication-plugin=mysql_native_password
restart: always
volumes:
- ./data:/var/lib/mysql
- ./docker/db/conf.d/my.cnf:/etc/mysql/conf.d/my.cnf
- ./docker/db/init:/docker-entrypoint-initdb.d
ports:
- 3306:3306
healthcheck: # healthcheck
test:
["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
start_period: 5s
timeout: 20s
retries: 10
environment:
TZ: Asia/Tokyoaa
phpmyadmin:
image: phpmyadmin/phpmyadmin
platform: linux/amd64
container_name: phpMyAdmin
environment:
- PMA_ARBITRARY=1
- PMA_HOST=db
depends_on:
db: # phpmyadminはdbの準備が完了したら構築する
condition: service_healthy
ports:
- 8000:80
.dockerignore
**/vendor
.gitignore
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.env.production
.env.example
.phpunit.result.cache
Homestead.json
Homestead.yaml
auth.json
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.vscode
.DS_Store
db
Laravel側の設定
src/.env(Laravelのroot)
DB_CONNECTION=mysql
DB_HOST=db # Dockerのservice名を利用
DB_PORT=3306
DB_DATABASE=test # Mysqlのenvに合わせる
DB_USERNAME=test # Mysqlのenvに合わせる
DB_PASSWORD=test # Mysqlのenvに合わせる
おわりに
Dockerの環境づくりは何度かやったことがあるのですがhealthcheckを利用したの初めてでした(存在は知ってた)
今回腰を据えて環境構築をすることになったので、healthcheckは絶対に導入したいと考えていました。
慣れないうちはDockerで環境構築をするに当たり様々な試行錯誤と調査が必要で大変ですが、完成した時の達成感は大きなものがありました。
この記事を作成するにあたり多くの有益な情報源を頼らせていただきました。
ありがとうございます。
参考URLを貼っておきますので確認してください。
参考