2019/8/10 注意 構成を大幅に見直し、記事も合わせて加筆しています。
2019/9/4 Laravel 6 でも動作するように修正を加えました。
2019/9/28 要望が多かったのでNodeコンテナを起動したままの状態に変更しました。
2019/10/30 忙しい人向けの記事を書きました
2019/12/31 appコンテナをPHP7.4にアップデートしました。
2020/5/9 この記事の内容を全て書き直しました 最強のLaravel開発環境をDockerを使って構築する【新編集版】
当記事で使用しているGitHubリポジトリは既にアーカイブされています。使える部分はあるかと思いますが、ご利用は自己責任でお願いします。
概要
docker(docker-compose)でLEMP環境(PHP/nginx/MySQL)を構築し、Laravelの新規プロジェクト作成まで行います。
Laravelを動作させる最小docker構成のハンズオン記事も書いてますので、一からdocker構成を作ってみたい人はこちらの記事をおすすめします。
用意する環境
- PHP7.3
- Laravel5.8
- MySQL8.0
- nginx1.17
- その他(Node,Redis,MailHog)
リポジトリ
https://github.com/ucan-lab/docker-laravel-alpine
環境構築のコマンドのみ見たい方は README.md を参照ください。
対象読者
- Laravelが動く環境をdockerで作りたい人
Docker とは
Dockerとは、一台のマシン上に複数の隔離された環境を構築する軽量なコンテナ型の仮想化技術です。
特定のプロセスの実行環境を Dockerイメージ
という単位で管理できます。
Dockerのメリットとしては、
仮想マシン(VirtualBox)と違ってハードウェア(CPU, メモリ)をシミュレーションする必要がないためとても軽快です。
補足
コンテナに出たり入ったりすることが多いので下記のようにします。
[mac] $ Macで実行するコマンド
[web] $ dockerの web コンテナ内で実行するコマンド
[app] $ dockerの app コンテナ内で実行するコマンド
[db] $ dockerの db コンテナ内で実行するコマンド
[node] $ dockerの node コンテナ内で実行するコマンド
[redis] $ dockerの redis コンテナ内で実行するコマンド
前提
- git
- Macであれば標準でインストールされている
- Docker
- https://docs.docker.com/docker-for-mac から最新版をダウンロードする
- 参考記事: DockerをMacにインストールする
[mac] $ git --version
git version 2.22.0
[mac] $ docker --version
Docker version 19.03.1, build 74b1e89
[mac] $ docker-compose --version
docker-compose version 1.24.1, build 4667896b
最終的なディレクトリ構成
[mac] $ tree .
.
├── README.md
├── docker => 各コンテナの設定ファイル
│ ├── ash
│ │ ├── .ash_history
│ │ ├── aliases.sh
│ │ └── color_prompt.sh
│ ├── mysql
│ │ └── my.cnf
│ ├── nginx
│ │ └── default.conf
│ └── php
│ ├── Dockerfile
│ └── php.ini
├── logs => 各種ログファイル
├── src => Laravelプロジェクトをインストールするディレクトリ
├── .env
├── .gitignore
└── README.md
ここまでで事前準備終了です。
Docker環境を構築する
今回は handson
という作業ディレクトリを作ります。
[mac] $ mkdir handson
[mac] $ cd handson
GitHubリポジトリからDockerテンプレートをダウンロード
[mac] $ git clone https://github.com/ucan-lab/docker-laravel-alpine
[mac] $ cd docker-laravel-alpine
[mac] $ cp .env-example .env
環境設定ファイルの確認
dockerの.env
の中身を確認します。
[mac] $ less .env
データベースの接続情報を記述している箇所があります。
ここは Laravelの.env
の初期設定に合わせてます。
必要に応じて 環境設定ファイルや各コンテナの設定ファイルを変更してください。
Dockerのビルド、起動
[mac] $ docker-compose build
[mac] $ docker-compose up -d
-
build
コマンドで サービスの構築 を行う -
up
コマンドで コンテナを作成してサービスを開始 します -
-d
オプションで デタッチド・モードで起動(デフォルトはアタッチド・モード) します。- これにより通常はコンテナを実行するとすぐに終了しますが、バックグラウンドで動作するようになります。
-
docker-compose up -d --build
ワンコマンドにまとめてもok
[mac] $ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------------------------
docker-laravel_app_1 docker-php-entrypoint php-fpm Up 0.0.0.0:18000->8000/tcp, 9000/tcp
docker-laravel_db-testing_1 docker-entrypoint.sh mysqld Up 0.0.0.0:13307->3306/tcp, 33060/tcp
docker-laravel_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:13306->3306/tcp, 33060/tcp
docker-laravel_mail_1 MailHog Up 1025/tcp, 0.0.0.0:18025->8025/tcp
docker-laravel_node_1 docker-entrypoint.sh node Up
docker-laravel_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
docker-laravel_web_1 nginx -g daemon off; Up 0.0.0.0:10080->80/tcp
-
ps
コマンドで起動しているコンテナの一覧を表示します。
上記のようにコンテナが表示されていればokです。
Laravelプロジェクトを新規に作成する場合
[mac] $ docker-compose exec app composer create-project --prefer-dist "laravel/laravel=5.8.*" .
[mac] $ docker-compose exec app composer require predis/predis
-
composer create-project laravel/laravel
新しいLaravelプロジェクトを作成するコマンド-
--prefer-dist
はzipでダウンロードする(高速)、デフォルトはgit cloneする -
.
カレントディレクトリにインストールする
-
-
composer require predis/predis
Redisを使ってるので、ライブラリを入れる
上記のアドレスにアクセスしてLaravelのウェルカムページが表示されればokです。
ポート番号は他の環境と被らないようあえて 10080
番号に設定してます。
LaravelのDocker環境構築は以上で完了です!!
お疲れ様です🎉🎉🎉
必要に応じて...
Laravelのコマンドを実行したい場合
php
, composer
, artisan
コマンドは app
コンテナ内で実行します。
[mac] $ docker-compose exec app ash
[app] $ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
-
ash
エイシェル- Almquist Shell(アルムクィストシェル)
- Alpine Linuxでは軽量化のため、bashではなくashが採用されています。
-
migrate
するとusers
とpassword_resets
テーブルが生成される。 - ※ migrateエラーが発生する場合
Laravelの.env
のDB_HOST
へMySQLのコンテナ名を設定してください。(DB_HOST=db
)
MySQLに接続したい場合
MySQLはdbコンテナに入ってMySQLコマンドを実行します。
環境変数に接続情報が入っているのでこのままコピペでログインできます。
[mac] $ docker-compose exec db bash -c 'mysql -uroot -p${MYSQL_PASSWORD} ${MYSQL_DATABASE}'
上記のコマンドでMySQLにログインし、MySQLコマンドを実行できます。
[db] mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | JST |
| time_zone | SYSTEM |
+------------------+--------+
2 rows in set (0.01 sec)
[db] mysql> show variables like '%char%';
+--------------------------+--------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.00 sec)
[db] mysql> show databases;
+--------------------+
| Database |
+--------------------+
| homestead |
| information_schema |
+--------------------+
[db] mysql> show tables;
+---------------------+
| Tables_in_homestead |
+---------------------+
| migrations |
| password_resets |
| users |
+---------------------+
[db] mysql> select * from migrations;
+----+------------------------------------------------+-------+
| id | migration | batch |
+----+------------------------------------------------+-------+
| 1 | 2014_10_12_000000_create_users_table | 1 |
| 2 | 2014_10_12_100000_create_password_resets_table | 1 |
+----+------------------------------------------------+-------+
- タイムゾーン:
Asia/Tokyo
- 文字コード:
utf8mb4
上述の php artisan migrate
を実行していれば migrations
テーブルに2件データが入ってるはず。
MySQL管理ツールから接続したい場合
オススメのMySQL管理ツールはTablePlusです。理由はMySQL8.0に対応してるから😊
設定例
変更箇所
Name: docker-laravel(任意)
Host: 127.0.0.1
Port: 13306
User: homestead
Password: secret
Database: homestead
TablePlusの画面
Node(npm, yarn)を実行したい場合
[mac] $ docker-compose exec node ash
[node] $ npm install # OR yarn install
[node] $ npm run dev # OR yarn run dev
Redisを使いたい場合
[mac] $ docker-compose exec redis ash
[redis] $ redis-cli
127.0.0.1:6379> SET hoge bar
OK
127.0.0.1:6379> GET hoge
"bar"
RedisをLaravelで使いたい場合
$ docker-compose exec app php artisan tinker
Redis::set('name', 'hoge');
Redis::get('name');
参考: https://readouble.com/laravel/5.8/ja/redis.html
Laravelのビルトインサーバを使いたい場合
[mac] $ docker-compose exec app php artisan serve --host 0.0.0.0
-
serve
Laravelのビルトインサーバを起動します。コンソール上にログが表示されます。 -
--host
外部からのアクセスを許可する指定をします。
データベースを初期化する
$ docker-compose down --volumes --rmi all
$ docker-compose up -d --build
$ docker-compose exec app php artisan migrate
既存のLaravelプロジェクトの実行環境を構築する
例えば、このLaravelプロジェクトを動かしてみたいなぁという時。
[mac] $ mkdir handson
[mac] $ cd handson
[mac] $ git clone git@github.com:ucan-lab/docker-laravel.git
[mac] $ git clone git@github.com:ucan-lab/laravel60-quickstart-basic.git
[mac] $ cd docker-laravel
.env
を書き換える
#PROJECT_PATH=./src
PROJECT_PATH=../laravel60-quickstart-basic
あとは環境構築して動作確認します😊
[mac] $ docker-compose up -d --build
[mac] $ docker-compose exec app composer install
[mac] $ docker-compose exec app cp .env.example .env
[mac] $ docker-compose exec app php artisan migrate
各種バージョン情報
$ docker-compose exec web nginx -V
nginx version: nginx/1.17.3
built by gcc 8.3.0 (Alpine 8.3.0)
built with OpenSSL 1.1.1c 28 May 2019
TLS SNI support enabled
[mac] $ docker-compose exec app php -v
PHP 7.3.8 (cli) (built: Aug 2 2019 06:11:32) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.8, Copyright (c) 1998-2018 Zend Technologies
with Xdebug v2.7.2, Copyright (c) 2002-2019, by Derick Rethans
[mac] $ docker-compose exec app composer -V
Composer version 1.9.0 2019-08-02 20:55:32
[mac] $ docker-compose exec db mysql -V
mysql Ver 8.0.17 for Linux on x86_64 (MySQL Community Server - GPL)
[mac] $ docker-compose exec redis redis-cli --version
redis-cli 5.0.5
[mac] $ docker-compose exec node node -v
v12.8.1
[mac] $ docker-compose exec node npm -v
6.10.2
[mac] $ docker-compose exec node yarn --version
1.17.3
※バージョン固定してないものもあり、構築するタイミングによってバージョン差異はあります。
今回Dockerを勉強して知ったこと
上記の方々にレビューいただき、今回改めて知ったことを共有します。
コンテナ名の衝突を避ける
コンテナを起動するとフォルダ名が初期値としてプロジェクト名となってしまい、フォルダ名を変えた場合に、プロジェクト名が勝手に変わってしまう問題があります。
コンテナ名だけでなく、イメージ名、ネットワーク名、ボリューム名の衝突にも気を付ける必要があります。
COMPOSE_PROJECT_NAME
COMPOSE_PROJECT_NAME
を使えば、 container_name
も指定する必要なく、「COMPOSE_PROJECT_NAME 変数 + _ + サービス名 + _ + 連番」という名前になります😊
RUN set -eux
RUN を実行する際にはじめにシェルオプションを設定すると
buildを実行する際にコマンドが表示されるので、処理が途中で失敗した場合などに原因調査しやすいというメリットがあります。
-
-e
オプションによって実行したコマンドが1つでもエラーになれば直ちに終了するようにし、 -
-u
オプションで未定義の変数などを使おうとすればエラーにするようにしている。 -
-x
オプションでは実行コマンドとその引数をトレースとして出力するようにしている。
複数行でRUNの実行
Dockerは文を実行するたびにイメージのレイヤーを作成されてしまう。
RUN コマンドは繋げてワンライナーにする方が良い。
コマンドが長くなる場合は \
で改行して見やすくする。
# NG
RUN apk update
RUN apk add git
# GOOD!
RUN apk update && \
apk add git
一時的な変数は ENV ではなく ARG を使う
ARG
は Dockerfile 内で使用可能な変数です。
ARG foo=bar
RUN echo $foo
ADD より COPY
ファイルをコピーする意図であれば、 ADD
より COPY
を使った方がより直感的で分かりやすい
ADD ./my.cnf /etc/mysql/my.cnf # NG
COPY ./my.cnf /etc/mysql/my.cnf # GOOD!
トップレベルボリュームを使用する
トップレベルボリュームを使用するとデータの永続化が可能になります。名前付きvolume とも呼ぶそうです。
また、ボリュームが隠蔽化されるため誤って削除する心配が少なくなり開発しやすくなります。
テスト用に使うデータベースを用意する
Laravelの場合、テスト用のデータベースを作成することが多いので、
テスト用のDBも合わせて作成してあると開発環境としてはさらに良い。
/docker-entrypoint-initdb.d
のディレクトリ配下に .sql
や .sh
ファイルを配置すれば初回起動時に実行してくれます。
ベースイメージはコンテナの軽さを重視するならAlpine
Alpine Linux(アルパイン・リナックス)とは、
muslとBusyBoxをベースとしたLinuxディストリビューションです。
(用語を説明すると新たな用語の説明をしなければならなくなる説)
セキュリティ・シンプルさ・リソース効率を重視したOSです。
特定のOSのシェルを実行するようなアプリでなければ、Alpineはとても軽量です。
ただ、徹底的に軽量化されているため、AWSやGCPにデプロイした際に苦戦しそうです🤔
Alpine以外のDockerイメージとしては、UbuntuやDebianのイメージが良く使われる傾向にあるみたいです。個人歴にはCentOSとかRedHat系のOSが好きです😊
関連記事
参考にさせていただいた記事
- Dockerでサクっとローカル開発環境(LAMP + Laravel)を構築する
- Dockerfileを書くときに気をつけていること10選
- VagrantとDockerについて名前しか知らなかったので試した
- Dockerfileを書くときに気をつけていること10選
- Dockerfile ARG入門
- DBアクセスで遅くなったテストの実行時間を Docker で 40% 削減した方法
さいごに
初めてdocker環境の構築に挑戦しましたが、個人的にはイイ感じに作れたかなと満足してます😊
もっとこうした方がイイよ!っていうアドバイスがあったらコメントいただけると嬉しいです!