Docker② DockerでLaravel環境構築

# Dockerを使ったLaravel開発環境構築

## 目次
1. 環境準備
1. ディレクトリ作成
1. docker-compose.yml作成
1. Dockerfile作成
1. PHP設定ファイル作成
1. Nginx設定ファイル作成
1. Laravelプロジェクト作成
1. 動作確認

## 参考
[Dockerを使ってLaravel開発環境構築](https://qiita.com/A-Kira/items/1c55ef689c0f91420e81)

## 環境準備
どうせなので、まっさらのEC2でやってみた方が良いかなと。
最低限何が必要なんだ？ってことで前回のおさらいをしてみたけど、こんな感じか。

``` 
Dockerインストール
# sudo amazon-linux-extras install docker

Dockerサービス起動
# systemctl start docker.service

サービスの起動確認
# systemctl status docker

Dockerの自動起動設定
# systemctl enable docker

試しにDockerコマンド実行
# docker info
```  

```  
Docker Composeインストール
# curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose

Docker Composeのインストールを確認
# docker-compose --version
docker-compose version 1.21.2, build a133471
```  

これで大丈夫そうだった。余裕っすね。


## ディレクトリ作成

>以下の構成を想定しています。
**project**
├ docker-compose.yml
├ **docker**
│　 ├ **php**
│ 　│　 ├ php.ini
│ 　│ 　└ Dockerfile
│　 └ **nginx**
│ 　　　└ default.conf
└ **server**

とのこと。（太字はディレクトリ）

```  
# cd /var
# mkdir project
# mkdir project/docker project/server
# mkdir project/docker/{php,nginx}
# ll -d `find ./project`
drwxr-xr-x 4 root root 34 Mar  5 02:51 ./project
drwxr-xr-x 4 root root 30 Mar  5 02:52 ./project/docker
drwxr-xr-x 2 root root  6 Mar  5 02:52 ./project/docker/nginx
drwxr-xr-x 2 root root  6 Mar  5 02:52 ./project/docker/php
drwxr-xr-x 2 root root  6 Mar  5 02:51 ./project/server
``` 

別にvarじゃなくてもいいけど、なんとなくvarで。


## docker-compose.yml作成

```yml:docker-composer.yml

version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
    - ./server:/var/www

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./server:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:5.7
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306
``` 

こんな感じにするらしい。
中身について考えてみる。

### php
``` 
 php:
   container_name: php  ①
   build: ./docker/php  ②
   volumes:
   - ./server:/var/www  ③
``` 

①　コンテナの名前
②　./docker/phpにあるDockerfileを参照する
③　ホスト側の./serverと、コンテナ側の/var/wwwをマウント

### nginx
``` 
nginx:
  image: nginx  ①
  container_name: nginx  ②
  ports:
  - 80:80　③
  volumes:
  - ./server:/var/www　④
  - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf　⑤
  depends_on:
  - php　⑥
``` 

①　Dockerイメージの指定
②　コンテナの名前
③　PORTを指定
④　ホスト側の./serverと、コンテナ側の/var/wwwをマウント
⑤　ホスト側のdefault.confを、コンテナ側にコピー（マウント？）
⑥　依存関係を指定。この場合、nginxを実行する前にphpｗ実行する。

### db
```
db:
  image: mysql:5.7　①
  container_name: db-host　②
  environment:
    MYSQL_ROOT_PASSWORD: root　③
    MYSQL_DATABASE: database　④
    MYSQL_USER: docker　⑤
    MYSQL_PASSWORD: docker　⑥
    TZ: 'Asia/Tokyo'　⑦
  command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci　⑧
  volumes:
  - ./docker/db/data:/var/lib/mysql　⑨
  - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf　⑩
  - ./docker/db/sql:/docker-entrypoint-initdb.d　⑪
  ports:
  - 3306:3306　⑫
```

DBに関しては、実際はRDSを使用したい。
現時点ではとりあえずコンテナを作成して使用する。


①　Dockerイメージの指定
②　コンテナの名前
③～⑦
　　諸々の環境変数。
　　別ファイルに記載して「env_file: .env」みたいに指定することも可能。
　　（というかセキュリティ面とか考えたらその方が良いのでは）
⑧　デフォルトのコマンドを上書きする、らしい。
⑨～⑪
　　諸々のマウント　
⑫　PORTを指定


## Dockerfile作成

phpコンテナの構築時に、以下のDockerfileを使用する。

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

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"
``` 

各行の処理については、[Dockerfileリファレンス](http://docs.docker.jp/engine/reference/builder.html)を参照。


## php.ini作成

phpの設定ファイル。

```:php.ini 
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
``` 

## default.conf作成

nginxの設定ファイル。

```:default.conf 
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;

  location / {
    root /var/www/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }
``` 

## Laravelプロジェクト作成

``` 
docker起動
# docker-compose up -d
ERROR: Service 'php' failed to build: The command '/bin/sh -c php composer-setup.php' returned a non-zero code: 1
``` 

こけた。
こけたら元に戻してくれるのかと思いきや、戻らないみたい。

``` 
イメージ一覧を表示
# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              4744417607b3        10 minutes ago      472MB
php                 7.2-fpm             6ff5bc1d81f0        7 days ago          398MB
``` 

どこでこけたんだろう。
と思って、元の記事のコメント見てみた。

>自分と同じようにComposerのインストールで引っかかった方は、
最新のハッシュ値を下のサイトで確認して書き換えると上手くいくと思います。
https://getcomposer.org/download/

ふむふむ、確かにリンク先確認したらハッシュ値が違った。
※ていうか、べた書きなことに少し疑問盛ってたけど、ちゃんと追っておけばよかった。


>Composerのインストールはバージョンによってハッシュ値が異なってしまう関係上、毎回Dockerfileを書き換えのは面倒なので以下の書き方をすると書き換える必要がなくて便利です！

``` 
# 変更前
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

# 変更後
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
``` 

なにこれ天才かよ。。。

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

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"
``` 

すっきりした。
もう一回実行してみる。

``` 
docker起動（2回目）
# docker-compose up -d
ERROR: Service 'php' failed to build: The command '/bin/sh -c composer global require "laravel/installer"' returned a non-zero code: 1
``` 

こけたけど、さっきよりは処理進んでるっぽい。
赤字の部分にこんなのがあった。

``` 
[ErrorException]
proc_open(): fork failed - Cannot allocate memory
``` 

**これ、知ってるぞ**
Docker云々の前、普通にLaravelデビューするときに出てきた。
その時と同じ状況でやってるんだから、同じことが起きても不思議じゃないよね。

https://akamist.com/blog/archives/236
以前はここに記載の方法「Swap領域の有効化」でうまくいったけど、Dockerでやってる今はどうなんだろう。
試しにやってみる。

``` 
# /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 14.0341 s, 76.5 MB/s

# /sbin/mkswap /var/swap.1
mkswap: /var/swap.1: insecure permissions 0644, 0600 suggested.
Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
no label, UUID=672b24c0-04f2-4b5b-b6ce-b3bd6ad3a764

# /sbin/swapon /var/swap.1
swapon: /var/swap.1: insecure permissions 0644, 0600 suggested.
``` 

準備OK。いざ。

``` 
docker起動（3回目）
# docker-compose up -d
（略）
Creating php     ... done
Creating db-host ... done
Creating nginx   ... done

# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                               NAMES
c111408c89a5        nginx               "nginx -g 'daemon of…"   2 minutes ago       Up 2 minutes                0.0.0.0:80->80/tcp                  nginx
1d5bc8716afa        mysql:5.7           "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes                0.0.0.0:3306->3306/tcp, 33060/tcp   db-host
94d3abb55903        project_php         "docker-php-entrypoi…"   2 minutes ago       Up 2 minutes                9000/tcp                            php
93eae4fcf1cc        f959b6f2dc70        "/bin/sh -c 'compose…"   12 minutes ago      Exited (1) 11 minutes ago                                       upbeat_saha
7e3ab5b0fb47        4744417607b3        "/bin/sh -c 'php com…"   45 minutes ago      Exited (1) 45 minutes ago                                       sleepy_hellman
※下の2つはこけた時のなので、後で消した
``` 

#### **脳汁☆全開**
続きもやっていこう。

``` 
phpコンテナに入る
# docker-compose up -d
root@94d3abb55903:/var/www#

Laravelプロジェクト作成
# laravel new
（略）
Application ready! Build something amazing.
``` 

さっくりと成功しました。

## 動作確認

事前にEC2のセキュリティグループに手を加えておくのを忘れない。

**こけた。**
（画面とりわすれちゃったけど）LaravelのPermission Denied的なやつがでてくる。

Laravelまわりのディレクトリのパーミッション変更が必要だった。
「これってセキュリティ的にどうなの？」とは思う。
けど現段階ではまだそこまで考えなくていいので、無心で変えていく。

``` 
# sudo chmod 2775 /var/project/server
# find /var/project/server -type d -exec sudo chmod 2775 {} +
# find /var/project/server -type f -exec sudo chmod 0664 {} +
# sudo chmod -R 777 /var/project/server/storage/
# sudo chmod -R 777 /var/project/server/bootstrap/cache
``` 

**うまくいった。今回はここまで。**
![20200305_DockerLaravelTest.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596543/2f467404-64e1-9317-5468-733f334e3dcb.png)