Laravel開発環境構築

[10]: https://qiita.com/daichannel/items/312925f1a9867a9a75cc "Vagrant＋VirtualBoxで作った仮想環境(CentOS)にLaravel環境構築"
[20]: https://qiita.com/y_hokkey/items/d51e69c6ff4015e85fce "docker-composeを使うと複数コンテナの管理が便利に"
[30]: https://qiita.com/yuta-ushijima/items/d3d98177e1b28f736f04 "docker-compose.ymlの書き方について解説してみた"
[40]: https://qiita.com/daichannel/items/312925f1a9867a9a75cc "Vagrant＋VirtualBoxで作った仮想環境(CentOS)にLaravel環境構築"

# はじめに
[前回記事][10]で、Laravel開発環境を仮想環境（VirtualBox）上に作成することはできた。
今回は仮想環境上で動作するDockerコンテナでLaravelのビルドインWebサーバーを実行します。ホストOS、ゲストOS、Dockerコンテナ間のディレクトリマッピングを整備することで、ホストOS上で変更したソースの内容をリアルタイムでDockerコンテナへ反映させ、動作を確認できるような開発環境を整備します。

# 目的
docker-compose.yml および Dockerfile の記述方や配置方法などを学ぶことを目的としています。

最終目標は、Vagrantfileやdocker-compose.yml、Dockerfile、各種設定ファイルを配布することで、誰でも同じ開発環境を構築できることです。
実際の開発環境整備を考える場合、DBやWebサーバーもコンテナ化してLaravelコンテナと連携させる必要がありますが、今回は割愛します。

# システム構成
![system.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477633/0d9efcfa-ffcb-3332-d594-39967ace73fd.png)
※相変わらず配色センスのかけらも無いですね。。。

# ディレクトリ構成
![directory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477633/148d28a3-2ed8-cf53-6dc2-202410260770.png)

# Vagrant、VirtualBoxのインストール
* Vagrant
https://www.vagrantup.com/downloads.html

* VirtualBox
https://www.virtualbox.org/wiki/Downloads

# 作業を始める前に
[こちらの記事][40]を元に、phpのインストールをして、カスタマイズしたphp.iniと、/var/www/blogディレクトリ（配下の全てのファイルを含む）を取り出しておいてください。
Dockerfileを使ってカスタマイズしたDockerイメージを作成する際に必要になります。

### 取り出すファイル、ディレクトリ
 - php.ini
 - blogディレクトリ（/var/log/blog）

# 仮想環境(BargeLinux）の作成
コマンドプロンプトを起動し、d:ドライブ直下にlara_projectフォルダを作成し、そこへ移動します。

```
> d:
> mkdir lara_project
> cd lara_project
```

今回のDockerホストOSはDocker向けの軽量OS、BargeLinuxを使用します。
BargeLinuxのイメージをダウンロードします。

```
> vagrant box add ailispaw/barge
```

BargeLinux起動用のVagrantfileの雛形を作成します。

```
> vagrant init ailispaw/barge
```

作成したVagrantfileの雛形をカスタマイズします。
D:\lara_project フォルダに Vagrantfileファイルが出来ているので、テキストエディタで開いて、以下の編集を行います。

```diff:Vagrantfile
# コメントアウト解除
- 31| # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
+ 31| config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
# ディレクトリマウント設定を追記
+ 47|   config.vm.synced_folder "source", "/vagrant/source"
+ 48|   config.vm.synced_folder "env", "/vagrant/env"
+ 49|   config.vm.synced_folder "log", "/vagrant/log"
```
31行目の編集は、後ほどDockerコンテナ上で起動されたLaravelのビルドインWebサーバーへ接続する為に必要になります。

マウントするディレクトリを作成します。

```
> mkdir env, log, env/app
```
ここで作成した env/app ディレクトリに、[作業を始める前に](#作業を始める前に)で取り出した `php.ini` を配置します。
また、[作業を始める前に](#作業を始める前に)で取り出した`blog`フォルダをリネームして、`D://lara_project/source`フォルダとして配置してください。

仮想環境を起動します。

```
> vagrant up
```
カレントフォルダのvagrantfileを参照して、そこに記載してある仮想環境を構築、起動します。

仮想環境（BargeLinux）が起動しているので、仮想環境にSSHで接続しましょう。

```
> vagrant ssh
```

# ゲストOS（BargeLinux）の設定
## Docker 最新化
既定のDockerバージョンは 1.10.xとかなので、Dockerを更新します。
開発環境なので、比較的最近のバージョンである 18.06.3 に更新します。

```
$ sudo /etc/init.d/docker restart v18.06.3-ce
$ docker --version
Docker version 18.06.3-ce, build d7080c1
```

## Docker Compose のインストール
Docker Composeを利用すると、複数のDockerコンテナの管理が楽にできます。
今回は前述の通り、DBやWebはインストールしませんが、環境構築の自動化を目的に導入します。

こういうツールをオーケストレーションツールと言いますが、今はKubernetesが主流なのかな。。。ただ、今回はDocker Composeを使います。

Docker Compose をダウンロードします。

```
$ wget -L --no-verbose https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m`
```
`uname -s`はカーネル名が返ってきます。今回で言えば「Linux」です。
`uname -m`はマシンタイプが返ってきます。今回で言えば「x86_64」です。

ダウンロードしたファイルに実行権限を付与します。

```
$ chmod +x docker-compose-`uname -s`-`uname -m`
```
`/opt/bin`配下に移動し、コマンドにします。
※通常は `/usr/local/bin` 配下なのですが、BargeLinuxに左記ディレクトリは存在していない為、Dockerコマンドと同じ、パスの通った `/opt/bin` に配置します。

```
$ sudo mv docker-compose-`uname -s`-`uname -m` /opt/bin/docker-compose
```
念のため、安易にユーザーに実行させないように、所有者をrootに変更します。

```
$ sudo chown root:root /opt/bin/docker-compose
```

## docker-compose.yml の作成
Docker Compose の設定ファイル、docker-compose.yml を新規作成します。

```
$ touch /vagrant/env/docker-compose.yml
```
作成したdocker-compose.ymlを編集していきます。
詳細は[こちらの記事][30]を参照してください。

```
$ vi /vagrant/env/docker-compose.yml
```
```lang:docker-compose.yml
version: '3.5'  // docker-compose.yml の記述フォーマットバージョンです

services:

  app: // このレベルがコンテナだと思ってください。名前は何でもOKです。
    container_name: laravel     // コンテナ名
    build: ./docker-practice    // このコンテナイメージを作成するDockerfileの配置ディレクトリ
    image: laravel_custom       // このコンテナイメージの名前です
    ports:                      // ポートマッピングです。
      - 80:8000
    volumes:                    // ディレクトリのマッピングです。
      - /vagrant/source:/var/www/lara_project  // Laravel本体
      - /vagrant/log:/var/log/lara_project     // ログ
```

## Dockerfileの作成
Dockerのコンテナイメージは、公開されているイメージをそのまま使うだけではなく、アプリケーションや各種設定などのカスタマイズを行ったイメージを作成することが出来ます。
その際Dockerfileに、ベースとなるイメージ、追加するアプリケーションのインストール手順や、各種設定ファイルのコピー手順などを記載し、`docker build`コマンドでこのDockerfileを呼び出すことで、カスタマイズしたDockerイメージを作成できます。

Docker-Composeでも、build句にDockerfileの配置ディレクトリを指定することでカスタムイメージをビルドすることが出来ます。

```
$ touch /vagrant/env/app/Dockerfile
$ vi /vagrant/env/app/Dockerfile
```
```lang:Dockerfile
// ベースイメージはCentOSです。
FROM centos:latest

// ここからPHPのインストールを行います。まずは、EPELリポジトリの追加を行います。
RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

// Remiリポジトリを追加します。PHP 7.x系はこのリポジトリからインストールします。
RUN yum -y install https://rpms.remirepo.net/enterprise/remi-release-7.rpm

// yum-config-managerを利用する為、yum-utilsをインストールします。
RUN yum -y install yum-utils

// Remiリポジトリを有効化します。
RUN yum-config-manager --enable remi-php72

// PHPと、関連ライブラリをインストールします。
RUN yum -y install php php-devel php-mbstring php-pdo php-gd php-xml php-mcrypt php-zip php-unzip

// 予め用意したphp.iniを/etc/php.iniに上書きします。
// Dockerfile内でテキスト編集などはできないので、設定ファイルは予め用意し、上書きします。
COPY php.ini /etc/php.ini

// PHPのライブラリ管理ツール composer のインストーラーをダウンロードし、インストールします。
RUN curl -sS https://getcomposer.org/installer | php

// composer の実行ファイル composer.phar を パスの通ったディレクトリ /usr/local/bin に配置し、composer にリネームします。
RUN mv composer.phar /usr/local/bin/composer

// Laravelのインストーラーをcomposerで取得します。
RUN composer global require "laravel/installer"

// カレントディレクトリを /var/www/ へ移動します。
WORKDIR /var/www

// /var/www 配下にlara_projectの名前で新規Laravelプロジェクトを作成します。
RUN composer create-project --prefer-dist laravel/laravel lara_project "5.6.*"

// プロジェクトディレクトリに移動します。
WORKDIR /var/www/lara_project

// CMD句で、デーモンを起動します。ここでは、PHPのビルドインWebサーバーを起動しています。

// 8000番ポートで待ち受け、ルートディレクトリをpublicとしています。
CMD ["php", "-S", "0.0.0.0:8000", "-t", "public"]
```
※RUN句で、sudo で実行していませんが、Dockerコンテナ内は基本rootで実行される為、sudo の必要はありません。

# Dockerイメージのビルド
CentOSのDockerイメージをベースに、PHPおよびcomposerのインストールを行ったDockerイメージを `docker-compose build`コマンドで作成します。

```
$ sudo docker-compose -f /vagrant/env/docker-compose.yml build
```
新しいイメージ `laravel_custom` が出来ているか確認しましょう。

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
laravel_custom      latest              6146ebf2ca14        39 seconds ago      795MB
centos              latest              67fa590cfc1c        9 days ago          202MB
```
では、Docker Composeから新しいイメージでコンテナを起動しましょう。

```
$ sudo docker-compose -f /vagrant/env/docker-compose.yml up -d
```
コンテナが起動しているか確認します。

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
5c08e5c3fa7c        laravel_custom      "php -S 0.0.0.0:8000…"   5 seconds ago       Up 3 seconds        0.0.0.0:80->8000/tcp   laravel
```

ホスト側からコンテナで起動しているビルドインWebサーバ（`http://localhost:8080`）へアクセスしてみましょう。
以下が表示されればOKです。
![laravel_success_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477633/afc564ca-4367-94b0-8ce5-a26929c71f67.png)

# ホストOS側でソースコードを変更
では、ホストOS側でソースコードを修正し、反映されるか確認します。
`D:\lara_project\source\resources\views\welcome.blade.php` をエディタで開き、以下のように変更します。

```diff:welcome.blade.php
- 82|                    Laravel
+ 82|                    Laravel_Custom
```
ブラウザでF5を押して、再読み込みしてください。
![laravel_success_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477633/417e7897-66ef-13ee-2fda-849dfe142961.png)

これでホストOS上で VS Codeなどでソース編集して、即時修正確認が行えます。

# はまったところ
### ディレクトリのマウントタイミング
ディレクトリのマウントのところはかなり悩みました。
ディレクトリのマウントは、Dockerコンテナ実行時に行われる為、Build時に問題なくても実行時にエラーになる場合があります。

今回で言えば、最初はホストの `d:\lara_project\source` ディレクトリに何も格納しないで、`docker-compose build`を行ったところ、何もエラーは出ずにイメージが出来ましたが、`docker-compose run'でホスト側のsourceディレクトリが コンテナの`/var/www/lara_project`にマウントされ、直前のLaravelのインストール操作で出来ていたはずのファイルが全て消えてしまい、エラーになっていました。
これになかなか気がつけず、かなり悩みました。

本文でも記載している通り、予めLaravelのファイル郡をホスト側に配備することで、対応しました。

### リポジトリの一時接続エラー
`docker-compose build`実施時、Remiリポジトリに接続できないエラーが発生しました。
結局、少ししたら復旧したので事なきを得ましたが、同じような事象が発生した場合、待つしかない、というのは正直不安要素です。

# 参考
https://qiita.com/y_hokkey/items/d51e69c6ff4015e85fce
https://qiita.com/yuta-ushijima/items/d3d98177e1b28f736f04