太陽がまぶしかったから

C'etait a cause du soleil.

Docker for Mac で PHP 7.2 x Laravel 5.6 のコンテナを作成

Laravel を Docker で使ってみよう

 今更ながらにプログラミング熱が高まっているので、GW中に Webアプリケーションでも作成してみようと、PHP の Laravel 環境を作ってみることとした。ローカル環境を汚したくないので Docker を利用。 Laradock のような作成済み環境もあったが、PHP自体にも初めて触るので、いちから作成してみる。

 Docker for Mac はインストール済みの前提とする。 Docker はコンテナ型仮想化環境。VMware や VirtualBox などの仮想環境に比べて軽量かつDockerfileという簡単な設定ファイルからコンテナイメージファイルを作成できるようにすることで手順書がほとんどいらなくなる。いわゆる Infrastructure as Code の根幹である。

Dockerfile からコンテナイメージを作成

FROM centos:latest

RUN yum update -y
RUN yum -y install aws-cli autoconf \
  && yum -y install git vim unzip wget httpd \
  && yum -y install libzip libzip-devel opnessl

RUN yum -y install epel-release \
  && yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm \
  && yum search php72 \
  && yum -y install php72
RUN ln -s /usr/bin/php72 /usr/bin/php
RUN yum -y install php-openssl php72-php-mbstring php72-php-pdo php72-php-gd php72-php-dom  php72-php-mysql

RUN curl -sS https://getcomposer.org/installer \
  | php -- --install-dir=/usr/local/bin --filename=composer
RUN composer global require "Laravel/installer=~1.1"
RUN composer global update

WORKDIR /var/www
RUN composer create-project laravel/laravel laravelapp --prefer-dist
WORKDIR /var/www/laravelapp
RUN composer update

CMD php artisan serve --host=0.0.0.0 --port=8000

 上記を、 Dockerfile というファイル名で保存(各コマンドの意味は後述)。

$ docker build -t my-php-app .

 Dockerfile のビルドを実施。

$ docker run --name phpapp -d -p 50000:8000 my-php-app

 ビルドされたイメージを起動を phpapp という名前(--name)でバックグラウンド起動(-d)。Docker 側のホストマシン側のポート番号50000 を Docker側の 8000 番に接続。

f:id:bulldra:20180501141846j:plain

 できた。一度このような Dockerfile ができれば次からやるときは誰がやっても簡単に環境を作成できるようになるが、実際にイメージファイルを作るまではそれなりに大変だった。

Dockerfile の詳説

CentOS のイメージを取得

FROM centos:latest

RUN yum update -y
RUN yum -y install aws-cli autoconf \
  && yum -y install git vim unzip wget httpd \
  && yum -y install libzip libzip-devel opnessl

 まずは Cent OS の最新バージョンイメージをダウンロードしてきて必要ライブラリをインストール。Cent OS だから大変だったんじゃないか説があるが、エンタープライズ領域だと Cent OS / RHELに決め打ちされる可能性が高いことを念頭においた。 これだけで Cent OS の環境の作れてしまう時代。

PHP 7.2 をインストール

RUN yum -y install epel-release \
  && yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm \
  && yum search php72 \
  && yum -y install php72
RUN ln -s /usr/bin/php72 /usr/bin/php
RUN yum -y install php-openssl php72-php-mbstring php72-php-pdo php72-php-gd php72-php-dom

 PHP 7.2 と Laravel に必要なPHPエクステンションをインストール。 Cent OS の通常リポジトリには PHP の最新版が入っていないため、いわゆるRemi リポジトリを追加する必要があるとのこと。必要な Extension は Laravel公式ドキュメント を参照。

Composer をインストール

RUN curl -sS https://getcomposer.org/installer \
  | php -- --install-dir=/usr/local/bin --filename=composer

 Laravel をインストールする前段階として、 PHP のパッケージ管理プログラムの Composer をインストール。

 ここからは上記参考書を元に作成。

Laravel をインストール

RUN composer global require "Laravel/installer=~1.1"
RUN composer global update

 Composer からLaravel をインストールして update。 installer=~1.1 を入れなかったり、 update をしないとサンプルアプリケーション作成時に落ちる。

Laravel プロジェクトの作成と起動

WORKDIR /var/www
RUN composer create-project laravel/laravel laravelapp --prefer-dist
WORKDIR /var/www/laravelapp
RUN composer update

CMD php artisan serve --host=0.0.0.0 --port=8000

 laravelapp というプロジェクトを作成して artisan というテストサーバーを起動。通常通りに artisan を起動して 127.0.0.1 に割り当てるとホストマシンからの参照で ERR_EMPTY_RESPONSE が出るため、 0.0.0.0 に設定。ここの試行錯誤に一番時間がかかったりもした。

プロジェクトをローカルで編集して反映

 Docker イメージは 状態を持たないため、起動するたびに作成時の状態に戻る Immutable Infrastructure という性質を持っている。このため、プロジェクトのファイルをローカルにもってきてから編集し、起動時直後にローカル側のファイルを反映する仕組みとする。

$ docker cp phpapp:/var/www/laravelapp ./

 Docker上のファイルをコピーするのは docker cp コマンドで行う。サンプルプロジェクトの View テンプレートは laravelapp/resources/views で管理されているので、適当に編集。

$ docker cp laravelapp/ phpapp:/var/www/

 ローカルファイルの内容を Docker 側のファイルに反映。

f:id:bulldra:20180501144051p:plain

 編集内容が画面に反映された。ファイル反映を再起動スクリプト等に書いておくことでローカル側の編集内容が Docker 側に自動反映されるようにしておく。

docker stop phpapp
docker rm `docker ps -a -q`
docker run --name phpapp -d -p 50000:8000 my-php-app
docker cp laravelapp/ phpapp:/var/www/

 本来的には git から最新のソースを取ってくるようにしたり、DBサーバーをたてたりすべきだが、これ以上の Yak Shaving を続けるのも本筋からずれるので、まずは参考書を読み進められる状態にするまで。自分で手を動かすと意外に大変だな。