DockerでPHP5-Alpineの開発環境（MySQL、Redis)を作る

# はじめに

Dockerの復習がてら、PHPの開発環境を構築してみた。

# システム構成

* nginx
* php-fpm
    * php5/php7
* mysql
* redis

世の中、PHP5のサポートが切れるのでPHP7へ移行中です。そのため、PHP5の開発環境が必要になるのです。

PHP5だけの対応部分を書いておきますので、それを無視すればPHP7でも動作します。

# nginx + php7 + mysql (+http2)

リクルートの山田さんの記事が、ステップ・バイ・ステップで書かれていて、Dockerの理解・復習にはかどります。

ありがとうございます!

[docker-compose による nginx + HTTP/2 + PHP-FPM7 + MySQL 環境の構築方法](https://tech.recruit-mp.co.jp/infrastructure/post-12795/)

# php5-alpine対応

[Docker HubのPHPのリポジトリ](https://hub.docker.com/_/php)からPHP5＋alpineのイメージを探して書き換えます。

```dockerfile
FROM php:5-fpm-alpine
RUN docker-php-ext-install pdo_mysql mysqli mbstring
```

[GitHub上に変更したファイルを載せています。](https://github.com/idani/nginx-http2-php-mysql/commit/d1be66249b808929d33a1522a026d371918bf352)

# xdbug対応

デバッガがあるかないかは、使える装備が竹槍なのか戦車なのかぐらい効率・威力が違います。

作成したサンプルは以下になります。
https://github.com/idani/nginx-http2-php-mysql/tree/master/step6-php5-xdebug

以下の記事を参考にDockerFileを書き換えていきます。
こちらの記事からリンクされているGithub上の設定ファイルの方が、かなり参考になります。
一読されると良いかと思います。

[php-alpineコンテナにxdebugをインストールする時にハマったメモ](https://qiita.com/ucan-lab/items/fbf021bf69896538e515) 

さて、PHP5向けには、最新のXdebugは対応していません。
[xdebugのリリースノート](https://xdebug.org/updates.php#x_2_6_0alpha1)を確認すると、２．６からPHP5をサポートしないということです。このためxdebugの２．５．５を利用します。
※PHP7の方は、２．５．５を外してください。

また、Xdebugを導入することで、時刻表示の警告が表示されるようになりました。
このためTimezoneの設定も追加しています。


```dockerfile:app/Dockerfile
FROM php:5-fpm-alpine

# timezone
ARG TZ=Asia/Tokyo

# Composer install
RUN set -eux && \
  apk add --update --no-cache --virtual=.build-dependencies \
    autoconf \
    gcc \
    g++ \
    make \
    tzdata && \
  cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
  echo ${TZ} > /etc/timezone && \
  pecl install xdebug-2.5.5 && \
  apk del .build-dependencies && \
  docker-php-ext-install pdo_mysql mysqli mbstring && \
  docker-php-ext-enable xdebug

```

また、xdebug用の追加設定は、「xdebug.ini」として、別途作成して、追加設定という感じで読み込むようにしています。

* [[PHP] Xdebug のリモートデバッグ、理解していますか？](https://qiita.com/castaneai/items/d5fdf577a348012ed8af)を参考にさせていただきました。

補足ですが、php.ini自体は、コンテナのデフォルト設定を使っています。
date.timezoneの設定をする必要がありましたので、php.iniを用意するのではなく、xdebug.iniに追記して、設定ファイルを1つにしています。

```ini:xdebug.ini
date.timezone = "Asia/Tokyo"

xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.remote_port=9000
xdebug.remote_host="host.docker.internal"
xdebug.remote_connect_back = 0
; xdebug.remote_log=/tmp/xdebug.log

```

このxdebug.iniは、共有ファイルとしてコンテナにマウントして利用します。

```yml:docker-compose.yml
version: '3'
services:
  web:
    image: nginx:1.13.5-alpine
    ports:
      - "80:80"
    depends_on:
      - app
    volumes:
      - ./web/default.conf:/etc/nginx/conf.d/default.conf
      - ./data/html:/var/www/html

  app:
    build: ./app
    env_file: .env
    environment:
      DATABASE_HOST: db
    depends_on:
      - db
    volumes:
      - ./data/html:/var/www/html
      - ./xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
  db:
    image: mysql:5.7.19
    env_file: .env
    ports:
      - "3306:3306"
    volumes:
      - db-data:/var/lib/mysql
      - ./db/initial.sql:/docker-entrypoint-initdb.d/initial.sql

volumes:
  db-data:

```

VS code 側の設定は、以下の記事を参考にさせていただきまして、デバッグ環境を手に入れることができました。

* [Dockerで構築したPHP環境をxdebugでデバッグ（vscode）](https://qiita.com/gigosa/items/90431be7a6a79db78480)

```json:launch.json
        {
            "name": "Listen for XDebug step6",
            "type": "php",
            "request": "launch",
            "port": 9000,
            "pathMappings": {
                // {docker上のdocument root}:{ローカルのdocument root}
                "/var/www/html":"${workspaceRoot}/step6-php5-xdebug/data/html"
            }
        },   
```
launch.jsonの全体像は、[Gitのサンプル](https://github.com/idani/nginx-http2-php-mysql/blob/master/.vscode/launch.json)で確認をしてください。

これで以下のようにvscodeのデバッグモードを利用できるようになりました。

<img width="1100" alt="index_php_—_nginx-http2-php-mysql.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/22c30a3e-47c4-5a67-d7bb-0c54ff527375.png">

<img width="960" alt="Step_6_nginx___PHP5___MySQL.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/7b835784-a887-0336-e097-c0a8ec16489b.png">

## 補足

xdebugの設定を見ると、9000ポートは使用しているから９０００１にするとかって設定をみます。php-fpmのポートが9000で、Xdebugの9000とかぶるという考えのように思えます。

私も勘違いをしていたのですが、Xdebugはクライアントでデバッガ(Vscode)がサーバとなります。

図にすると以下のような感じです。

![php-docker-xdebug.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/81718a94-8cf6-1fea-2049-3859e6d3291b.png)

簡単に説明すると。。。

1. ブラウザで１２７．０．０．１（：８０）を開くとNginx(web)に接続します。
2. Nginxは、index.phpのアクセスということで、PHP-FPMの９０００ポートにPHPの処理を依頼します。
3. PHP-FPMは、PHPの処理をするのですが、Xdebugの設定がある場合は、PHPの処理を「xdebug.remote_host：xdebug.remote_port」に送信します。
4. デバッガ(VS Code)が１２７．０．０．１：９０００ポートで待ち受けしており、PHP-FPMからのPHPの処理情報を受け取ります。





# PHP Redisの導入

Redisも使いたいので導入していきます。
こちらもxdbugと同様にPeclで導入するのが定石のようです。
以下のDockerFileのXdebugのところに redisを追加します。

```dockerfile:app/DockerFile
FROM php:5-fpm-alpine

# timezone
ARG TZ=Asia/Tokyo

# Composer install
RUN set -eux && \
  apk add --update --no-cache --virtual=.build-dependencies \
    autoconf \
    gcc \
    g++ \
    make \
    tzdata && \
  cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
  echo ${TZ} > /etc/timezone && \
  pecl install redis xdebug-2.5.5 && \
  apk del .build-dependencies && \
  docker-php-ext-install pdo_mysql mysqli mbstring && \
  docker-php-ext-enable redis xdebug

```

次に、docker-copose.yml にRedisサーバを追加します。

```yml:docker-compose.yml
version: '3'
services:
  web:
    image: nginx:1.13.5-alpine
    ports:
      - "80:80"
    depends_on:
      - app
    volumes:
      - ./web/default.conf:/etc/nginx/conf.d/default.conf
      - ./data/html:/var/www/html

  app:
    build: ./app
    env_file: .env
    environment:
      DATABASE_HOST: db
      REDIS_HOST: redis
    depends_on:
      - db
      - redis
    volumes:
      - ./data/html:/var/www/html
      - ./app/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
  db:
    image: mysql:5.7.19
    env_file: .env
    ports:
      - "3306:3306"
    volumes:
      - db-data:/var/lib/mysql
      - ./db/initial.sql:/docker-entrypoint-initdb.d/initial.sql
  redis:
    image: redis:alpine3.9
    command: redis-server --requirepass ${REDIS_PASSWORD}
    ports:
      - "${REDIS_PORT}:${REDIS_PORT}"
volumes:
  db-data:

```

Redis用のパスワード(REDIS_PASSWORD)とポート(REDIS_PORT)は、「.env」の環境変数で指定をしています。

```sh:.env
・・・

# REDIS関係
REDIS_PORT=6379
REDIS_PASSWORD=password
```

PHP上のRedisの動作確認は、[phpredisの使い方まとめ](https://qiita.com/yudsuzuk/items/d88717e6e55b5c7fa16e)を参考にさせていただきました。

テスト用にindex.phpにRedisのテストコードを追記します。
しれっと「REDIS_HOST」という環境変数がありますが、こちらはdocker-composeでappコンテナで指定ししています。

```php:data/html/index.php
        $redis = new Redis();
        $redis->connect($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']);
        $redis->auth($_ENV['REDIS_PASSWORD']);
        echo '<pre class="log">';
        echo 'Redis接続' . PHP_EOL;
        echo $redis->ping() . PHP_EOL;

        // string_keyというkeyにhugaという値をセット
        $redis->set('string_key', 'huga');
        // 値を取得する
        $value = $redis->get('string_key');
        // 表示
        echo $value . PHP_EOL; // huga

        // lPushは先頭、rPushは末尾に値をpush
        $redis->rPush('list_key', 'a');
        $redis->rPush('list_key', 'b');
        $redis->lPush('list_key', 'c');
        $redis->lPush('list_key', 'd');

        // 値をすべて取得する -1はすべて
        $value = $redis->lRange('list_key', 0, -1);

        // 表示
        var_dump($value);
        echo '</pre>';
```

以下のように動作確認ができました。

<img width="1033" alt="Step_7_nginx___PHP5___MySQL___xdebug___redis.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/5038fcb3-0841-ea2c-7988-207839284341.png">

# まとめ

PHPの開発環境が何度でも再現可能な状態にすることができました。
今後のPHPの開発で活用していきたいですね。

~~ちなみに、あとメールのテスト環境がほしいので作っていきます。~~
[メール環境を構築しました!](https://qiita.com/idani/items/e703b8810db219bd57fa)