こんにちは!
今回は、Dockerを使ってLaravelの開発環境の構築を手軽に行う方法を解説していきます。
Dockerの中身のコードに関してもわかりやすく解説していきます。
以下のような方が対象です。
- Dockerでの環境構築方法がわからない
- いつもコピペしてて応用が効かない
- Dockerfileの中身がわからない
この記事を読むことで、以下のことがわかります。
- Dockerの基礎知識
- Dockerを使ったLaravel開発環境の構築
- Docker Composeを使ったコンテナ管理
- 具体的なDockerコードの意味
- Docker環境のカスタマイズ
以下、筆者の経験です。
- プログラミング歴3年以上
- 現役ITエンジニア
- 自社サービスを0から開発した経験複数あり
それでは早速見ていきましょう!
本記事の前提条件
注意点として、今回はMacOSを想定した記事となっております。
その点ご注意ください。
また、Docker Desktopはすでにインストールが完了しているものとして進めます。
まだDocker Desktopをインストールしていないという方は、以下の記事からインストールすることをおすすめします。
【入門】Docker Desktopとは何ができるの?インストールと使い方
Dockerの基礎知識
Dockerとは
Dockerとは、Docker社が開発しているコンテナ型の仮想環境を作成、配布、実行するためのプラットフォームです。
Dockerはホストマシンのカーネルを利用し、ホストOSの上にコンテナと呼ばれる仮想環境を作成することができます。
このコンテナ型仮想環境の中で、アプリケーションを開発したり動かしたりすることができるわけです。
Dockerのメリット
では、Dockerを使うとなぜ良いのでしょうか。
それは以下のような利点があるからです。
- インフラをコード化することができる
- ファイルを共有することで誰でも全く同じ環境を手早く作ることができる
- 本番環境へのデプロイが容易
例えば開発チームがあったとして、開発メンバーはある人はWindowsのPC、ある人はMacのPCとバラバラで存在すると、ある人の環境ではアプリケーションが動くが、他方の環境では動かないといった現象が発生することがあります。
ところが、Dockerを使っていれば、開発メンバーは環境が同じなので一人一人アプリケーションの挙動が違うなんてことは起こりません。
こういった利点から、現在ではDockerが広く使用されるようになりました。
DockerでのLaravel環境構築手順
さて、ここから本記事の主題であるDockerを使ったLaravelの環境構築手順を解説していきます。
今回は以下の構成の環境を作成していきます。
- Webサーバー→Apache
- プログラミング言語→PHP
- フレームワーク→Laravel
- データベース→MySQL
- データベース管理→phpMyAdmin
次に、ディレクトリ構成は以下のようになります。
app
docker
|_app
| |_Dockerfile
| |_000-default.conf
| |_php.ini
|_db
|_Dockerfile
|_my.cnf
docker-compose.yml
今回のデモ環境のディレクトリを容易しておきましょう
$ mkdir demo
$ cd demo
Laravelプロジェクト作成
まずはじめに、Laravelプロジェクトを作成していきましょう。
以下のコマンドを叩きます。
$ composer create-project laravel/laravel=9.x --prefer-dist app
すると、/appのLaravelプロジェクトのディレクトリが作成されます。
Dockerfileの作成と設定
このセクションからは本記事の主題であるDockerfileの書き方などを解説していきます。
PHPとApacheの作成、設定
次に、PHPとApacheのDockerfileの作成に移っていきます。
docker/appディレクトリに移動し、Dockerfileを作成します。
$ mkdir docker && cd docker // dockerディレクトリ作成して移動
$ mkdir app && cd app // appディレクトリ作成して移動
$ touch Dockerfile // Dockerfile作成
少し補足しておくと、Dockerfileを作成する際のファイル名は必ずDockerfileにしておいてください。 これは決まりになっており、別の名前にすると動作しません。 ファイル名を変更することもできますが、その場合は別途設定を追加する必要が出てきます。
次に、テキストエディタでDockerfileを編集します。
FROM php:8.1-apache
COPY /docker/app/php.ini /usr/local/etc/php/
COPY /docker/app/000-default.conf /etc/apache2/sites-available/000-default.conf
# Composerのインストール
RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer
RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install pdo_mysql
# Laravelで必要になるmodRewriteを有効化する
RUN mv /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled
RUN /bin/sh -c a2enmod rewrite
順番に解説していきます。
まず、一番上の行。
FROM php:8.1-apache
Dockerfileでは、インストラクションと呼ばれるものに引数をつけて実行するのが基本です。
インストラクションには以下の種類があります。
- FROM・・・新たに作成するDockerイメージのベースとなるイメージを指定する
- RUN・・・Dockerイメージのビルド時に実行するシェルスクリプト
- CMD・・・Dockerコンテナが立ち上がった時にデフォルトで実行されるコマンド
- COPY・・・ホストのファイルやディレクトリをDockerイメージにコピーする
- ENV・・・Dockerfile内の環境変数を設定します。設定された環境変数はDockerfile内で使うことができ、Dockerイメージから生成される全てのコンテナで使用可能です
- WORKDIR・・・コマンドを実行する作業ディレクトリを指定します
そのため、一番上の行はこれから作成するDockerイメージのベースとなるイメージを指定しています。 今回の場合はPHPとApacheが入ったイメージをベースイメージとして指定しています。
次に、以下コマンドでPHPの設定ファイルとApacheの設定ファイルをコンテナの中にコピーしています。
COPY /docker/app/php.ini /usr/local/etc/php/
COPY /docker/app/000-default.conf /etc/apache2/sites-available/000-default.conf
次に、以下コマンドで今後必要となるcomposerをインストールしています。
RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer
次に、以下コマンドでgitやzipやvimなどの必要となるコマンドをインストールします。
RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install pdo_mysql
ポイントは、最初にapt-get update
でパッケージマネージャを最新の状態に更新してから実行することと、pdo_mysqlをインストールすることです。
最後に、Apacheで必要となるmod_rewriteを有効化しておきます。
RUN mv /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled
RUN /bin/sh -c a2enmod rewrite
mod_rewriteを簡単に説明しておくと、URLの操作やリダイレクト処理などを行なっているApacheの機能で、有効/無効に設定することができます。
基本的には有効にしておきましょう。
次に、PHPの設定ファイルであるphp.iniを作成します。
touch php.ini
テキストエディタを開いて編集します。
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.language = "Japanese"
memory_limit = 1024M
post_max_size = 256M
upload_max_filesize = 50M
max_execution_time = 600
extension=pdo_mysql
ここではタイムゾーンや日本語設定、メモリサイズなどの最低限の設定を行なっています。
次にApacheの設定ファイルを作成していきます。
$ cd .. && touch 000-default.conf // docker/appディレクトリに移動してファイル作成
テキストエディタを開いて編集します。
<VirtualHost *:80>
DocumentRoot /var/www/html/public
<Directory /var/www/html/public>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
MySQLの作成、設定
同様に、dbディレクトリを作成してMySQLのDockerfileも作成していきます。
mkdir db && cd db
touch Dockerfile
テキストエディタで編集します。
FROM mysql:8.0.29-debian
# 設定ファイルの上書き
COPY /docker/db/my.cnf /etc/mysql/conf.d
RUN chmod 644 /etc/mysql/conf.d
RUN mv /etc/apt/sources.list.d/mysql.list /etc/apt/sources.list.d/mysql.list.disabled
RUN apt-get update && apt-get install -y curl && apt-get clean
RUN curl -sSfL https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 | gpg --import
RUN gpg --batch --export "B7B3B788A8D3785C" > /etc/apt/keyrings/mysql.gpg
RUN mv /etc/apt/sources.list.d/mysql.list.disabled /etc/apt/sources.list.d/mysql.list
RUN apt-get update && apt-get install -y locales \
&& echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen \
&& locale-gen ja_JP.UTF-8 \
&& update-locale LANG=ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
CMD ["mysqld"]
こちらも流れはPHP,Apacheの場合とほぼ同様です。
以下でベースイメージを指定します。
FROM mysql:8.0.29-debian
次に、MySQLの設定ファイルをコンテナ内にコピーします。
COPY /docker/db/my.cnf /etc/mysql/conf.d
RUN chmod 644 /etc/mysql/conf.d
以下は、通常は設定しなくても動くはずですが、2024/02/21時点の筆者の環境ではGPGキーエラーが発生しておりましたので追記しました。
RUN mv /etc/apt/sources.list.d/mysql.list /etc/apt/sources.list.d/mysql.list.disabled
RUN apt-get update && apt-get install -y curl && apt-get clean
RUN curl -sSfL <https://repo.mysql.com/RPM-GPG-KEY-mysql-2023> | gpg --import
RUN gpg --batch --export "B7B3B788A8D3785C" > /etc/apt/keyrings/mysql.gpg
RUN mv /etc/apt/sources.list.d/mysql.list.disabled /etc/apt/sources.list.d/mysql.list
次に、ロケールや文字コードなどの設定を行います。
RUN apt-get update && apt-get install -y locales \
&& echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen \
&& locale-gen ja_JP.UTF-8 \
&& update-locale LANG=ja_JP.UTF-8
最後に、環境変数を設定してコンテナ起動時にmysqldコマンドを叩きます。
ENV LANG ja_JP.UTF-8
CMD ["mysqld"]
こちらでDockerfileは完成になります。
次に、MySQLの設定ファイルを作成します。
$ touch my.cnf
テキストエディタで編集します。
[client]
default-character-set=utf8mb4
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
ここでは、デフォルトの文字コードその他の設定を行なっています。
Docker Composeを使ったコンテナの管理
ここまでで、PHP,Apache,MySQLのDockerfileを作成を完了しました。
Dockerfileは全て作成しましたので、最後にdocker-compose.ymlを作成してDocker Composeを利用したDockerコンテナの管理ができるようにしましょう。
まずはファイルを作成します。
$ touch docker-compose.yml // demoディレクトリ直下に作成
テキストエディタで編集していきます。
version: '3'
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
container_name: prdev_app
volumes:
- ./app:/var/www/html
ports:
- 8000:80
depends_on:
- database
database:
build:
context: .
dockerfile: docker/db/Dockerfile
container_name: prdev_db
platform: linux/amd64
command: --default-authentication-plugin=mysql_native_password
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 管理ユーザのパスワード
MYSQL_DATABASE: データベース名
MYSQL_USER: ユーザ名
MYSQL_PASSWORD: ユーザのパスワード
ports:
- 3306:3306
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: prdev_phpmyadmin
environment:
PMA_HOST: database
PMA_PORT: 3306
ports:
- 8080:80
depends_on:
- database
volumes:
db_data: {}
docker-compose.ymlファイルでは、各コンテナをサービスとして記述していきます。
ファイル内のservices直下に記述していきます。
補足として、docker-compose.ymlはインデントで各ブロックを識別しており、インデントがズレているとうまく動作しませんので、ご注意ください。
以下はPHP,Apacheのコンテナです。
app:
build:
context: .
dockerfile: docker/app/Dockerfile
container_name: prdev_app
volumes:
- ./app:/var/www/html
ports:
- 8000:80
depends_on:
- database
それぞれの意味を解説します。
build・・・Dockerfileを指定しています。contextとありますが、これはどこをルートディレクトリとするかの指定を行なっており、今回の場合はdocker-compose.ymlファイルが置かれているディレクトリをルートディレクトリとしています。
container_name・・・コンテナが起動する際のコンテナ名です。
volumes・・・ホスト(ローカル)とコンテナ内のファイルやディレクトリを同期させています。この同期することを、一般的に「マウント」と呼びます。記述方法は、「ホスト側の相対パス:コンテナ側の絶対パス」となります。
ports・・・「ホスト側のポート:コンテナ側のポート」と記述します。ホスト側のポートをコンテナ側のポート繋げています。
depends_on・・・依存関係を示しています。今回の場合は、appサービスをdatabaseサービスに依存させています。この場合、databaseサービスのコンテナ起動を待ってからPHP,Apacheのコンテナを起動します。逆にコンテナを停止するときは、appサービスのコンテナを停止してからdatabaseサービスのコンテナを停止します。
他のサービスも似たような書き方のため、以降は差分のみ説明していきます。
database:
build:
context: .
dockerfile: docker/db/Dockerfile
container_name: prdev_db
platform: linux/amd64
command: --default-authentication-plugin=mysql_native_password
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 管理ユーザのパスワード
MYSQL_DATABASE: データベース名
MYSQL_USER: ユーザ名
MYSQL_PASSWORD: ユーザのパスワード
ports:
- 3306:3306
platform・・・これはM1Mac用の記述で、apple slicon製のPCの場合は必要な記述です。
environment・・・環境変数の設定。MySQLのデータベース名やユーザ名、パスワードなどを設定します。
以下、phpmyadminも同様に記述していきます。
これで、docker-compose.ymlも作成できたので、最後にコンテナを立ち上げてみましょう。
$ docker-compose build // イメージをビルド
$ docker-compose up -d // コンテナ起動
正常に立ち上がって、以下にアクセスできれば成功です。
Laravel側のデータベース接続設定
コンテナがうまく立ち上がっても、現状のままだとLaravel側からMySQLに接続することができません。
最後にLaravel側の設定を追加しておきましょう。
$ cd app
envファイルをテキストエディタで編集します。
DB_CONNECTION=mysql
DB_HOST=database #データベースのサービス名
DB_PORT=3306
DB_DATABASE=データベース名
DB_USERNAME=ユーザ名
DB_PASSWORD=パスワード
注意点として、DB_HOSTはデータベースのサービス名を記述してください。
はい!これでLaravelからMySQLコンテナへ接続することができました。
応用編:カスタマイズや最適化
このセクションは応用編ということで、より効率的で保守性の高いDockerfileの書き方や設計を説明していきます。
いくつかあるとは思いますが、以下は筆者が重要だと思うものを取り上げます。
非root権限として実行する
コンテナ内でプログラムをrootユーザで実行するとセキュリティ的なリスクがあります。
root権限が与えられると、全てのファイルが見えてしまい、操作可能になってしまいます。
非root権限として実行するようにするには、以下のような設定を行なっておく必要があります。
FROM php:8.1-apache
...
# 以下2行を追加
RUN adduser myuser && chown -R myuser /var/www/html
USER myuser
不要なパッケージをインストールしない
たぶん必要だろうということで、あれもこれもパッケージをインストールしたり、どこかの記事を何も考えずにコピペしたりすると、ファイル容量や複雑さが増してしまいます。
できる限り不要なパッケージはインストールしないようにしましょう。
--no-install-recommends
オプションをつけると、不要なパッケージのインストールを避けることができるようです。
RUN apt-get update \
&& apt-get install -y --no-install-recommends \ # オプション追加
git \
zip \
unzip \
vim \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install pdo_mysql
ビルドコンテキストの利用
ビルドコンテキストを利用すると、指定したディレクトリ以下のファイルを全てDocker deamonに送信します。
build:
context: .
ビルドコンテキストで指定したディレクトリ以下のファイル容量があまりに多いと、buildに時間がかかってしまったり、メモリ消費が激しくなります。
そのため、Dockerfile用のディレクトリを作成し、余分なファイルやディレクトリを配置しないようにしましょう。
今回のデモでは、ディレクトリ構成が以下のようになっているため、余分なファイル等を配置しないように設計していました。
docker
|_app
| |_Dockerfile
| |_000-default.conf
| |_php.ini
|_db
|_Dockerfile
|_my.cnf
.dockerignoreを使った除外
ビルドコンテキストの利用のセクションと関係しますが、ビルドコンテキストで指定したディレクトリ配下に余分なファイル等が存在する場合でも、.dockerignoreで除外ファイルを指定すれば指定ファイルを無視できます。
記述方法などは以下から確認できます。
マルチステージビルドを使う
マルチステージビルドとは、段階を分けてイメージのビルドを行うことができる機能です。
DockerfileにFROM行を複数書くことで、各段階で異なるベースイメージを指定できます。
最終的なイメージとして採用されるのは最終ステージなので、前ステージの成果物は最終ステージにコピーすることでマルチステージビルドを実現できます。
今回のデモではホスト側でLaravelをインストールしてコンテナにマウントしていました。
しかし、Dockerビルド時にLaravelをインストールしたいような場合もあるかと思います。
このような場合は、マルチステージビルドを活用することができ、Laravelを作成するパートとコンテナを作成するパートに分けることで、コンテナに余分なリソースが入らない工夫ができます。
具体的な例を見てみましょう。
# Laravelをインストールするパート
FROM amazonlinux:2 as vendor
# PHPインストール
RUN amazon-linux-extras install -y php8.1
RUN yum install -y php-pecl-zip php-mbstring php-dom
# Composerのインストール
RUN cd /usr/bin && curl -s <http://getcomposer.org/installer> | php && ln -s /usr/bin/composer.phar /usr/bin/composer
# Laravelインストール
WORKDIR /var/www
RUN composer create-project laravel/laravel laravel
# コンテナを作成するパート
FROM php:8.1-apache
COPY --from=vendor /var/www/ /var/www/
COPY /docker/app/php.ini /usr/local/etc/php/
COPY /docker/app/000-default.conf /etc/apache2/sites-available/000-default.conf
RUN apt-get update \
&& apt-get install -y \
git \
zip \
unzip \
vim \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install pdo_mysql
# Laravelで必要になるmodRewriteを有効化する
RUN mv /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled
RUN /bin/sh -c a2enmod rewrite
上記の例では、最初にAmazon LinuxのベースイメージでComposerのインストールやLaravelのインストールなどを行なっています。
後続のコンテナを作成するパートでは、前段階であるLaravelインストールの成果物として、「/var/www/laravel」だけをコンテナ内にコピーしています。
COPY --from=vendor /var/www/ /var/www/
このようにすることで、例えばComposerのリソースなどをコンテナ内に作らずにビルドでき、イメージサイズを軽減することができます。
最後に
いかがでしたでしょうか。
今回はDockerを使ったLaravelの環境構築ということで、環境構築方法をできる限り丁寧にわかりやすく解説していきました。
ただDockerを使って環境構築できるようになるだけではなく、コードの意味やパフォーマンスや保守性を意識した構築ができるようになってほしいという筆者の思いから今回記事を作成しました。
少しでもDockerを使った環境構築を行う開発者の助けになれば幸いです。
ではでは😊
参考リソース
参考リンク
参考書籍
仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん [ 小笠原種高 ]
コメント