おっさんのダベリ

IT系の技術的な話題が多いです

DockerでMySQL、PHP、Apacheを連携させる

きっかけ

MySQLサーバのTimeZoneがUTCで、アプリケーションのTimeZoneがAsia/Tokyoの場合に、実際のところどうなるか確認したかった。

ということでDockerの勉強も兼ねてMySQLPHP/Apacheの2種類のイメージを連携させる方法を調べたのでメモります。

いつものように先人の知恵はこちら

今回使ったイメージは公式のイメージを利用しています。

MySQLサーバ起動

上記の公式イメージを取得し、ローカルでコンテナ起動

$ docker pull mysql:5.7
$ docker run --name mysqld -e MYSQL_ROOT_PASSWORD=pass -d mysql:5.7

ここでは、ROOTのパスワードを指定しています。 パスワード以外にもいろいろと指定できますので、本格的なWebアプリケーション用に構築するならばDocker Hubや参考サイトを確認してください。

MySQLクライアントの起動

同じイメージにはMySQLのクライアントも入っているので、別のコンテナとして起動します。 --linkオプションを付けることで、先ほど起動したmysqldと連携させることが出来ます。

$ docker run --link  mysqld:mysql -it --rm mysql /bin/bash

MySQLクライアントからMySQLサーバに接続

Dockerのコンテナに入れたら以下のコマンドでMySQLサーバに接続できます。

# mysql -u root -ppass -h $MYSQL_PORT_3306_TCP_ADDR

$MYSQL_で始まる環境変数は他にも定義されいますので、envコマンドなどで確認してください。

接続できたら、てけとうなDBとテーブルを作ります。

CREATE DATABASE mydb;
USE mydb;
CREATE TABLE users(
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(32),
  created TIMESTAMP
);
INSERT INTO users(name, created) VALUES('山田', NOW());

PHPのイメージ準備

公式のphp:5.6-apacheをベースにして、PDO MySQLを追加インストールしたイメージを作成します。

FROM php:5.6-apache
RUN apt-get update && \
  docker-php-ext-install pdo_mysql

これをベースにイメージをビルドします

$ docker build -t php:5.6-apache-pdo-mysql .

PHPコンテナ起動

PHPのイメージがビルドできたら、適当なディレクトリをマウントして起動します。 今回はApacheが同梱されたイメージですが、PHPCLIを使って確認します。

$ docker run --link  mysqld:mysql -it --rm -v `pwd`:/var/www/html php:5.6-apache-pdo-mysql /bin/bash

UTCMySQLとAsia/TokyoのPHPプログラムの変換

次のようなプログラムで確認してみました。 実行すると1レコードINSERTします。createdにはNOW()で値を入れているためUTCでの時刻として表示されます。 なので、$row['created']は、UTCでの日時表記となっています。 このサンプルではDateTimeクラスを使ってUTCからAsia/Tokyoへの変換を行っています。

<?php
// default timezone=Asia/Tokyo
date_default_timezone_set('Asia/Tokyo');

// connect DB
$db = new PDO('mysql:host=mysql;dbname=mydb', 'root', 'pass');

// sample record
$db->query("INSERT INTO users(name,created) VALUES('ほげほげ', NOW())");

$st = $db->query("SELECT * FROM users");
$rows = $st->fetchAll();
foreach ($rows as $row) {
    $user = [];
    $user['name'] = $row['name'];

    // retrieve as UTC
    $dt = new DateTime($rows['created'], new DateTimeZone('UTC'));
    // set default timezone
    $dt->setTimeZone(new DateTimeZone(date_default_timezone_get()));
    $user['created'] = $dt->format('Y-m-d H:i:s');

    var_dump($user);
}

PHPから値を入れる際には、一工夫必要になる気がしますが、それは今後のお話で。