【WSL2】DockerでLaravel開発環境を構築する -Part1-

【WSL2】DockerでLaravel開発環境を構築する -Part1-

はじめに

この記事では、WSL2 を使用して Docker + Laravel の開発環境(LAMP 環境)を構築するまでの手順を解説しています。

WSL2 をインストール済みであることを前提としています。

WSL2 を導入するまでの手順は以下の記事で紹介しています。

やりたいこと

この記事では最終的に以下の機能を持った開発環境を構築していきます。今回は、太字の部分を実装していきます。

  • Lravel の開発環境
  • npm を導入して JavaScript FW の開発にも対応する
  • リバースプロキシを導入して test.example.comのようなポート番号無しのドメインでアクセスできるようにする
  • mailhog を導入してメール送信のテストを行えるようにする
  • X-Debug の導入

開発環境

  • OS: Windows11(21H2)
  • WSL: Ubuntu-20.04 Version 2
  • Docker: Version 20.10.9
  • Docker Compose: Version 1.29.2

ディレクトリ構成

今回作成するプロジェクトのディレクトリ構成は以下のようになっています。

適宜アレンジしてもらっても構いません。

docker-lamp
├── docker
│   ├── mailhog
│   │   └── Dockerfile
│   ├── mysql
│   │   ├── Dockerfile
│   │   ├── init
│   │   │   └── init.sql
│   │   └── my.cnf
│   ├── nginx-proxy
│   │   └── Dockerfile
│   ├── phpMyAdmin
│   │   └── Dockerfile
│   └── web
│       ├── Dockerfile
│       ├── apache
│       │   └── 000-default.conf
│       └── php
│           └── php.ini
├── docker-compose.yml
└── htdocs
        └─ ここにLaravelのプロジェクトを作成する

Docker Compose とは?

Docker Compose とは、複数のコンテナの起動や停止・破棄などの処理を一連の操作をまとめて実行することができ、管理を容易にする機能のことです。

設定ファイルを用意し、コマンドを実行することでその設定ファイルを読み込んで全てのコンテナを起動することが出来ます。

docker-compose.yml の設定

docker-compose.ymlとは、Docker Compose を使ってコンテナを一元管理するための設定ファイルです。

今回使用するファイルの全体像です。

# Compose fileのバージョン指定
version: '3.8'

# 立ち上げるコンテナを記述していく
services:
  nginx-proxy:
    container_name: nginx-proxy-container
    build: ./docker/nginx-proxy
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro

  # ApacheとPHPが動作するコンテナ
  web:
    # コンテナ名を指定する
    container_name: web-container
    # 作成したDockerfileを利用してコンテナをビルドする
    build: ./docker/web
    # ポートのマッピングを設定する
    # 下記の記述だと、localhost:8081とブラウザから指定すると、Apacheの80番ポートに接続される
    ports:
      - 8081:80
    # コンテナとホスト側のディレクトリを同期させる設定
    volumes:
      # Laravelのソースが入る箇所を同期
      - ./htdocs:/var/www/html

  # MySQLを動かすコンテナ
  database:
    # コンテナ名を指定
    container_name: db-container
    build: ./docker/mysql
    volumes:
      # ボリュームにマウントしデータを永続化する
      - db-store:/var/lib/mysql
    ports:
      - 3306:3306

  # PHPMyadminを動かすコンテナ
  phpmyadmin:
    # コンテナ名を指定
    container_name: phpmyadmin-container
    build: ./docker/phpMyAdmin
    ports:
      - 8082:80
    # 依存関係をMySQLに設定
    depends_on:
      - database

  # mailhogのコンテナ
  mailhog:
    # コンテナ名を指定
    container_name: mailhog-container
    build: ./docker/mailhog
    ports:
      # 管理画面に接続するポート(違うポート番号にすると管理画面に接続できない)
      - 8025:8025

# 使用するボリュームを指定
volumes:
  db-store:

docker-compose.yml のバージョン

まず最初に、Compose File のバージョンを指定する必要があります。

# Compose fileのバージョン指定
version: '3.8'

2021 年 10 月時点で、version3.8を指定していれば問題ありません。

ただし、Compose ファイル形式をサポートしている Docker Engine のバージョンを合わせる必要があります。使用している環境に合わせて変更する必要がある場合があるので注意してください。

https://docs.docker.jp/compose/compose-file/compose-versioning.html

さらに詳細を知りたい場合は公式ページを参照してください。

各種コンテナの設定

コンテナの設定はservices:配下に記述していきます。ymlファイルはインデントを基準にして階層構造を作っていきます。要は設定項目を区切っていく形になります。

services:
  # 立ち上げるコンテナを記述していく
#↑インデントで階層を合わせる

ファイルの先頭にリバースプロキシの設定を記述していますが、先にその他のサーバの設定を見ていたほうが分かりやすいと思ったので別の記事で紹介します。

Web サーバの設定

まずは Web サーバの設定です。

services:
  # 中略

  # ApacheとPHPが動作するコンテナ
  web:
    # コンテナ名を指定する
    container_name: web-container
    # 作成したDockerfileを利用してコンテナをビルドする
    build: ./docker/web
    # ポートのマッピングを設定する
    # 下記の記述だと、localhost:8081とブラウザから指定すると、Apacheの80番ポートに接続される
    ports:
      - 8081:80
    # コンテナとホスト側のディレクトリを同期させる設定
    volumes:
      # Laravelのソースが入る箇所を同期
      - ./htdocs:/var/www/html

サービス名は任意の名前を付けることができます。そのプロジェクトで何のサーバを動かしているか分かりやすい名前にするのが良いと思います。

コンテナ名の指定

ここではコンテナ名を指定しています。

container_name: web-container

必須項目ではありませんが、コンテナが複数存在して分かりにくい場合は明示しておくことで、どのプロジェクトと関係しているものなのか判別できると思います。

build:

Dockerfile のディレクトリのパスを指定します。

build: ./docker/web

今回のプロジェクトでは、dockerディレクトリ配下に Dockerfile を配置しているのでそのディレクトリを指定しています。

ymlファイルのある場所を起点としてパスを指定します。

port:

ポートマッピングの設定を行います。ポートマッピングとは、ブラウザ側からポートを指定してアクセスをした場合、動作しているコンテナのポートと対応づけを行うことです。

ports:
  - 8081:80

この設定ではブラウザ側からhttp://localhost:8081とアクセスした場合に、動作しているコンテナの80番ポートにリクエストが対応されます。

80 番ポートは、Web サーバが Web ブラウザなどと HTTP 通信を行うために使用するポートです。

volumes:

volumeとは、データを永続化出来る場所のことです。イメージ的には外付け HDD のような役割を果たします。

通常コンテナ起動後、内部にデータを保存してもコンテナを破棄すると消えてしまいます。そのため、ホスト側の指定したディレクトリとコンテナ内のディレクトリをマウントさせることで、コンテナを停止したあともデータを保持することが出来ます。

volume を同期させるなどと言われることもあります。

# コンテナとホスト側のディレクトリを同期させる設定
volumes:
  # ホスト側:コンテナ側
  - ./htdocs:/var/www/html # Laravelのソースが入る箇所

Dockerfile の設定

Web サーバで使用する Dockerfile を作成します。

ここでは主に、Apache や PHP を実行するために必要なモジュールのインストールや、設定ファイルをコンテナにコピーする処理などが実行されます。

"docker/web/Dockerfile"
FROM php:8.1.9-apache-bullseye

# apacheの設定ファイルをコンテナにコピー
COPY ./apache/000-default.conf /etc/apache2/sites-available/000-default.conf
# phpの設定ファイルをコンテナにコピー
COPY ./php/php.ini /usr/local/etc/php/php.ini

# パッケージの更新及び必要ソフトのインストール
RUN apt-get update \
  && apt-get install -yqq \
  zlib1g-dev \
  libpq-dev \
  mariadb-client \
  unzip \
  libzip-dev \
  zip \
  && docker-php-ext-install \
  pdo_mysql \
  mysqli \
  # rewriteモジュールを有効化
  && a2enmod rewrite \
  && docker-php-ext-enable mysqli \
  # xdebug install
  && pecl install xdebug \
  && docker-php-ext-enable xdebug

# 指定したドメインでコンテナにルーティングされるように設定
# nginx-proxyに関連した設定
ENV VIRTUAL_HOST=test.example.com

# Composer Install
# 公式の Composer イメージを利用
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# rootユーザー実行した際に警告が出ないようにする
ENV COMPOSER_ALLOW_SUPERUSER 1
# Composerのホームディレクトリを変更
ENV COMPOSER_HOME /composer
# コマンドが実行できるようにパスを通す
ENV PATH $PATH:/composer/vendor/bin

# Node.js Install
RUN apt-get install -y nodejs \
  npm \
  && npm install n -g \
  && n latest

RUN composer global require "laravel/installer"

ここで指定したコマンドがdocker compose buildまたは初回実行時のdocker compose upで実行されます。

ベースのイメージを指定

まずベースとなるイメージを指定します。bullseye(ブルズアイ)は Debian 系の Linux ディストリビューションで構成されています。バージョンごとにコードネームが付けられており、Dcoker イメージのタグに使われています。

コードネームバージョン読み方
bullseyev11ブルズアイ
busterv10バスター
stretchv9ストレッチ
jessiev8ジェシー
"docker/web/Dockerfile
FROM php:8.1.9-apache-bullseye

このイメージではPHP 8.1.9が起動します。

PHP の設定

php.iniの設定を確認します。

"docker/web/php/php.ini"
[Date]
# タイムゾーンを日本に指定
date.timezone = "Asia/Tokyo"

[mbstring]
# デフォルトの言語を日本語に指定
mbstring.language = "Japanese"
# 内部エンコーディングを指定
mbstring.internal_encoding = "UTF-8"

# xdebugを使用するための設定
[xdebug]
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_host = host.docker.internal
xdebug.log = /tmp/xdebug.log
xdebug.client_port = 9013
xdebug.discover_client_host = 1

php.iniには php の実行環境を設定します。

ここで内部エンコーディングの指定に関してですが、公式ドキュメントにはこのように記載されています。

mbstring.language string
mbstring で使用される言語設定(NLS)のデフォルト値。 この設定は mbstring.internal_encoding を定義するため、 php.ini の中で mbstring.internal_encoding は、 mbstring.language後に置く必要があることに注意してください。

他の記事ではこの記述が逆になって記載しているものが多かったので注意してください。

mbstring.internal_encoding は非推奨

先程記述する順序について確認しましたが、mbstring.internal_encodingの設定は現在非推奨になっています。

警告 この非推奨の機能は、きっと 将来 削除 されるでしょう。
内部文字エンコーディングのデフォルト値を定義します。
この値は空のままにしておいて、代わりに default_charset を設定すべきです。

php.ini の設定を変更しておきます。

"docker/web/php/php.ini"
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.language = "Japanese"
default_charset = "UTF-8"
[xdebug]
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_host = host.docker.internal
xdebug.log = /tmp/xdebug.log
xdebug.client_port = 9013
xdebug.discover_client_host = 1

Composer をインストール

Composer をインストールする記述を確認します。

"docker/web/Dockerfile
# Composer Install
# 公式の Composer イメージを利用
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# rootユーザー実行した際に警告が出ないようにする
ENV COMPOSER_ALLOW_SUPERUSER 1
# Composerのホームディレクトリを変更
ENV COMPOSER_HOME /composer
# コマンドが実行できるようにパスを通す
ENV PATH $PATH:/composer/vendor/bin

バージョンを指定する場合は--from=composer:1.x.xのように指定します。今回は最新のバージョンを使用するためlatestを指定しています。

環境変数の詳細は公式ドキュメントを参考にしてください。

Node.js をインストール

nodejsnpmをインストールした後、細かくバージョンを指定できるようにnパッケージをインストールします。

"docker/web/Dockerfile
# Node.js Install
RUN apt-get install -y nodejs \
      npm \
    && npm install n -g \
    && n latest
    # ※2022年10月21日現在では v19.0.0 がインストールされる

npm のバージョンは各環境に合わせて必要なバージョンを指定してください。

MySQL の設定

次に MySQL の設定を見ていきます。

services:
  # 中略

  # MySQLを動かすコンテナ
  database:
    # コンテナ名を指定
    container_name: db-container
    build: ./docker/mysql
    volumes:
      # ボリュームにマウントしデータを永続化する
      - db-store:/var/lib/mysql
    ports:
      - 3306:3306

volumes:

volume の仕組みは前述したとおりです。設定している内容を確認します。

services:
  # 中略

  database:
    # 中略

    volumes:
      # ボリュームにマウントしデータを永続化する
      - db-store:/var/lib/mysql

Dockerfile の設定

ここでは環境変数の設定や、設定ファイルのコピーを実行する処理を記述しています。

必要であれば.envファイルで管理して下さい。

"docker/mysql/Dockerfile
FROM mysql:latest

# コンテナ内の環境変数を指定。詳細はDockerHubを確認
ENV TZ=Asia/Tokyo \
  MYSQL_DATABASE=docker-database \
  MYSQL_USER=docker \
  MYSQL_PASSWORD=docker \
  MYSQL_ROOT_PASSWORD=rootpass

# 設定ファイルをコンテナにコピー
COPY ./my.cnf /etc/mysql/conf.d/my.cnf
COPY ./init/* /docker-entrypoint-initdb.d/

mysql:latest

使用するイメージの指定はmysql:5.7のように:の後にタグを指定することができます。DockerHub を見ればわかりますが、各種イメージにはタグが振られているのでそれ指定することで、任意のイメージを取得します。

特にバージョンを指定しない限りmysql:latestのイメージを取得します。latestとは最新版のイメージのことです。

latest 版を使用する場合の注意点

公開されているイメージの内容は日々更新されており、環境構築するタイミングでは 3 ヶ月前のlatestイメージと、3 ヶ月後のlatestのイメージでは内容が異なったり、何らかの不具合が発生したりすることがあります。

公式ページのベストプラクティスにもこう書かれています。

イメージをビルドする場合には、常にわかりやすいタグをつけるようにします。 このタグを用いて、バージョン情報をコード化したり、目的とする用途(たとえば prod や test など)や安定性など、いろいろな情報を付与したりします。 こうしておけば、アプリケーションをさまざまな環境にデプロイする際にわかりやすくなります。 自動的に生成される latest タグには頼らないようにします。

必要に応じてバージョンを固定するようにしてください。

初回起動時に実行する SQL 文を指定

MySQL の Docker イメージでは、/docker-entrypoint-initdb.d/配下に.sh.sqlなどのスクリプトファイルを配置するとコンテナ起動時に実行させることが出来ます。

実行したい SQL 文を記述したファイルを作成して、

"docker/mysql/init/init.sql"
CREATE DATABASE IF NOT EXISTS sample_laravel

/docker-entrypoint-initdb.d/配下にコピーする処理を記述しておきます。

"docker/mysql/Dockerfile
COPY ./init/* /docker-entrypoint-initdb.d/

今回は、起動時に指定したデータベースが存在しなければ作成するというシンプルなsqlを実行させています。

my.conf

my.cnf ではサーバの設定を記述します。

"docker/mysql/my.conf"
[mysqld]
# デフォルトの文字セット
# この変数を設定する場合は、文字セットの照合順序を指定するように collation_server も設定する必要があります
character-set-server = utf8mb4
# サーバーのデフォルトの照合順序
collation-server = utf8mb4_unicode_ci

[client]
# クライアントから到達するステートメントの文字セット
default-character-set = utf8mb4

その他詳細は公式ドキュメントを参照して下さい。

phpMyAdmin の設定

次に、phpMyAdmin の設定を見ていきます。

services:
  # 中略

  # PHPMyadminを動かすコンテナ
  phpmyadmin:
    # コンテナ名を指定
    container_name: phpmyadmin-container
    build: ./docker/phpMyAdmin
    ports:
      - 8082:80
    # 依存関係をMySQLに設定
    depends_on:
      - database

Dockerfile の設定

使用するイメージを指定して環境変数を設定するシンプルな内容となっています。

注意点として、PMA_HOSTS=databaseは yml ファイルで指定したサービス名を指定するように注意してください。

"docker/phpMyAdmin/Dockerfile
FROM phpmyadmin/phpmyadmin:latest

ENV PMA_ARBITRARY=1 \
  # ↓ymlのサービス名と合わせる
  PMA_HOSTS=database \
  PMA_USER=root \
  PMA_PASSWORD=rootpass

環境変数

設定内容はDcokerHub の公式ページを参考にしました。

  • PMA_ARBITRARY=1:1 に設定すると、任意のサーバーへの接続が許可されます。
  • PMA_HOSTS=database:接続するデータベースを指定します。
  • PMA_USER=root:ログインユーザー名を指定します。
  • PMA_PASSWORD=root:ユーザーのパスワードを指定します。

depends_on:

depends_on:を指定することでコンテナ間の依存関係設定することが出来ます。

このように設定すると、db-containerphpmyadmin-containerの順番に起動します。

# 依存関係をMySQLに設定
depends_on:
  - database

その他詳細については、こちらの記事で詳しく解説されているので参考になると思います。

最後に

ここまでで各種コンテナの基本的な設定が完了しました。

次回ではリバースプロキシを導入してhttp://localhost:8080ではなく、任意のドメインで開発環境にアクセスできるようにしていきます。