汎用的なLEMP環境をdocker-compose up -dコマンド一発で起動するDockerキットを作りました！


## 作成背景
複数のサービスを取り扱う職場で横断的に開発に参加しており、「〇〇システムの改修が終わったら△△システムの開発を進めてね〜〜」という感じでのオーダーが多い職場でした。サービスによっては複数のシステムが同一言語で複数のメジャーバージョンを使用しており、[XAMPP](https://www.apachefriends.org/jp/) をその度にインストールするなど、ローカルPCの開発環境が重くなったり、環境がPC上で散らかっちゃったりしている状況でした。
さらには複数のシステムを跨いだ動きを考えて開発をするものについては、AWSなどに頼ってインフラを構築しなければならないなと思う状況でした。

~~AWSを個々の開発環境として使っていたらお金もかかりすぎてしまうため、~~自分のクライアントPC内で環境が作れないかなといろいろ探していたところ、1年前にDockerと出会い、DockerでWebサービス環境をいい感じに作れるようでしたので、汎用的で職場でも使用しはじめている環境構成を公開したいと思います。

<Details><summary> LEMP環境とは</summary>
LEMP環境とは、Webアプリケーションを開発するために使用するOS、Webサーバ、データベースサーバ、プログラミング言語を著した言語です。よく使われるWebサーバとして「Apache」が有名で、その頭文字をとって「LAMP」環境と呼ぶことが多く、聞いたことがある方もいるのではないでしょうか？
今回のLEMP環境も同じような考え方で、「E」は「Nginx（読み方：エンジンエックス）」の読みの頭文字の「E」をとっています。
- Linux（OS）
- Nginx（Webサーバ）
- MySQL / MariaDB（データベースサーバ）
- PHP（アプリケーションサーバ（プログラミング言語））
</Details>

## コンテナイメージの選定で必要なイメージなど
### jwilder/nginx-proxy
複数のコンテナで同一のポートで通信したいときに入れておくと良いリバースプロキシサーバのコンテナイメージです。
1つのサービスで複数のドメインを同時に利用する場合があることから、上記のコンテナを立てておきます。


### Alpine Linux
軽量なLinux OSで、よく使用しているUbuntuの1/7、CentOSでは1/40の容量で構成されているようです。

参考：[@ryuichi1208さん「超軽量なAlpine Linuxについて調べた」](https://qiita.com/ryuichi1208/items/6020cfabc92bd8153654)
> CentOS 約4GB
> Ubuntu 約700MB
> Alpine 約100MB

この汎用LEMP開発キットでは、コンテナ生成の際に時間のロスを減らすために、シンプルで軽量なOSであるAlpine Linuxのイメージをふんだんに採用しています。

## ディレクトリ構成
Dockerを存在を布教するまで知らないエンジニアが多かったこともあり、新米エンジニアなどには「プログラムの改修だけなら、このディレクトリの中身だけをいじれば良い」といえるような、シンプルなディレクトリ構成にするように心がけました。
昨今トレンドになってきている「[マイクロサービスアーキテクチャー](http://album.cloudit.co.jp/?p=5212)」の考えを参考にしてNginx、MySQL/MariaDB、PHPをコンテナごとに分割しました。[^1]
全体的なディレクトリ構成は下記のようになります。

```:ディレクトリ構成
project_root/
 ┣ data/
 ┃  ┣ html
 ┃  ┃  ┗ web-app/
 ┃  ┗ logs
 ┃     ┗ nginx/
 ┣ php-fpm/
 ┃  ┣ conf/
 ┃  ┃  ┗ php.ini
 ┃  ┗ Dockerfile
 ┣ nginx/
 ┃  ┣ conf.d/
 ┃  ┃  ┗ default.conf
 ┃  ┗ Dockerfile
 ┣ mariadb/
 ┃  ┗ docker-entrypoint-initdb.d/
 ┃     ┗ initial.sql
 ┣ phpmyadmin/
 ┃  ┗ config/
 ┃     ┗ config.inc.php
 ┣ env/
 ┃  ┣ .env
 ┃  ┗ その他環境変数のテンプレートファイル
 ┣ docker-compose.yml
 ┗ .gitignore
```

基本的に、インフラを整える必要のない方には原則「data」ディレクトリ直下のソースコードをいじっていただければ良いようにしています。

| ディレクトリパス | 説明                                                                     |
|:------------|:------------------------------------------------------------------------|
| data/html   | 各コンテナに設置するプログラムソースを格納（~~執筆時に「data/src」にすればよかったと反省中~~）| 
| data/logs   | 各コンテナのログファイルを出力                                                  | 
| nginx       | Nginxコンテナで使用する設定ファイルなどを格納しています                              | 
| mariadb     | データベースコンテナで使用する設定ファイルなどを格納しています                         | 
| phpmyadmin  | Webベースでデータベースを操作するためのツールで、独自の設定をする際に設定ファイルを格納します| 
| env　　　    | すべてのコンテナに共通する環境変数と各コンテナごとに挿入する環境変数のファイルを格納します。あくまでもこれは「テンプレート」のため、実際に環境変数を使用する場合は「.env」というディレクトリ名で複製して使うようにします（DockerキットをGitHubに登録するためにわざとしてます）| 

### Docker Compose
LEMP環境のコンテナを同時に生成できるように設定情報を`docker-compose.yml`に記載をしていきます。

```:docker-compose.yml
version: '3'

services:
  nginx-proxy:
    image: jwilder/nginx-proxy:alpine
    privileged: true
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./data/logs/nginx/nginx-proxy:/var/log/nginx
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro

  web:
    image: nginx:alpine
    env_file:
      - ./.env/.env
    environment:
      - VIRTUAL_HOST=www.app.local
    depends_on:
      - app
    volumes:
      - ./data/html/app:/var/www/html
      - ./nginx/web.conf:/etc/nginx/conf.d/default.conf
      - ./data/logs/nginx/api:/var/log/nginx

  app:
    build:
      context: .
      dockerfile: ./php-fpm/Dockerfile
    ports:
      - 9000:9000
    env_file:
      - ./.env/.env
    volumes:
      - ./data/html/app:/var/www/html
      - .env/app.env:/var/www/html/.env # 例えば、app.envという名前でアプリケーションの.envファイルとして、アプリケーション内のライブラリphpdotenvを用いて環境変数を読み取らせるようにする

  db:
    image: mariadb:latest
    ports:
      - 3306:3306
    env_file:
      - ./.env/.env
    volumes:
      - db-data:/var/lib/mysql
      - ./mariadb/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d

  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    ports:
      - 8080:80
    env_file: ./.env/.env
    environment:
      - PMA_HOST=db
      - PMA_USER=root
      - PMA_PASSWORD=password
      - PMA_BLOWFISH_SECRET=
    depends_on:
      - db
    volumes:
      - ./phpmyadmin/config/config.inc.php:/var/www/html/config.inc.php

volumes:
  db-data:
```

### Dockerfileについて
#### データベースコンテナ（MariaDB/MySQL）
基本的にチューニングを考えた作りにしていなかったので、データベースコンテナのDockerfileは存在しません。
コマンドベースでチューニングを行う場合は、Dockerfileを作成してやりましょう。

#### Webサーバコンテナ
基本的にチューニングを考えた作りにしていなかったので、データベースコンテナのDockerfileは存在しません。
コマンドベースでチューニングを行う場合は、Dockerfileを作成してやりましょう。
また、`nginx/conf.d`ディレクトリ内には、コンテナ名ごとにnginxのconfファイルを格納しておくと、修正時にわかりやすくなります。
複数のWebサーバを動かす必要が出てきたときは、そのコンテナごとにconfファイルを`/docker-compose.yml`の`volumes:`内に設定すれば、コンテナを切り分けて入れることも可能です。

#### アプリケーションコンテナ
PHP7.4以降では「oniguruma」という正規表現のモジュールがPHPに標準ライブラリとして搭載していないようです。（※ ***ドツボにはまる***重要ポイントです！）
composerは、開発時は基本的に「ホスト側のcomposer」を利用してライブラリをインストールしていたので、コンテナ内では気持ち程度に入れております。

```Dockerfile:/php-fpm/Dockerfile
FROM php:fpm-alpine
RUN apk upgrade && \
    apk update && \
    apk add --update --no-cache \
      oniguruma-dev \ # PHPバージョンが`<7.4`であれば、この行は不要です！
      icu-dev && \
    apk add \
      vim \
      git \
      composer && \
    docker-php-ext-install -j$(nproc) \
      intl \
      pdo_mysql \
      mysqli \
      mbstring

WORKDIR /var/www/html
```


## 使用コマンド
使用コマンドは下記の2つだけです。

```:バックグラウンドでdocker-compose.ymmlファイルに記載のあるdockerコンテナを一括起動
docker-compose up -d
```
```:バックグラウンドでdocker-compose.ymmlファイルに記載のあるdockerコンテナを一括シャットダウン
docker-compose down
```

また、コンテナがうまく立ち上がっているかの確認をするときのために、下記の2つのコマンドも覚えておくと便利です。

```:コンテナがうまく立ち上がっているかを確認する
docker-compose ps
```
```:コンテナを特定してコンテナを立ち上げる際のログを確認する
docker-compose logs | grep <CONTAINER_NAME>
```

## 最後に
今回は、Dockerを使った簡単で汎用的な開発環境構築キットの作り方を公開させていただきました。
実際のソースコードも公開させていただきますので、よかったら使用してみてください。

[yusuke-shina/apache-httpd-docker-kit](https://github.com/yusuke-shina/apache-httpd-docker-kit)
＊詳しいセットアップの仕方などをREADME.mdに記載できていませんが、記載できる隙が作れたら、更新していきます！

今回は、~~簡単で汎用的な開発環境構築キットという名目だったので~~（Dockerでのネットワーク構築については勉強中の身）ネットワーク周りの設定をDocker Composeを使って反映できていませんので、その辺とかも出来次第更新できたらと考えております。

具体的な説明があまりできていない雑な記事ではありますが、Dockerにこれから挑戦される方、開発環境をDocker化したいという方々のさわりとして、参考にしていただければ幸いです。
また、お詳しい方はコメント欄に認識が異なる部分がありましたらご指摘いただけると幸いです。

[^1]: 本当にこのやり方がマイクロサービスアーキテクチャの考え方に則しているかが怖いですが……