DockerでPHP+Nginx+MySQLを構築〜使えるようになるまで

タイトル通りです。只今webサイトの構築をしていてどうせならDockerを使って動かそうと思い、Dockerの勉強をしている最中です。qiitaを見れば既に構築済みのスクリプトがたくさんあるのですがそれを使っては勉強にならないし、そこに至った過程などがわからないため、半分以上自分の為に&今後参考にできるようにそこに至った過程を記しながら書き貯めたいと思います。
なお、今回はdocker-compose.ymlを使って書いていきます。

最終的なディレクトリツリーは

```
.
├── Dockerfile
├── docker-compose.yml
├── data
│   └── database
├── web
│   └── test.php
├── nginx
│   └── nginx.conf
├── php
│   ├── Dockerfile
│   └── php-fpm.conf
└── phpmyadmin
    └── config.inc.php
```
#構築
##nginxを作る
webサーバー無くてはサイトは出来ません。まず最初にnginxを立てます。

```docker-compose.yml
nginx:
  image: nginx:latest
  ports:
    - 8080:80
  volumes:
    - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    - ./web:/var/www/html
```

nginxのimageをDocker-hubから取ってきて、portが8080から80にフォワード、自分で書いたnginx.conf、web(ディレクトリ、この中に.html .phpが入ってる)をボリュームする。
これでnginx自体は終わり

##nginxとphpをつなげる
nginxはapacheと違ってphpの使用がめんどくさいです。
初め、安直にlinks: -phpで繋げようとしたら　ERROR: for nginx  Cannot start service nginx: b'Cannot link to a non running container:　と怒られた。
エラーを見ると動いてないコンテナには繋げられないそうなのでlinksの代わりにdepends_onを使います。
>depends_on
Express dependency between services, Service dependencies cause the following behaviors:
>docker-compose up starts : services in dependency order. In the following example, db and redis are started before web.

>docker-compose up SERVICE : automatically includes SERVICE’s dependencies. In the following example, docker-compose up web also creates and starts db and redis.

>docker-compose stop : stops services in dependency order. In the following example, web is stopped before db and redis.
>>[公式ドキュメント](https://docs.docker.com/compose/compose-file/#depends_on)より

nginxはphpに依存するのでphpが起動してから起動するようにします
そして起動しようとしたらまたエラー、色々調べたらversionを3にしたり、上記のnginx.confのボリューム先は/etc/nginx/conf.d/default.conf　じゃないと上手くいかないっぽい。修正して

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

services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./web:/var/www/html
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

  php:
    image: php:7-fpm
    volumes:
      - ./web:/var/www/html
```

これで一先ずphpは使えるようになった。

## PHPをMySQLにつなげる
nginxをphpに繋げた時と同じようにphpをmysqlに繋げる。今度はphpがmysqlに依存しているのでdocker-compose.ymlは

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

services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

  php:
    image: php:7-fpm
    volumes:
      - ./web:/var/www/html
    depends_on:
      - sql

  sql:
    image: mysql:5.7
    ports:
      - 13306:3306
    volumes:
      - ./data/database:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password 
```
こんな感じになった、MYSQL_ROOT_PASSWORDもここで記述する必要がある。

#使えるようになるまで
##MySQLデータの操作
MySQLのデータベースにテーブルを作成したりする為にコンテナにアクセスする必要がある。
まず docker ps でmysqlのコンテナIDを調べる。その後

```bash

$ docker exec -it [mysqlのコンテナID(先頭3文字でも大丈夫)] /bin/bash
```

でコンテナ内のbashが起動する。
あとは通常のmysqlの操作と同じ、 

```
# mysql -u root -p
```

でさっき指定したmysqlのパスワードを打ち込めばログインできる、これでテーブルなどを操作できる。

又、今回phpmyadminを使用してデータの操作をすることにした。
上記のdocker-compose.ymlに以下を追加する

```docker-compose.yml
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - 8888:80
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=sql
      - PMA_USER=root
      - PMA_PASSWORD=password
    depends_on:
      - sql
    volumes:
      - /sessions   
      - ./phpmyadmin/config.inc.php:/var/www/html/config.inc.php 
```

これで8888ポートにアクセスするだけでデータの操作ができるようになる。

##PHPからMySQLへのアクセス
ここから実際にphpを使ってmysqlにアクセスする。
テスト用に

```php:test.php

<?php
    try {
        $dsn = 'mysql:host=sql;dbname=[database];';
        $db = new PDO($dsn, 'root', 'password');

        $sql = 'SELECT version();';
        $stmt = $db->prepare($sql);
        $stmt->execute();
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        var_dump($result);
    } catch (PDOException $e) {
        echo $e->getMessage();
        exit;
    }
?>

```
上記のphpファイルを作ってブラウザ上で開き、しっかりバージョン情報が得られるか実験する。この時host名はlocalhostではなくsqlになる事に注意
そして実際に開いてみると「could not find driver」と出ます。mysqlと接続するにはphp側にpdo_mysqlというものを入れる必要があるらしいのでdocker-compose.ymlを少し編集します。

```docker-compose.yml
  php:
    image: php:7-fpm
    build: ./php/  //追加
    volumes:
      - ./web:/var/www/html
    depends_on:
      - sql
```

そしてphpフォルダ内に以下のDockerfileを作成します

```dockerfile
FROM php:7-fpm

RUN apt-get update && docker-php-ext-install pdo_mysql
```
docker-composeではRUNに相当するものがないのでDockerfileを使ってコンテナ作成時にpdo_mysqlをインストールするよう記述します
その後 docker-compose build でビルドし、再起動させると
![スクリーンショット 2019-12-25 21.00.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465545/960e4445-e5fc-5d27-4abe-2903aa444356.png)
バージョン情報が出ました！これでphpとmysql間が使えるようになりました！

##nginxの設定
実際に使っているとcssファイルやイメージを読み込まなくなったので調べてみるとnginxの設定で解決できたので記載しておきます。nginx.confのserverディレクティブに以下を追加します。

```
location ~\.(css|js|png|html) {
        root /var/www//html;
        access_log off;
        expires max;
        try_files $uri $uri/ =404;
    }
```


以上で一通り使えるようになったはずです。
サーバーで実際に動かすときはOS側で8080番ポートを解放してください、僕はこれに気づかず二、三日頭を捻らせてました。