Help us understand the problem. What is going on with this article?

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

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を使って構築する【新編集版】

概要

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 コンテナ内で実行するコマンド

前提

[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
[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を使ってるので、ライブラリを入れる

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
  • ash エイシェル
  • migrate すると userspassword_resets テーブルが生成される。
  • migrateエラーが発生する場合 Laravelの.envDB_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に対応してるから😊

設定例

スクリーンショット 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環境の構築に挑戦しましたが、個人的にはイイ感じに作れたかなと満足してます😊
もっとこうした方がイイよ!っていうアドバイスがあったらコメントいただけると嬉しいです!

ucan-lab
Backend Developer at ROLO. I love PHP and I'm focusing on Laravel, Docker, GraphQL.
https://u-can.pro
miraito-inc
システムデザインを中心に置いた開発により高品質で使いやすいシステムを提供いたします。業務システム構築、アプリ開発、コンサルティングまで幅広く手がけています。
https://miraito-inc.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした