web開発

[docker,nginx]mysqlコンテナとPHPコンテナをつなげる【ポイントはdriverです】

こんにちは。もんしょー(@sima199407)です。

PHPとMySQLのつなぎ方をdockerで使いたい!

という疑問があるかと思います。
今回は、docker上のmysqlとPHPの接続方法について解説してきたいと思います。
完成のソースコードも用意しておりますので、説明は省略したい方はこちらをどうぞ。
github

また、mysql+python編の記事もありますのでぜひ。

開発環境

・Mac OS Mojave
・docker for Mac
・MySQL 5.7
・PHP7.1

上記の通りです。

dockerのインストール方法は下記からDLしていただければオッケーです。

docker for mac

docker-php-mysql/
├── mysql
│   ├── Dockerfile
│   ├── docker-compose.yaml
│   └── my.cnf
└── nginx-php
    ├── Dockerfile
    ├── default.conf
    ├── docker-compose.yml
    └── php
        └── index.php

docker-compseファイルを作成

今回はdocker-composeを使って作業していきます。

通常であれば1つのdocker-composeファイルにmysqlとphpを書いていくのですが、今回は別々に作成されたものをつなげていく作業をやっていこうと思うので別々で書いていきます。

mysql/docker-compose.yml

コードは以下の通り

version: '3'
services:
  mysql:
    image: mysql:5.7
    container_name: mysql
    ports:
      - "3316:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: mysql
      MYSQL_PASSWORD: mysql
      MYSQL_DATABASE: mysql
    volumes:
      - ./my.cnf:/etc/mysql/conf.d/my.cnf
    volumes_from: #may not require
      - mysql-volume:rw #may not require
    working_dir: "/var/lib/mysql"
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    depends_on:
      - mysql-volume



  mysql-volume:
    image: busybox
    container_name: mysql-volume
    volumes:
      - ./data:/var/lib/mysql

nginx-php/docker-compose.yml

コードは以下の通り

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

  app:
    container_name: php-alpine
    build: ./php
    volumes:
      - ./data/html:/var/www/html

web→nginx
app→php
になります。

docker-composeでコンテナを作成するときにimageかbuildで作成するかと思いますが、phpの方はDockerfileを参照するのでbuildに書いていきます。

DockerFileを作成

mysql/Dockerfile

コードは以下の通り

FROM mysql:5.7
RUN touch /var/log/mysql/mysqld.log
FROM alpine:latest

RUN apk update && \
    apk add mysql-client

nginx-php/Dockerfile

コードは以下の通り

FROM php:7.1-fpm
RUN docker-php-ext-install pdo_mysql ###ポイント

2行目のコマンドが重要でして、デフォルトだと入っていないmysqlのドライバーをインストールしています。これを入れていないとエラーがでて接続ができません。(ここでハマりました。。)

.confファイルの作成

各コンテナの詳細な設定ファイルになります。
ここが抜けると後々に支障をきたす場合がございますので作成することをおすすめします。

php/default.conf

コードは以下の通り

server {
    listen 80;
    server_name _;

    root  /var/www/html;
    index index.php;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(\.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

imageだけでいいかなと思って作業していたら、cssとjsを読み込んでくれないというエラーが出てきたので、こちらを入れてコンテナを再度立ち上げたところ、その事象を解決できたので入れておきましょう。

mysql/my.cnf

コードは以下の通り

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

[client]
default-character-set=utf8

mysqlの設定内容です。
コンテナ作るときに設定しておくと便利なので書いておきます。

コンテナ生成〜コンテナ同士の接続まで

srcディレクトリを除くファイルが出来上がったので、ここからコマンドを叩いていきます。

phpとnginxのコンテナを立ち上げる

以下のコマンドを叩きます。

$ cd nginx-php
$ docker-compose up -d  --build

無事に立ち上がっているか確認します。

$ docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                               NAMES
4444eree4444        nginx:1.13.5-alpine   "nginx -g 'daemon of…"   27 hours ago        Up 27 hours         0.0.0.0:88->80/tcp                  nginx-alpine
333wwwww3333        nginx-php_app         "docker-php-entrypoi…"   27 hours ago        Up 27 hours         9000/tcp                            php-alpine

mysqlのコンテナを立ち上げる

先ほどと同じようにmysqlのコンテナを立てますので、以下のコマンドを叩きます。

$ cd mysql
$ docker-compose up -d --build

そしてmysqlコンテナが立ち上がっている確認します

$ docker ps
395a5936t080        mysql:5.7             "docker-entrypoint.s…"   2 days ago          Up 2 days           33060/tcp, 0.0.0.0:3316->3306/tcp   mysql

mysqlのhostを探す

dockerの場合、mysqlに接続するためのゲートウェイとなるホストIPアドレスを調べる必要があります。

以下の方法で調べることができます。

mysqlのコンテナに入る

ターミナルで作業します

$ docker exec -it [コンテナ名(例)mysql] sh
#

コンテナ名の代わりにコンテナIDを使うこともできます。

ユーザー権限を変える

# mysql -u root -p //rootでmysqlにログイン
Enter password:[docker-compose.ymlで設定したrootのパスワード]
mysql> GRANT ALL PRIVILEGES ON *.* TO mysql@'%';

テストデータを入れる

まずテストテーブルを作成

mysql> CREATE TABLE test_users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(32) NOT NULL,
email VARCHAR(32) NOT NULL,
PRIMARY KEY (id)
);

そして、テストデータを入れます

mysql> INSERT INTO test_users (id,name,email) VALUES (1, 'taro','taro@test.com');

jqをインストール

jqとは、JSONでデータを使うコマンドです。

ターミナルで以下を叩きます。

$ brew install jq

MySQLコンテナのネットワークを調べます。

$ docker inspect mysql | jq '.[0].NetworkSettings.Networks|keys'
[
"mysql_default"
]

mysql_defaultとわかったので、以下のコマンドを叩きます。

$ docker network inspect mysql_default | jq '.[0].IPAM.Config[0].Gateway'
"172.22.3.1"

上記が設定するべきIPアドレスになります。

src/index.phpを作成

接続がうまく行っているかを確認するため、index.phpを作ります。

<?php

//接続する設定を作成
$dsn = 'mysql:dbname=mysql;host=172.22.3.1;port=3316';
$user = 'mysql';
$password = 'mysql';


try {
    $dbh = new PDO($dsn, $user, $password);
    


    $sql = "SELECT * FROM test_users";
    $stmt = $dbh -> query($sql);
    $result = $stmt->fetch(PDO::FETCH_ASSOC);
    if (isset($result)){
    var_dump($result);
    }
    

} catch (PDOException $e) {
    echo "接続失敗: " . $e->getMessage() . "\n";
    exit();
}

$dsnのhostの部分は先程jqを使って調べたIPアドレスを入れます。

接続してみる

http://localhost:88

に接続して、mysqlに入れたテストデータが入っていればOKです。

エラーが出るとき

index.phpに以下を追記してください

<?php 
phpinfo();
~

それでlocalhostにアクセスすると、PHPの情報が入っているので、「PDO」の欄を見てください。

その中に「mysql」が入っている確認してみてください。

もし、ない場合はDockerfileで設定した「docker-php-ext-install pdo_mysql」がインストールされていないようなので、もう一度ファイルを見直しましょう。

まとめ

dockerは便利ですが、環境設定をするときに少々ハマってしまうことがあるので参考になればと思います。
今回の場合ですと、phpにmysqlのドライバーが入っていないと接続できないというのがキーになってくるかと思いますのでまずそこを疑ってみるのが良さそうです。