CakePHP3もくもく勉強会#2レポート「DockerでPHPの開発環境を構築しよう」

今日は[[第2回]CakePHP3もくもく勉強会 - connpass](https://connpass.com/event/63761/)に参加しました。参加者は僕を含めて5名。

いきなり「Laravelで何か作りたい」とCakePHP勉強会を根底から覆す発言があったり、「Lumen良さそう」「そもそもそれフルスタックフレームワークでもないし！」といったフリーダムな雰囲気で勉強会が幕を開けましたwww 他にも、フローベースでIoTをプログラミングできるNoderedの話や、作業記録アプリTogglの話など、CakePHPの枠を超えた情報交換があったりと、ゆるいオフライン勉強会ならではの面白さがありましたね。

中でも「PHPの開発環境ってどうしてます？」という発言がキッカケで、DockerでPHPの環境を作ることをテーマに勉強会を進める流れになりました。もくもく会というタイトルとはうらはらに突発的にハンズオンになったわけです。

本稿では行ったハンズオンの要旨を公開したいと思います。教えながら書いたところもあるので、言葉足らずだと思います。おかしなところはご指摘お願いします。

なお次回からはイベント名が変わり、[[第3回]YYPHP - connpass](https://connpass.com/event/64263/)になります。

## Docker for Macをインストールする


* Docker for Macをダウンロードして、インストールする。
* ダウンロードするもの: https://download.docker.com/mac/stable/Docker.dmg
* Docker Hubのアカウントは作らなくてOK。

## PHP+MySQL+Nginxの環境を構築する


* 適当にフォルダを作る。プロジェクト名がおすすめ。

```
mkdir my-first-cake-project
cd my-first-cake-project
```

* docker-compose.yml という名前でファイルを置く

```yaml:docker-compose.yml
version: '2'
services:
  # DB
  mysql: # これは自由につけて良い名前
    container_name: "mysql"
    image: mysql:5.6
    ports:
      - '3306:3306' # デバッグ用に開けとく。SequelProなどで繋げるように
    environment:
      MYSQL_ROOT_PASSWORD: root
  # php
  php:
    container_name: "php"
    image: php:7.1-apache
    ports:
      - '8080:80'
    volumes:
      - ./html:/var/www/html
    links:
      - mysql
```

## 起動

```
docker-compose up -d
```

## 起動状況の確認

```
docker ps
```

2つのコンテナが立ち上がっていればOK

```
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
d326a0b91a48        php:7.1-apache      "docker-php-entryp..."   2 hours ago         Up 2 hours          0.0.0.0:80->80/tcp       php
7fee0033f8fb        mysql:5.6           "docker-entrypoint..."   2 hours ago         Up 2 hours          0.0.0.0:3306->3306/tcp   mysql
```

## index.phpを作る

html/index.phpを作る:

```php:html/index.php
<?php
phpinfo();
```

ファイル構成はこうなる。

```
.
├── docker-compose.yml
└── html
    └── index.php
```

## トップページを開いてみる

ブラウザでhttp://localhost:8080 を開くとトップページが見れるはず。

## 停止

```
docker-compose stop
```

## 消し去る

stopしてから実行するとコンテナが消える。

```
docker-compose rm
```

## 質問

### Docker for MacとXAMPPはどう違うか？

普段はWindowsでXAMPPを使っているが、Dockerはどう違うのか？

Dockerは軽量仮想化、XAMPPはApache・PHP・MySQLの実行環境がバンドルされたアプリ。どちらも、PHPの開発環境を作るのに使えるが、違いがある。

DockerはLinuxのOSをコンテナ呼ばれる仮想環境を作ってApacheなりMySQLなりのプロセスを実行してくれる。PHP+Apacheのコンテナ、MySQLのコンテナはそれぞれ独立したLinux環境になる。今回はDocker for Macでその2つのコンテナを起動したが、イメージとしては、Mac上に2台のLinuxサーバを立てた格好になる。

XAMPPはWindows上に直接PHP+ApacheとMySQLのプロセスを実行するので仮想マシンではない。

XAMPPはApache+MySQLの環境に特化しているが、Dockerはそれに限らないので、たとえば、MongoDBが追加で必要になったら、Dockerなら簡単にMongoDBつきの開発環境も作れる。

複数のプロジェクトをあつかうときは、XAMPPだとすべてのプロジェクトをhtdocsに入れて開発するのが普通だが、Dockerはプロジェクトごとにdocker-compose.ymlを作ってやるほうがよい。

プロジェクトによってPHPのバージョンが違ったり、必要な拡張が異なったりする。XAMPPのように全プロジェクトを同じ環境で開発していると、あるプロジェクトのためのバージョンアップや拡張追加が、他のプロジェクトに影響することもしばしばあるが、Dockerはプロジェクトごとに別の環境を簡単に作れるので、そういったトラブルに遭いにくい。

## トラブルシューティング


### 3306、8080が使えない

docker-compose upでError starting userland proxy: Bind for 0.0.0.0:3306といったエラーメッセージが出るときは、他のアプリ等がポート3306や8080を使っている。

```console:エラーメッセージ
❯ docker-compose up -d
Starting mysql ...
Starting mysql ... error

ERROR: for mysql  Cannot start service mysql: driver failed programming external connectivity on endpoint mysql (874ae0f88156787bae18f0b25d9651e9591359d438183910f6a117b8088d2336): Error starting userland proxy: Bind for 0.0.0.0:3306 failed: port is already allocated

ERROR: for mysql  Cannot start service mysql: driver failed programming external connectivity on endpoint mysql (874ae0f88156787bae18f0b25d9651e9591359d438183910f6a117b8088d2336): Error starting userland proxy: Bind for 0.0.0.0:3306 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.
```

MAMP等のアプリが起動していないか確認し、起動していたら止める。それでも解決しない場合は、docker-compose.ymlのポートを別の番号に変更して試してみる。たとえば、3333とか9000とか。