Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
952
Help us understand the problem. What is going on with this article?
@ucan-lab

【超入門】20分でLaravel開発環境を爆速構築するDockerハンズオン

概要

docker(docker-compose)でLEMP環境(PHP/nginx/MySQL)を構築し、Laravelの新規プロジェクト作成、構築した環境を破棄してから環境の再構築までをハンズオン形式で行います。

ご注意

記事を寄稿したタイミングでは、補足の解説は特になくコマンドだけのご紹介だったので、コマンド部分のみコピペすれば20分で終わる内容でした。
しかし、継ぎ足しで解説を追記していった結果、普通に読みながら進めていくと2時間ぐらいのボリュームになってしまってます💦

ご了承下さい🙇‍♂️

更新履歴

  • 2020/09/09 Laravel8(当時はLaravel6が出た頃)がリリースされ、こちらの記事も内容が古くなったので全て書き直しました。

目的

Dockerの細かい概念などはすっ飛ばして、
このハンズオンの通りに進めればDocker×Laravelの環境を構築できます。
習うより慣れろで行ってみましょう!

ハンズオン終了時のGitHub

ハンズオンイベント

【ぺちオブ】ゆーきゃんプレゼンツ!Laravel + Docker 環境構築ハンズオン

あの有名なぺちオブのイベントとしてハンズオン講師をやらせていただきました!
ありがとうございます🙏

レビュワー

スペシャルサンクス🙇‍♂️🙏

前提条件

  • Mac基準ですが、Windowsでも動作することを確認済み
  • コマンドは [環境] $ とprefixを付けてます。
  • 所要時間は事前準備部分を除いて20分を目安としてます。
  • エディタはファイル編集時にお好みのもので開いて作業ください🙏

構築環境、使用技術

それぞれ、どういった技術なのか抑えておくと理解がしやすいです。

dockerおすすめ書籍

冒頭で習うより慣れろと言いましたが、習っておくのもそれはそれで良いことなのでオススメの書籍や記事をご紹介します。私はこの辺りの記事や本を読んで勉強したのでオススメしてます。

マンガでわかるdockerシリーズ

@llminatoll さんがDockerについてマンガで分かりやすく説明されてます。
初めての方はこちらのマンガでDockerの概念を学んでから進めると理解しやすいです。

dockerおすすめ記事・サイト

公式系

記事

スライド

事前準備

Windowsユーザー

Git Bashのインストールをお願いします。(Linuxコマンドをそのまま打てるようになります)

Git Bash を起動した際は下記のコマンドを実行ください。

$ exec winpty bash

GitHubアカウントの作成

Gitの初期設定

user.emailuser.name が設定されていればok!
Gitの初期設定を行ってない場合、下記の記事を参考に初期設定をお願いします。

Mac Git 初期設定

最終的に下記のように表示されればokです。

$ git config --list | grep user
user.email=xxx@yyy.com
user.name=zzz

GitHub SSH接続設定

$ ssh -T github.com
Warning: Permanently added 'github.com,52.69.186.44' (RSA) to the list of known hosts.
Hi ucan-lab! You've successfully authenticated, but GitHub does not provide shell access.

successfully authenticated の文字が出ればok!
Warningは気にしなくてok!

GitHub SSH接続設定を行ってない場合、下記の記事を参考に初期設定をお願いします。
もしくはハンズオンをHTTPSに置き換えて進めてください。

Mac GitHub SSH接続設定

docker, docker-compose のインストール

[Mac] Docker for Macをインストール

[Windows] Docker for Windowsをインストール

イントール確認

[mac] $ docker --version
Docker version 19.03.12, build 48a66213fe

[mac] $ docker-compose --version
docker-compose version 1.26.2, build eefe0d31

Docker起動確認

インストールしたDockerを起動してください。
running 状態になっていればokです。

スクリーンショット 2019-09-29 1.39.55.png


ここまでで事前準備終了です。


今回のハンズオンのゴール

  • 3層アーキテクチャのコンテナの構築
    • ウェブサーバー(web)
      • nginxで静的コンテンツ配信サーバを構築
    • アプリケーションサーバー(app)
      • nginxを経由してPHPを動作させるアプリケーションサーバを構築
      • PHPパッケージ管理ツールComposerのインストール
    • データベースサーバー(db)
      • MySQLデータベースサーバーの構築
  • Laravelをインストールしてwelcome画面の表示
  • LaravelとMySQLを連携し、マイグレーションを実行
  • Docker環境の破棄
  • Docker環境をGitHubから再構築

🐳【初心者向け】20分でLaravel開発環境を爆速構築するDockerハンズオン🐳

  • 所要時間: 20分目安

作業ディレクトリを作成

[mac] $ mkdir docker-laravel-handson
[mac] $ cd docker-laravel-handson

最終的なディレクトリ構成

.
├── README.md (この名前にするとGitHubで見た時にHTMLに変換して表示してくれる)
├── infra (*1)
│   ├── mysql (*1)
│   │   ├── Dockerfile
│   │   └── my.cnf (*1)
│   ├── nginx (*1)
│   │   └── default.conf (*1)
│   └── php (*1)
│       ├── Dockerfile (この名前にするとファイル名の指定を省略できる)
│       └── php.ini (*1)
├── docker-compose.yml (この名前にするとファイル名の指定を省略できる)
└── backend (*1)
    └── Laravelをインストールするディレクトリ

このディレクトリ構成を目指します。
(*1) 任意の名前に変更してもokです。

リモートリポジトリを作成

GitHub Create remote repository
GitHub docker-laravel-handson

リポジトリ名 docker-laravel-handson のGitHubリモートリポジトリを作成する。

リモートリポジトリへ初回コミット&プッシュ

[mac] $ echo "# docker-laravel-handson" >> README.md
[mac] $ git init
[mac] $ git add README.md
[mac] $ git commit -m "first commit"
[mac] $ git branch -M main

※ 2020/10/1 からデフォルトブランチがmasterからmainに変更されました。

リモートリポジトリを登録します。
リモートリポジトリ先は適宜置き換えてください。

[mac] $ git remote add origin git@github.com:ucan-lab/docker-laravel-handson.git

リモートリポジトリ先が正しく設定されていることを確認してください。

[mac] $ git remote -v
origin  git@github.com:ucan-lab/docker-laravel-handson.git (fetch)
origin  git@github.com:ucan-lab/docker-laravel-handson.git (push)

# もしリモートリポジトリ先を間違えた場合は下記のコマンドから変更できます。
[mac] $ git remote set-url origin <リモートリポジトリ>

リモートリポジトリ先の名前を origin と付けられていること。
リモートリポジトリ先のURL等に間違いがないことを確認する。

GitHubへpushします。

[mac] $ git push -u origin main
  • -u オプションは --set-upstream の省略
    • ローカルリポジトリの現在のブランチ(main)をリモートリポジトリ(origin)のmainにpush先を設定
    • 以降は git push だけで git push origin main と同義

GitHubのリモートリポジトリのmainブランチへpushされていることを確認します。

お好みのGUIエディタで開く

ymlファイルをCUIエディタで書いていくのは大変なのでお好みのGUIエディタ(今回はVSCode)で開きます。
code コマンドがインストールされていれば、簡単にプロジェクトをVSCodeで開けます。

[mac] $ code .

ScreenShot 2020-10-15 2.34.39.png

また、 control + shift + @ で統合ターミナルをVSCodeで開くことができます。
ファイルの編集もコマンドの実行もVSCodeだけで行えます。

ScreenShot 2020-10-15 2.36.26.png

アプリケーションサーバ(app)コンテナを作る

PHPアプリケーションサーバコンテナを作成します。
公式のPHP-FPMイメージをベースイメージとしてカスタマイズします。

ディレクトリ構成

.
├── infra
│   └── php
│       ├── Dockerfile
│       └── php.ini # PHPの設定ファイル
├── backend # Laravelをインストールするディレクトリ
└── docker-compose.yml

docker-compose.yml を作成する

touch コマンドで空ファイルを作成してますが、作成後はお好みのエディタで編集ください。
ファイル名のタイプミス防止のため空ファイルだけ作成してます。
当ハンズオンはこの流れで進めていきます。

[mac] $ touch docker-compose.yml

作成した docker-compose.yml を下記の通りに編集します。

docker-compose.yml
version: "3.8"
services:
  app:
    build: ./infra/php
    volumes:
      - ./backend:/work
  • docker-compose.yml ファイルはインデント(半角スペース)が意味を持ちます。注意してコピペしてください。

docker-compose.yml: 設定値の補足

docker-compose.yml
version: "3.8"

Docker Composeファイルのバージョンを指定しています。

通常はメジャー番号とマイナー番号を両方指定します。
ちなみにマイナーバージョンを指定しない場合はデフォルト0が使用されます。

docker-compose.yml
# 下記は同じ指定になる
version: "3"
version: "3.0"
docker-compose.yml
services:
  app: # => サービス名は任意
    build: ./infra/php
    volumes:
      - ./backend:/work

サービス名に app (アプリケーションサーバー)の名前を付けて定義しています。
サービス名は任意に決められます。

build: で指定しているのはビルドコンテキストを指定します。
ビルドコンテキストとは、docker buildを実行する際の現在の作業ディレクトリのことをビルドコンテキスト(build context)と呼びます。

Dockerfile が置かれている ./infra/php ディレクトリをビルドコンテキストとして指定します。
Dockerビルドの際は Dockerfile のファイルを探すので、ファイル名の指定は不要です。

volumes: ではホスト側のディレクトリや名前付きボリュームをコンテナ側へマウントしたい時に指定します。
今回はホスト側の ./backend ディレクトリをappサービスのコンテナ内 /work へマウントしてます。

./docker/php/Dockerfile を作成する

  • Composerコマンドのインストール
  • Laravelで必要なPHP拡張機能のインストール
    • bcmath, pdo_mysql が不足しているので追加インストール
[mac] $ mkdir -p infra/php
[mac] $ touch infra/php/Dockerfile

下記のコードを丸ごとコピーして Dockerfile へ貼り付けてください。

infra/php/Dockerfile
FROM php:7.4-fpm-buster
SHELL ["/bin/bash", "-oeux", "pipefail", "-c"]

ENV COMPOSER_ALLOW_SUPERUSER=1 \
  COMPOSER_HOME=/composer

COPY --from=composer:1.10 /usr/bin/composer /usr/bin/composer

RUN apt-get update && \
  apt-get -y install git unzip libzip-dev libicu-dev libonig-dev && \
  apt-get clean && \
  rm -rf /var/lib/apt/lists/* && \
  docker-php-ext-install intl pdo_mysql zip bcmath

COPY ./php.ini /usr/local/etc/php/php.ini

WORKDIR /work

./docker/php/Dockerfile: 設定値の補足

Dockerfileはテキストファイルであり、Dockerイメージを作り上げるために実行する命令をこのファイルに含めることができます。

各種Docker命令を解説します。

FROM php:7.4-fpm-buster

FROM命令はイメージビルドのためのベースイメージを設定します。
FROM イメージ名:タグ名 で指定します。

php | Docker Hub公式イメージをベースイメージとして利用します。

SHELL ["/bin/bash", "-oeux", "pipefail", "-c"]

SHELL命令は何も指定しない場合は SHELL ["/bin/sh", "-c"] がデフォルト値となります(Linuxの場合)

パイプ中のあらゆる段階でエラーがあれば失敗とするため、pipefailオプションを明示的に指定してます。

-o オプションはオプションを設定するためのオプションです。
-e オプションを定義しておくと、そのシェルスクリプト内で何らかのエラーが発生した時点で、それ以降の処理を中断できます。
-u オプションを定義しておくと、未定義の変数に対して読み込み等を行おうとした際にエラーとなります。
-x オプションを定義しておくと、実行したコマンドを全て標準エラー出力に出してくれます。

おまじないと思ってもらえればokです。SHELL命令は必須ではないです。

ENV COMPOSER_ALLOW_SUPERUSER=1 \
  COMPOSER_HOME=/composer

ENV命令はコンテナ内のサーバー環境変数を設定します。

COPY --from=composer:1.10 /usr/bin/composer /usr/bin/composer

RUN apt-get update && \
  apt-get -y install git unzip libzip-dev libicu-dev libonig-dev && \
  apt-get clean && \
  rm -rf /var/lib/apt/lists/* && \
  docker-php-ext-install intl pdo_mysql zip bcmath

Debian系のパッケージ管理ツールは apt-get, apt とありますが、Dockerfile内で apt を実行するとCLIインターフェース向けではないと警告が表示されるため、apt-getを使用します。

apt-get update インストール可能なパッケージの「一覧」を更新します。
実際のパッケージのインストール、アップグレードなどは行いません。

apt-get -y install xxx Laravelのインストールに必要なパッケージをインストールします。
下記のパッケージをインストールしておけばokだと思います。

apt-get clean && rm -rf /var/lib/apt/lists/* ここはパッケージインストールで使用したキャッシュファイルを削除しています。

phpの公式Dockerイメージには、docker-php-ext-install, docker-php-ext-enable, docker-php-ext-configure のPHP拡張ライブラリを簡単に利用するための便利コマンドが予め用意されています。

docker-php-ext-install intl pdo_mysql zip bcmath PHPの拡張ライブラリをインストールしています。

COPY ./php.ini /usr/local/etc/php/php.ini

WORKDIR /work

./docker/php/php.ini を作成する

php.ini はPHPの設定ファイル

  • PHPエラーメッセージの設定
  • PHPエラーログの設定
  • メモリ等の設定(お好みで)
  • タイムゾーン設定
  • 文字コード設定
[mac] $ touch infra/php/php.ini
php.ini
zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /dev/stderr
default_charset = UTF-8

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
mbstring.language = Japanese

build & up

  • appコンテナの作成
  • PHPのバージョン確認
  • Laravelで必要なPHP拡張機能の確認
[mac] $ docker-compose up -d --build
  • docker-compose コマンドは docker-compose.yml があるディレクトリで実行します。
  • docker-compose updocker-compose.yml に定義したサービスを起動します。
  • -d 「デタッチド」モードでコンテナを起動します。
    • デフォルトは「アタッチド」モードで全てのコンテナログを画面上に表示
    • 「デタッチド」モードではバックグラウンドで動作
  • --build コンテナの開始前にイメージを構築します
    • 特に変更がない場合はキャッシュが使用されます。
[mac] $ docker-compose ps
            Name                          Command              State    Ports  
-------------------------------------------------------------------------------
docker-laravel-handson_app_1   docker-php-entrypoint php-fpm   Up      9000/tcp

docker-laravel-handson_app_1 コンテナの State が Up になっていたら正常に起動している状態です。

  • docker-compose ps コンテナ一覧を表示します。
    • Name: コンテナ名
    • Command: 最後に実行されたコマンド
    • State: 状態(Up)はコンテナが起動している状態
    • Ports: 9000/tcp(コンテナのポート)
    • 9000番のホストポートは公開されていないので、コンテナの外からはアクセスできない

appコンテナ内ミドルウェアのバージョン確認(コンテナに入ってコマンド実行)

作成したappコンテナの中に入ってPHP, Composerのバージョン、インストール済みの拡張機能を確認します。
Laravel 7.xのサーバ要件に必要な拡張機能が入っていることを確認します。

[mac] $ docker-compose exec app bash

# PHPのバージョン確認
[app] # php -v
PHP 7.4.6 (cli) (built: May 15 2020 13:01:21) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies

# Composerのバージョン確認
[app] # composer -V
Composer version 1.10.10 2020-08-03 11:35:19

# インストール済みの拡張機能の一覧
[app] # php -m
[PHP Modules]
bcmath
Core
ctype
curl
date
dom
fileinfo
filter
ftp
hash
iconv
intl
json
libxml
mbstring
mysqlnd
openssl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
readline
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zip
zlib

[Zend Modules]

exit でコンテナの外に出ます。

[app] $ exit

control + d でもコンテナから出られます。

補足説明

appコンテナ内に入ってphpコマンドを実行しています。

  • docker-compose exec 実行中のコンテナ内で、コマンドを実行します。
  • app サービス名(コンテナ名)を指定します。

PHPのバージョン確認(コンテナの外からコマンド実行)

コンテナの外から php コマンドを実行することもできます。

  • docker-compose exec [サービス名] [実行したいコマンド]
[mac] $ docker-compose exec app php -v
PHP 7.4.6 (cli) (built: May 15 2020 13:01:21) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies

結果にコミット

[mac] $ git status
  (use "git add <file>..." to include in what will be committed)
    docker-compose.yml
    infra/php/Dockerfile
    infra/php/php.ini

[mac] $ git add .
[mac] $ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    new file:   docker-compose.yml
    new file:   infra/php/Dockerfile
    new file:   infra/php/php.ini

[mac] $ git commit -m "feat create docker app container"
[main f5a637f] feat create docker app container
 3 files changed, 49 insertions(+)
 create mode 100644 docker-compose.yml
 create mode 100644 infra/php/Dockerfile
 create mode 100644 infra/php/php.ini

[mac] $ git log

ウェブサーバー(web)コンテナを作る

nginxウェブサーバーコンテナを作成します。
nginxのベースイメージをそのまま利用します。

ディレクトリ構成

.
├── infra
│   └── nginx
│       └── default.conf # nginxの設定ファイル
├── backend
│  └── public # 動作確認用に作成
│       ├── index.html # HTML動作確認用
│       └── phpinfo.php # PHP動作確認用
└─── docker-compose.yml

docker-compose.yml へ追記する

  • ポート転送の設定(今回は10080ポートにする)
  • タイムゾーンの設定
version: "3.8"
services:
  app:
    build: ./infra/php
    volumes:
      - ./backend:/work

  # 追記
  web:
    image: nginx:1.18-alpine
    ports:
      - 10080:80
    volumes:
      - ./backend:/work
      - ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf
    working_dir: /work
  • docker-compose.yml ファイルはインデント(半角スペース)が意味を持ちます。注意してコピペしてください。
  • app コンテナの設定と同じインデントレベルで貼り付けます。

docker-compose.yml: 設定値の解説

    image: nginx:1.18-alpine

コンテナを起動させるイメージを指定します。
nginx | Docker Hubを指定してます。
今回は公式のnginxイメージをそのまま利用しています。(Dockerfileは不要)

ちなみにnginxは1.10, 1.12 等の偶数のバージョンが安定バージョンになります。
特に理由がなければ偶数バージョンをご利用ください。

    ports:
      - 10080:80

nginxへ外(ホスト側)からコンテナ内へアクセスさせるため公開用のポートを設定します。
ホスト側:コンテナ側 と設定します。

    volumes:
      - ./backend:/work
      - ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf

ホスト側にあるディレクトリ、ファイルをコンテナ内へマウントさせています。

docker/nginx/default.conf を作成する

[mac] $ mkdir infra/nginx
[mac] $ touch infra/nginx/default.conf

Laravel公式にnginxの設定例が用意されているので、こちらを流用します。
https://readouble.com/laravel/7.x/ja/deployment.html

default.conf
server {
    listen 80;
    server_name example.com;
    root /work/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    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$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

root, fastcgi_pass ドキュメントルート設定を書き換えてます。
nginxの設定を詳しく知りたい方は下記の記事がオススメです。

build & up

[mac] $ docker-compose down
[mac] $ docker-compose up -d --build
  • docker-compose コマンドは docker-compose.yml があるディレクトリで実行します。
[mac] $ docker-compose ps
            Name                          Command              State           Ports        
--------------------------------------------------------------------------------------------
docker-laravel-handson_app_1   docker-php-entrypoint php-fpm   Up      9000/tcp             
docker-laravel-handson_web_1   nginx -g daemon off;            Up      0.0.0.0:10080->80/tcp

docker-laravel-handson_web_1 コンテナの State が Up になっていたら正常に起動している状態です。

また、Ports の項目が、appコンテナは9000/tcp でwebコンテナは 0.0.0.0:10080->80/tcp と表示形式が異なってます。
これはホスト上の10080番ポートをコンテナの80番ポートへ割り当てています。

nginxのバージョン確認

[mac] $ docker-compose exec web nginx -v
nginx version: nginx/1.18.0

webコンテナの確認

  • webコンテナの動作確認
  • HTMLとPHPが表示されるか
[mac] $ mkdir backend/public
[mac] $ echo "Hello World" > backend/public/index.html
[mac] $ echo "<?php phpinfo();" > backend/public/phpinfo.php

「Hello World」が表示されることを確認する。

phpinfoの情報が表示されることを確認する。

[mac] $ rm -rf backend/*

確認用に作成したHTML, PHPファイルは不要なので削除します。

結果にコミット

[mac] $ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   docker-compose.yml
    modified:   infra/php/Dockerfile

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    infra/nginx/default.conf

[mac] $ git add .
[mac] $ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   docker-compose.yml
    new file:   infra/nginx/default.conf
    modified:   infra/php/Dockerfile

[mac] $ git commit -m "feat create docker web container"
[main 5e278c1] feat create docker web container
 3 files changed, 29 insertions(+), 1 deletion(-)
 create mode 100644 infra/nginx/default.conf

[mac] $ git log

Laravelをインストールする

  • app コンテナに入り、Laravelをインストール
  • welcomeページが表示されるか
[mac] $ docker-compose exec app bash
[app] $ composer create-project --prefer-dist "laravel/laravel=8.*" .
[app] $ php artisan -V
Laravel Framework 8.0.0

[app] $ exit

Laravel ウェルカム画面の表示

LaravelのWelcome画面が表示されることを確認する。

結果にコミット

[mac] $ git status
[mac] $ git add .
[mac] $ git status
[mac] $ git commit -m "feat laravel install"
[mac] $ git log

データベース(db)コンテナを作る

MySQLデータベースコンテナを作成します。
MySQLのベースイメージをそのまま利用します。

参考記事

ディレクトリ構成

.
├── infra
│   └── mysql
│       ├── Dockerfile
│       └── my.cnf # MySQLの設定ファイル
└── docker-compose.yml

docker-compose.yml へ追記する

  • データベース名やユーザー名等の接続情報とタイムゾーンの設定は環境変数で渡す
  • トップレベルvolumeを使用してデータの永続化
version: "3.8"
services:
  app:
    build: ./infra/php
    volumes:
      - ./backend:/work

  web:
    image: nginx:1.18-alpine
    ports:
      - 10080:80
    volumes:
      - ./backend:/work
      - ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf
    working_dir: /work

  # 追記
  db:
    build: ./infra/mysql
    volumes:
      - db-store:/var/lib/mysql

volumes:
  db-store:

./docker/mysql/Dockerfile を作成する

[mac] $ mkdir infra/mysql
[mac] $ touch infra/mysql/Dockerfile

下記のコードを丸ごとコピーして Dockerfile へ貼り付けてください。

infra/mysql/Dockerfile
FROM mysql:8.0

ENV MYSQL_DATABASE=laravel_local \
  MYSQL_USER=phper \
  MYSQL_PASSWORD=secret \
  MYSQL_ROOT_PASSWORD=secret \
  TZ=Asia/Tokyo

COPY ./my.cnf /etc/mysql/conf.d/my.cnf
RUN chmod 644 /etc/mysql/conf.d/my.cnf

コメントでいただいたのですが、Windows環境でボリュームマウントを行うと、ファイルパーミッションが777となるようです。
my.cnf に書き込み権限が付いてるとMySQLの起動時にエラーが発生します。
その対策としてボリュームマウントではなくDockerfileを作成して my.cnf ファイルコピー、読み取り専用に権限変更してます。

docker/mysql/my.cnf を作成する

  • 文字コードの設定
  • タイムゾーンの設定
  • ログ設定
[mac] $ mkdir infra/mysql
[mac] $ touch infra/mysql/my.cnf
my.cnf
[mysqld]
# character set / collation
character_set_server = utf8mb4
collation_server = utf8mb4_0900_ai_ci

# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM

# Error Log
log-error = mysql-error.log

# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0

# General Log
general_log = 1
general_log_file = mysql-general.log

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4

build & up

[mac] $ docker-compose down
[mac] $ docker-compose up -d --build
  • docker-compose コマンドは docker-compose.yml があるディレクトリで実行します。
[mac] $ docker-compose ps
            Name                          Command              State           Ports        
--------------------------------------------------------------------------------------------
docker-laravel-handson_app_1   docker-php-entrypoint php-fpm   Up      9000/tcp             
docker-laravel-handson_db_1    docker-entrypoint.sh mysqld     Up      3306/tcp, 33060/tcp  
docker-laravel-handson_web_1   nginx -g daemon off;            Up      0.0.0.0:10080->80/tcp

docker-laravel-handson_db_1 コンテナの State が Up になっていたら正常に起動している状態です。

[mac] $ docker-compose exec db mysql -V
mysql  Ver 8.0.20 for Linux on x86_64 (MySQL Community Server - GPL)

マイグレーション実行(エラーが発生します)

[mac] $ docker-compose exec app bash
[app] $ php artisan migrate

   Illuminate\Database\QueryException 

  SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.tables where table_schema = laravel and table_name = migrations and table_type = 'BASE TABLE')

  at vendor/laravel/framework/src/Illuminate/Database/Connection.php:671
    667▕         // If an exception occurs when attempting to run a query, we'll format the error
    668▕         // message to include the bindings with SQL, which will make this exception a
    669▕         // lot more helpful to the developer instead of just the database's errors.
    670▕         catch (Exception $e) {
  ➜ 671▕             throw new QueryException(
    672▕                 $query, $this->prepareBindings($bindings), $e
    673▕             );
    674▕         }
    675▕ 

      +37 vendor frames 
  38  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

[app] $ exit

SQLSTATE[HY000] [2002] Connection refused このエラーはよく見るMySQLのエラーです。
MySQLに接続拒否されたエラーなので、この場合は大体MySQLへの接続設定に誤りがあります。

backend/.env のDB接続設定を修正する。

[mac] $ vim backend/.env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel_local
DB_USERNAME=phper
DB_PASSWORD=secret

backend/.env.example も同様にDB接続設定を修正しておきます。

[mac] $ vim backend/.env.example
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel_local
DB_USERNAME=phper
DB_PASSWORD=secret

マイグレーション実行(再実行)

[mac] $ docker-compose exec app bash
[app] $ php artisan migrate

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.07 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.04 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.02 seconds)

試しにデータを作ってみる

[mac] $ docker-compose exec app bash
[app] php artisan tinker
$user = new App\Models\User();
$user->name = 'phper';
$user->email = 'phper@example.com';
$user->password = Hash::make('secret');
$user->save();
[mac] $ docker-compose exec db bash
[db] $ mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE
[mysql] > SELECT * FROM users;
+----+--------------------+-----------------------------+---------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| id | name               | email                       | email_verified_at   | password                                                     | remember_token | created_at          | updated_at          |
+----+--------------------+-----------------------------+---------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
|  1 | phper              | phper@example.com           | NULL                | $2y$10$/cmcAIdF7twOntcazkn4/e61YAM2F99hCrOo.qRUz7cUa/ZydrbVS | NULL           | 2020-08-24 17:09:53 | 2020-08-24 17:09:53 |
+----+--------------------+-----------------------------+---------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
1 rows in set (0.00 sec)

結果にコミット

[mac] $ git status
[mac] $ git add .
[mac] $ git status
[mac] $ git commit -m "feat create docker db container"
[mac] $ git log

GitHubにpush

[mac] $ git push

リモートリポジトリへpushされていることを確認します。

Docker環境の再構築

Docker環境の破棄

コンテナの停止、ネットワーク・名前付きボリューム・コンテナイメージ、未定義コンテナを削除

[mac] $ docker-compose down --rmi all --volumes --remove-orphans

作業ディレクトリの削除

プロジェクトを削除するので、GUIエディタは閉じておきましょう。

[mac] $ cd ..
[mac] $ rm -rf docker-laravel-handson

Visual Studio Code等のGUIエディタで開いている場合は、一度エディタを終了しましょう。

環境の再構築

GitHubからリポジトリをクローン

** 自身のリポジトリ先に適宜変更してください **

[mac] $ git clone git@github.com:ucan-lab/docker-laravel-handson.git
[mac] $ cd docker-laravel-handson
[mac] $ docker-compose up -d --build

/work/public/../vendor/autoload.php を開くのに失敗してエラーになっていることを確認します。
git cloneが終わった状態では app コンテナ内に /work/vendor ディレクトリが存在しないためです。

Laravelインストール

app コンテナに入ります。

[mac] $ docker-compose exec app bash

vendor ディレクトリへライブラリ群をインストールします。
composer.lock ファイルを参照します。

[app] $ composer install

composer install 時は .env 環境変数ファイルは作成されないので、 .env.example を元にコピーして作成します。

[app] $ cp .env.example .env

スクリーンショット 2019-09-29 2.10.51.png

.envAPP_KEY= の値がないとこのエラーが発生します。
このコマンドでアプリケーションキーを生成できます。

[app] $ php artisan key:generate

Welcome画面が表示されることを確認します。

[app] $ php artisan migrate

最後にマイグレーションを実行して成功すればハンズオン終了です。
お疲れ様でした🙌🙌 コンテナを停止して終了してください。

[app] $ exit
[mac] $ docker-compose down

オマケ

MySQLに接続したい

[mac] $ docker-compose exec db bash -c 'mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE}'

mysql> show tables;
+---------------------+
| Tables_in_homestead |
+---------------------+
| migrations          |
| password_resets     |
| users               |
+---------------------+
3 rows in set (0.00 sec)

mysql> desc users;
+-------------------+---------------------+------+-----+---------+----------------+
| Field             | Type                | Null | Key | Default | Extra          |
+-------------------+---------------------+------+-----+---------+----------------+
| id                | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| name              | varchar(255)        | NO   |     | NULL    |                |
| email             | varchar(255)        | NO   | UNI | NULL    |                |
| email_verified_at | timestamp           | YES  |     | NULL    |                |
| password          | varchar(255)        | NO   |     | NULL    |                |
| remember_token    | varchar(100)        | YES  |     | NULL    |                |
| created_at        | timestamp           | YES  |     | NULL    |                |
| updated_at        | timestamp           | YES  |     | NULL    |                |
+-------------------+---------------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)

マイグレーションが実行されるとLaravel側で最初から用意されている users, password_resets のテーブルが生成されています。

Laravelのログをコンテナログに表示する

backend/.env を修正する。

LOG_CHANNEL=stderr

backend/routes/web.php

Route::get('/', function () {
    logger('welcome route.');
    return view('welcome');
});

$ docker-compose logs
# -f でログウォッチ
$ docker-compose logs -f
# サービス名を指定してログを表示
$ docker-compose logs -f app

MySQLクライアントツールで接続したい

docker-compose.ymldb サービスに下記設定を追記して、コンテナを再起動して設定を反映してください。

    ports:
      - 33060:3306

dbコンテナへのポート転送設定がないとホストからアクセスが行えません。
MySQLクライアントツールは「Sequel Ace」がオススメです。

Windowsエラーメモ

Error response from daemon

$ docker-compose up -d --build
docker: Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).

解決策をいくつか

マイグレーションエラーの補足

Host '172.27.0.2' is not allowed to connect to this MySQL server

$ php artisan migrate
   Illuminate\Database\QueryException  : SQLSTATE[HY000] [1130] Host '172.27.0.2' is not allowed to connect to this MySQL server (SQL: select * from information_schema.tables where table_schema = homestead and table_name = migrations and table_type = 'BASE TABLE')

  at /work/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
    660|         // If an exception occurs when attempting to run a query, we'll format the error
    661|         // message to include the bindings with SQL, which will make this exception a
    662|         // lot more helpful to the developer instead of just the database's errors.
    663|         catch (Exception $e) {
  > 664|             throw new QueryException(
    665|                 $query, $this->prepareBindings($bindings), $e
    666|             );
    667|         }
    668| 

  Exception trace:

  1   PDOException::("SQLSTATE[HY000] [1130] Host '172.27.0.2' is not allowed to connect to this MySQL server")
      /work/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70

  2   PDO::__construct("mysql:host=db;port=3306;dbname=homestead", "homestead", "secret", [])
      /work/vendor/laravel/framework/src/Illuminate/Database/Connectors/Connector.php:70

  Please use the argument -v to see more details.

このエラーが発生した場合は my.cnf を作成する前に docker-compose up -d でビルドしてしまった可能性が高いです。

$ docker-compose down --volumes --rmi all
$ docker-compose up -d --build

設定ファイルがない状態でMySQLの初期化が行われたでデータが永続化されてしまってるので一度ボリューム毎削除してビルドし直せばokです。

docker volumes の共有で Permission denied (SELinux) 問題

CentOS 等の場合 volumes でホストと共有したファイル(ディレクトリ)にアクセスできないことがあります。

書き込み権限を与える

$ chmod -R 777 logs
$ chmod -R 777 src/storage/logs

ログディレクトリはホスト側からもコンテナ側からも書き込みするので、書き込み権限を付与しておきましょう。

応用

より実用的な構成のdocker構成の記事を書いてますので、よかったらこちらの記事も読んでもらえると嬉しいです。

952
Help us understand the problem. What is going on with this article?
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
ucan-lab
Backend Developer at ROLO. I love PHP and I'm focusing on Laravel, Docker, GraphQL.
yyphp
PHPerが毎週集まり、ざっくばらんに情報交換する雑談コミュニティ

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
952
Help us understand the problem. What is going on with this article?