【Docker】AlpineLinuxを使ったLaravel環境構築

######  2019/05/08修正

この4月からエンジニアになりました。
初心者なりにDockerで環境構築をしたので、ご指導いただきたいです！

様々な記事を参考にさせていただきました。投稿者の方に感謝。

## 概要

Docker-Composeを使ったDockerのコンテナ用意。

 - Composerを使ったLaravelプロジェクトインストール
 - gitを使ったLaravelプロジェクトクローン

### Docker環境

 - Docker-Desktop 2.0.0.2 
 - docker-compose 1.23.2

### 構築環境

 - php:7.2.12-fpm-alpine3.7
 - nginx:1.15.6
 - mysql:5.7
 - Laravel 任意

alpineLinuxは軽いからいいですね！
通常のphp-fpmだとdebianなのでalpineにします。

## 構成

ディレクトリ名：gataponとし、その内部構成です。

```
.
├── docker
│   ├── db
│   │   ├── my.conf
│   │   ├── .env_db
│   │   └── .gitignore
│   │ 
│   ├── php
│   │   ├── Dockerfile
│   │   └── php.ini
│   └── web
│       └── default.conf
└── docker-compose.yml
```

## 準備編：Docker-Compose

### docker-compose.ymlファイル

MySQLのデータは永続化のため、Data Volumeコンテナを用意してます。
yamlファイルでData Volumeコンテナを追加するのはservicesの階層にvolumesを記入すればOK。<br>


参考：[Dockerのデータ永続化関連について](https://qiita.com/onokatio/items/fcc9f8f94f8533bb030a)


```yml:docker-compose.yml
version: '3'
services:
  web:
    image: nginx:1.15.6
    ports:
      - "8000:80"
    depends_on:
      - app
    volumes:
      - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf  # 別ファイルで定義
      - ./html:/var/www/html
    
  app:
    build: ./docker/php # Dockerfileでビルド
    depends_on:
      - mysql
    volumes:
      - ./html:/var/www/htm

  mysql:
    image: mysql:5.7
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    env_file: ./docker/db/.env_d　 # 別フォルダで環境変数を定義
    ports:
      - "3306:3306"
    volumes:
      - mysql:/var/lib/mysql # volumeコンテナとマウント
      - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf

volumes:
  mysql: # volumeコンテナ用意
```

## nginxディレクトリ

Nginxとphp-fpmはニコイチ！！以下の記事が参考になります。といっても私にとってはまだ難しい。<br>繰り返し読んでいかないといけないと思っています。<br>

参考：[nginx と PHP-FPM の仕組みをちゃんと理解しながら PHP の実行環境を構築する](https://qiita.com/kotarella1110/items/634f6fafeb33ae0f51dc)

```conf:docker/web/default.conf
server {
    listen 80;

    root  /var/www/html;
    index index.php index.html index.htm;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000; 
        fastcgi_index index.php;

        include     fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
```

何度か写生したことはあるのですが、nginx設定ファイルのFastCGI記述については、まだあまり理解できてません。

## phpディレクトリ

### Dockerfile

alpineLinuxの特徴は非常に軽量であることです。必要なものをインストールしましょう。
今回は以下の記事のDockerfileを参考にし、gitとvimも追加しました。<br>

参考：[laravel 5.6 + laravel-mix 2.x (docker with alpine linux)にて、 npm install したら pngquant で libpng-dev のエラーが出たから暫定対応したメモ](https://qiita.com/hokutoasari/items/e01179cd3bb0e2fd74af)

```Dockerfile:docker/php/Dockerfile
FROM php:7.2-fpm-alpine3.7
COPY php.ini /usr/local/etc/php/

RUN apk --no-cache update && \
    apk --no-cache upgrade && \
    apk --no-cache add \
    curl-dev \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    libxml2-dev \
    zlib-dev \
    pcre-dev \
    g++ \
    make \
    autoconf \
    openssl \
    nodejs-npm \
    bash \
    vim \
    git \
  && docker-php-ext-install \
    curl \
    dom \
    mbstring \
    pdo \
    pdo_mysql \
    simplexml \
    zip \
    opcache \
  && docker-php-ext-configure gd \
    --with-freetype-dir=/usr/include/ \
    --with-jpeg-dir=/usr/include/ \
    --with-png-dir=/usr/include/ \
  && docker-php-ext-install gd \
  && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
  && chmod +x /usr/local/bin/composer \
  && rm -rf /var/cache/apk/*
```

Linuxごとにパッケージインストーラが違いますし、オプションも違いますね。
各コマンドの勉強に以下のサイトを使わせていただきました。<br>

参考：[Dockerやる前のAlpine Linux](https://yoshinorin.net/2016/10/01/alpine-linux/)

### php.ini

超絶シンプルです。<br>

```ini:docker/php/php.ini
date.timezone = "Asia/Tokyo"

mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
```

## dbディレクトリ

### .env_db

```:docker/db/.env_db
MYSQL_RANDOM_ROOT_PASSWORD=yes

# 以下はそのままLaravelの.envファイルでも使います 
MYSQL_DATABASE=sample
MYSQL_USER=user
MYSQL_PASSWORD=password
```

MySQLコンテナを生成する際は`MYSQL_RANDOM_ROOT_PASSWORD`,`MYSQL_ALLOW_EMPTY_PASSWORD`,`MYSQL_ROOT_PASSWORD`を設定しないと怒られます。スタックした時に参考にさせていただいた記事です。<br>

参考：[DockerのMySQLイメージ起動時に渡す環境変数](https://qiita.com/nanakenashi/items/180941699dc7ba9d0922)

### my.cnf

以前に文字化けするとのご指摘をいただいていたので、utf-8に変更しDBの文字化けを回避できるように変更しました。

```:docker/db/my.cnf
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

[client]
default-character-set=utf8
```

.env_dbをgitに上げないように記入しておきます。

```docker/db/.gitignore
.env_db 
```

## 起動編：Docker-Compose

### イメージ・ビルド

`docker-compose.yml`があるディレクトリにて実行。ファイル内のbuildが実行されます。

```shell
$ docker-compose build
```

完了したら確認しましょう。

```shell
$ docker images

REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
gatapon_app           latest              a70a11dc6d1c        20 hours ago        337MB
php                   7.2-fpm-alpine3.7   a2dfd79ee40c        3 months ago        77.6MB
```

こんな感じに出れば成功です。
REPOSITORY名は`<フォルダ名>_<ymlファイルのservies名>`になります。`<services名>`は短いと、後々便利です。

### コンテナ起動

```shell
$ docker-compose up -d
```

長々と処理が行われますが、最終的に以下の内容が出たら成功です。

```shell
Creating sample_mysql_1 ... done
Creating sample_app_1   ... done
Creating sample_web_1   ... done
```

コンテナ生成と起動が同時に行われます。
しっかりと動いているか確認しましょう。
用意したファイルに何か不備がある場合、起動フェイントかけてきてます。（起動してすぐ落ちる）


```shell
$ docker-compose ps

     Name                   Command              State                 Ports
------------------------------------------------------------------------------------------
gatapon_app_1     docker-php-entrypoint php-fpm   Up      9000/tcp
gatapon_mysql_1   docker-entrypoint.sh mysqld     Up      0.0.0.0:3306->3306/tcp, 33060/tcp
gatapon_web_1     nginx -g daemon off;            Up      0.0.0.0:8000->80/tcp
```

うまくいっていない場合は`docker-compose logs`や`docker ps`などを駆使して確認しましょう。

この時点で`localhost:8000`にアクセスするとnginxのエラー画面が表示されます。

<img width="1105" alt="スクリーンショット 2019-02-06 16.44.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/222848/ec47bb94-9280-cf9d-d054-0d25c7ada9e4.png">


あともう少しです。

## Laravel インストール

### composerを使ってLaravelプロジェクトインストール

Laravelプロジェクトをインストールし、Laravel画面を出しましょう。
bashでコンテナにログインします。

```shell
$ docker-compose exec app bash 

# Laravelプロジェクトをインストール
bash# composer create-project --prefer-dist laravel/laravel gatapon_app "5.5.*"
```

### nginx設定ファイルの変更

先ほど`localhost:8000`に接続してもnginxエラーでしたが、Laravel画面を出したいのでnginx設定ファイルを変更する必要があります。

```conf:docker/web/default.conf
server {
    listen 80;

    root  /var/www/html/gatapon_app/public;  # <- 'Laravelプロジェクト/public'を追加
    index index.php index.html index.htm;

~~
```

追加したらコンテナ再起動

```shell
#　コンテナから退場
bash# exit

# コンテナ再起動
$ docker-compose restart
```

再起動が完了したら`localhost:8000`にアクセス。
Laravel画面が出たら完了です。

### マイグレーション

Laravelプロジェクトに移動してください。
マイグレーションできるか確認するため、`.env`ファイルをいじりましょう。

```:.env
DB_CONNECTION=mysql
DB_HOST=mysql      #docker-compose.ymlのサービス名に クローンする際注意（？）感想に追記
DB_PORT=3306
DB_DATABASE=sample
DB_USERNAME=user
DB_PASSWORD=password
```

コンテナ内に入ってマイグレーションしましょう。

```shell
$ docker-compose exec app bash

bash# cd gatapon_app
bash# php artisan migrate
```

成功したでしょうか？

### git cloneを使ったLaravel起動

上記とほとんど同じですが、git cloneの時はしなければいけないことが増えます。詳細は以下の記事を確認ください。

参考：[Laravelのプロジェクトをgit cloneしたときの手順](http://vdeep.net/laravel-git-clone)

## 感想

Docker楽しい。くじら可愛い。


### DB_HOSTについて

Laravelインストーラを使うか、git cloneをするかで
`html/project_name/.env`の`DB_HOST`を`127.0.0.1`のままにする必要があるかも...←真偽不明
どうしてそうなるのか調査中...