Dockerでlaravelの開発環境構築をした (php-pfm,nginx, mysql) 2019

おはようございます。

タイトルの通りに今日はDockerでlaravelの環境構築経験を述べたいと思います。

私はまだ日本語を勉強中なので。わかりにくいことがあれば申し訳ありません。

2017に同じ内容の記事を投稿しました：https://qiita.com/mytv1/items/f26cd77f2801357dee8f
それでも最近また触りたいと思って、触ってみたらLaravelのバージョンが古くなったとわかりました。新しいパッケージを結合できるように更新したいというきっかけで再度記載します。

よろしくお願いします。

# ホストの情報
#### OS
MacOS High Sierra 10.13.6
#### Docker
```
$docker -v
Docker version 19.03.5, build 633a0ea
```
#### Docker Compose
```
$docker-compose -v
docker-compose version 1.24.1, build 4667896b
```

# 構築する予定の環境情報
#### Webserver 
Nginx 1.0

#### Database
mysql 8.0

#### PHP
PHP:7.4-FPM

#### 構成
構築終わったら構成が下記だと想定します。

```
|-- app # Laravelを格納するDockerコンテナ
|-- composer # Composerを格納するDockerコンテナ（PHPのcomposerです！）
|-- db # データベースを格納するDockerコンテナ
|-- docker-compose.yml 
|-- web # ウェブサーバーを格納するDockerコンテナ
```

ディレクトリ構成と実際動いている構成と下記のように関係があると思います。

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/ns7jo9ahu3_Untitled%20Diagram.jpg)

`app`、`web`、`db`はそれぞれのコンテナと該当します。

処理フローと言えば、最初にリクエストはWebコンテナに渡されて、その後WebコンテナからAppコンテナに引き渡します。ここにもし必要であればAppコンテナはDatabaseコンテナとクエリーでやりとりして、その結果を処理してからWebコンテナにレスポンスに返し、最後にブラウズに返却します。

# 構築手順
## 1.プロジェクトを作成
### 1.1.新規ディレクトリを作成
ゼロから作成ということで、新規ディレクトリを作成します。名前について私は「docker_laravel_2019」と選びますが、任意です。

```
$ mkdir docker_laravel_2019
$ cd docker_laravel_2019
```

### 1.2.Laravelプロジェクトを新規作成
https://laravel.com/docs/6.x/installation#installing-laravel 

Laravelの公式サイトによると作成するにはComposer経由という選択肢がありますね。
私もComposer経由で作成しますが、そのComposerをホストPCにあるComposerではなく、Dockerコンテナとして新規作成します。

理由はホストPCでComposerとPHPのバージョンを管理するのはDockerで管理と比べてちょっと手間ということです。PHPのバージョン、Composerのバージョンを上げたり、下げたり調整するMacosの手順のはちょっと面倒かもしれませんね。
簡単な場合はDockerなら記載し直したらいけると思います。

#### 1.2.1. Composerディレクトリを作成
```
$ mkdir composer
```

#### 1.2.2. ComposerのDockerイメージを作成
https://github.com/mytv1/docker_laravel_2019/blob/master/composer/composer.dockerfile

**composer/composer.dockerfile**

```
FROM php:7.4-fpm

RUN apt-get update && apt-get install -y libzip-dev

# Extension zip for laravel
RUN docker-php-ext-install zip 

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

RUN composer global require laravel/installer
```

ベースのイメージは最新のphpバージョンの7.4を選びました。その後はcomposerインストールまたはComposerでlaravelプロジェクトを作成するのに必要なライブラリ（zip)をインストールします。

最後はコマンドの`RUN composer global require laravel/installer`はLaravelのインストーラーをインストールします。

#### 1.2.3. ComposerのDockerイメージをビルド
これまでComposerのDockerイメージを作成しました。次はコンテナになるようにビルドします。

```
$ docker build -t localcomposer -f ./composer/composer.dockerfile ./composer
```

・`-t localcomposer` : イメージの名前というか、タグを`localcomposer`とします。

実行するとインストールするのに数分がかかるかもしれません。

#### 1.2.4. ComposerコンテナでLaravel初期プロジェクトを作成

Linux 

```
$ docker run -it -v $(pwd):/var/www/html localcomposer:latest /root/.composer/vendor/bin/laravel new app
```

Window :

```
$ docker run -it -v ${pwd}:/var/www/html localcomposer:latest /root/.composer/vendor/bin/laravel new app
```

・`-v $(pwd):/var/www/html` :ホストのカレントディレクトリをコンテナの`/var/www/html`とマウントします。その新規のプロジェクトが`/var/www/html`に作成がされるので、それをコンテナと一緒に消さないようにホストに残すようにするということです。
・`app`：作りたいLaravelプロジェクトの名前、appとします。

実行終わったら、ディレクトリは下記のようになりますね。

```
|-- app
|-- composer
	|-- composer.dockerfile
```

### 1.3. NginxのDockerコンテナを構築
#### 1.3.1. 新規ディレクトリを作成
```
$ mkdir web
```

#### 1.3.2. Nginxの設定を作成
##### web/vhost.confを作成
https://github.com/mytv1/docker_laravel_2019/blob/master/web/vhost.conf

```
server {
      listen 80;
      index index.php index.html;
      root /var/www/public;
      error_log  /var/log/nginx/error.log;
      access_log /var/log/nginx/access.log;
      proxy_set_header HTTP_AUTHORIZATION $http_authorization;
    
      location / {
          try_files $uri /index.php?$args;
      }

      location ~ \.php$ {
          fastcgi_split_path_info ^(.+\.php)(/.+)$;
          fastcgi_pass app:9000;
          include fastcgi_params;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
          fastcgi_param PATH_INFO $fastcgi_path_info;
          sendfile off;
      }
}
```

その中にある数点を説明させていただきます。
* `listen 80` : 80ポートに聞き耳を立てる
* `fastcgi_pass app:9000`: FastCGIサーバーのアドレスを指定します。WebサーバーのNginxがリクエストを受けた後はFastCGI（Laravel）に引き渡します。そのアドレスはここにしています。appはホスト名で、後でdocker-compose.ymlに記載されます。9000はデフォルトのポートですね。

#### NginxのDockerイメージを作成
`web/web.dockerfile`を作成

https://github.com/mytv1/docker_laravel_2019/blob/master/web/web.dockerfile

```
FROM nginx:1.10
ADD vhost.conf /etc/nginx/conf.d/default.conf
```

ベースイメージはnginx:1.10にします。Nginxの設定はホストのvhost.confから`ADD`でコポーします。

これまで構成は下記になりますね。

```
|-- app
|-- composer
|-- web
	|-- vhost.conf
    |-- web.dockerfile
```

### 1.4. MysqlのDockerコンテナを構築
#### 1.4.1. 新規ディレクトリを作成

```
$ mkdir db
```

#### 1.4.2. mysql設定を作成
**./db/my.cnf**を作ります

https://github.com/mytv1/docker_laravel_2019/blob/master/db/my.cnf

```
[mysqld]
default-authentication-plugin = mysql_native_password
```

今度私が使うイメージは`mysql:8.0`で、デフォルト認証方法は普通のパスワードの認証ではなく、caching_sha2_passwordという認証仕方になります。そのままだとlaravelの一般的な認証はいけませんので、mysqlの設定に通常の認証設定に変更します。

mysqlのDockerコンテナは公式な既存のイメージを使います。Nginxのように私は継続し新規で作成しません。ただ設定を上書きます。

これまで構成は下記になります。

```
|-- app
|-- composer
|-- web
|-- db
	|-- my.conf 
```

### 1.5. LaravelのDockerコンテナを構築
#### 1.5.1. Dockerイメージを作成
`./app/app.dockerfile`を作ります。
https://github.com/mytv1/docker_laravel_2019/blob/master/app/app.dockerfile

```
FROM php:7.4-fpm

RUN apt-get update && apt-get install -y libzip-dev

# Extension mysql driver for mysql
RUN docker-php-ext-install pdo_mysql mysqli
```

ComposerのDockerイメージのように、ベースイメージをphp:7.4-fpmにします。その他はpdoまたmysqlドライバーのライブラリをインストールします。

#### 1.5.2. Laravelに必要なパッケージをインストール
```
$ docker run -v $(pwd)/app:/var/www/html localcomposer:latest composer install
```

また前述で作成したcomposerのDockerコンテナでインストールします。
1~2分ぐらいかかるかもしれません。

#### 1.5.3. 環境変数を編集
下記のように`./app/.env`を編集します。

```
DB_HOST=127.0.0.1
DB_PASSWORD=
```
↓

```
DB_HOST=database
DB_PASSWORD=secret
```

・`DB_HOST`: Laravelから見るデーターベースのホストを指定する場所です。通常はホストで同じで配置されて、127.0.0.1でいいですが、今度はDockerコンテナの間で繋がるということで、ホスト名はDockerコンテナの名称になります（デフォルト該当するネットワーク名はDockerコンテナの名になるでしょう）

・`DB_PASSWORD`: rootとしてログインするパスワードです。この「secret」は後でdocker-compose.ymlで宣言します。

これまでディレクトリの構成は：

```
|-- app
	|-- ....
	|-- .env    
	|-- app.dockerfile
 	|-- ....
|-- composer
|-- web
|-- db
```

### 1.6. docker-composer.ymlを作成
`docker-compose.yml`はそれぞれのコンテナをモータニングする手順を記載するファイルですね。

私は下記のように設定します。

`./docker-compose.yml`を作る

https://github.com/mytv1/docker_laravel_2019/blob/master/docker-compose.yml

```
version: '3'
services:

  # The Application
  app:
    build:
      context: ./app/
      dockerfile: app.dockerfile
    working_dir: /var/www
    volumes:
      - ./app/:/var/www/

  # The Web Server
  web:
    build:
      context: ./web/
      dockerfile: web.dockerfile
    working_dir: /var/www
    volumes:
      - ./web/:/var/www/
      - ./app/public:/var/www/public
    ports:
      - 8080:80

  # The Database
  database:
    image: mysql:8.0
    volumes:
      - ./db/dbdata:/var/lib/mysql
      - ./db/my.cnf:/etc/mysql/conf.d/my.cnf
    command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci','--default-authentication-plugin=mysql_native_password']
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: secret
    ports:
        - "33061:3306"

volumes:
  dbdata:
```

今まで作成していたコンテナの名称の通りに、それぞれのコンテナをここに記載します。

* `app` : LaravelのDockerコンテナ、ホストの`app`をコンテナの`/var/www`とマウントします。開発する時にホストで修正するとすぐにコンテナに反映するようにするためです。
* `web` : NginxのDockerコンテナ
* `database` : DatabaseのDockerコンテナ

これまでディレクトリの構成は：

```
|-- app
|-- composer
|-- web
|-- db
|-- docker-compose.yml
```

## 2.システムを立ち上げる
これまで構築は終わると思います。実行してみましょう〜

```
$ docker-compose up
```

立ち上がる1分ほど、http://0.0.0.0:8080で下記の表示が出ると想定します。

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/pw3ryc8wsf_Screen%20Shot%202020-01-03%20at%2020.08.06.png)

これまで構築が終わります！機能開発はこれから開始されると思います。

### その他
上記のインデックスページが出るということはまだLaravelがデータベースと繋がらない可能性があります。
確認するために、マイグレーションを実行してみます。

```
$docker-compose exec app php artisan migrate --seed
```

デフォルトはlaravelは認証用のテーブルのマイグレーションが用意されますん。実行するとこういうテーブルが作られますね。ついでにダンプデータも作ります（seed）。実行結果はこんな感じです。

```
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.04 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.03 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.02 seconds)
Database seeding completed successfully.
```

無事に実行できたら、繋がることは大丈夫だと思います〜

## 3.ソースコード
https://github.com/mytv1/docker_laravel_2019

この記事に利用する設定、コードをgithubに上げました。ご参考になればと思います。

## お終い
これまでお疲れ様でした〜
この記事は皆の作業に役に立てば嬉しいです。m(_ _)m