Edited at

Laravelの開発環境をDockerを使って構築する

2019/8/10 注意 構成を大幅に見直し、記事も合わせて加筆しています。

2019/9/4 Laravel 6 でも動作するように修正を加えました。

2019/9/28 要望が多かったのでNodeコンテナを起動したままの状態に変更しました。


概要

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

環境構築のコマンドのみ見たい方は 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 コンテナ内で実行するコマンド


前提

[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.git

[mac] $ cd docker-laravel


環境設定ファイルの確認

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
-----------------------------------------------------------------------------------------------------
myproject_app_1 docker-php-entrypoint /bin ... Up 0.0.0.0:18000->8000/tcp, 9000/tcp
myproject_db-testing_1 docker-entrypoint.sh mysqld Up 0.0.0.0:13307->3306/tcp, 33060/tcp
myproject_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:13306->3306/tcp, 33060/tcp
myproject_mail_1 MailHog Up 1025/tcp, 0.0.0.0:18025->8025/tcp
myproject_node_1 docker-entrypoint.sh node Up
myproject_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
myproject_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を使ってるので、ライブラリを入れる

http://127.0.0.1:10080

上記のアドレスにアクセスしてLaravelのウェルカムページが表示されればokです。

スクリーンショット 2019-02-09 11.46.14.png

ポート番号は他の環境と被らないようあえて 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



  • .envDB_HOST へMySQLのコンテナ名を設定する。


  • migrate すると userspassword_resets テーブルが生成される。


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に対応してるから😊


設定例

スクリーンショット 2019-08-10 4.47.13.png


変更箇所

Name: docker-laravel(任意)

Host: 127.0.0.1
Port: 13306
User: homestead
Password: secret
Database: homestead


TablePlusの画面

スクリーンショット 2019-08-10 4.48.30.png


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

http://127.0.0.1:18000



  • serve Laravelのビルトインサーバを起動します。コンソール上にログが表示されます。


  • --host 外部からのアクセスを許可する指定をします。


データベースを初期化する

$ docker-compose down --volumes --rmi all

$ docker-compose up -d --build
$ docker-compose exec app php artisan migrate


既存のLaravelプロジェクトの実行環境を構築する

例えば、このLaravelプロジェクトを動かしてみたいなぁという時。

https://github.com/ucan-lab/laravel60-quickstart-basic

[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

http://127.0.0.1:10080


各種バージョン情報

$ 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(アルパイン・リナックス)とは、

muslBusyBoxをベースとしたLinuxディストリビューションです。

(用語を説明すると新たな用語の説明をしなければならなくなる説)

セキュリティ・シンプルさ・リソース効率を重視したOSです。

特定のOSのシェルを実行するようなアプリでなければ、Alpineはとても軽量です。

ただ、徹底的に軽量化されているため、AWSやGCPにデプロイした際に苦戦しそうです🤔

Alpine以外のDockerイメージとしては、UbuntuやDebianのイメージが良く使われる傾向にあるみたいです。個人歴にはCentOSとかRedHat系のOSが好きです😊


関連記事


参考にさせていただいた記事


さいごに

初めてdocker環境の構築に挑戦しましたが、個人的にはイイ感じに作れたかなと満足してます😊

もっとこうした方がイイよ!っていうアドバイスがあったらコメントいただけると嬉しいです!