2
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DockerのMySQL imageでタイムゾーンを日本時間にする

Last updated at Posted at 2020-05-03

はじめに

  • ユーザーが指定したコンテンツ表示予約時間の9時間前にコンテンツが表示されてしまう、とユーザーから問合せがありました

  • コンテンツ表示予約時間の抽出SQLが以下の状態となっており、環境構築時にMySQLを日本時間にしておけば今回の問題が起きなかったのでは、と思ったので、とりあえず試してみます

    SELECT * FROM contents AS c WHERE c.reservation_time <= NOW();
    

前提(試した環境)

  • ホストOSバージョン: macOS Catalina 10.15.4
    • Windows Proであれば、PowerShellでもイケると思います(たぶん)
  • dockerバージョン: 19.03.8
    • docker for mac(windows)必須
  • dockerコンテナのMySQLイメージのバージョン: 5.7系(業務で使用中のものと合わせているので)

※ニワカなので、おかしな実装や考え方をしているかもしれませんが、ご指摘くださると嬉しいです!

実現方法

  1. MySQLが載ってるOSのタイムゾーンを日本時間にする
    • MySQLはOSのタイムゾーンをデフォルトで見るため
  2. MySQLのタイムゾーンを日本時間にする

結論

  • 「1.MySQLが載ってるOSのタイムゾーンを日本時間にする」がDBコンテナ再起動不要な分オススメ

  • そもそもSQLのNOW()関数を使わずに、アプリ側で現在時刻を埋め込むようにすべきなのかも(アプリ側のタイムゾーンを日本時間にしている前提)

    • 本番環境でDockerを使っていなければ、システムOSを日本時間に変更することを忘れる可能性があるので。。。
    アプリ側としてCakePHPを利用しており、`NOW()`を使わない例
    # sample.php
    use Cake\Datasource\ConnectionManager;
    $now = date('Y-m-d H:i:s'); // アプリ側のタイムゾーンで現在時刻を取得
    $sql = "SELECT * FROM contents AS c WHERE c.reservation_time <= '" . $now . "'";
    $connection = ConnectionManager::get('default');
    $results = $connection->execute($sql)->fetchAll('assoc');
    
    • execute()ではなくfind()メソッドなど使うべきですが…いったんわかりやすさ重視で
      (ちなみにはじめにの問合せの修正対応は上記を行いました)

    実現手順

    MySQLが載ってるOSのタイムゾーンを日本時間にする

    1. dockerfileを以下の通り、ホストOSの適当なディレクトリに用意する
      (ファイル名: dockerfile)

      FROM mysql:5.7
      RUN apt-get update
      RUN apt-get install -y tzdata && \
          cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
      ENV MYSQL_ROOT_PASSWORD root
      
    2. 以下のコマンドを実行する

      # イメージのビルド(例:`docker build -t mysql57_jst:latest ./`)
      ホストOS% docker build -t <好きなイメージ名>:<好きなタグ名> <作成したdockerfileがいるパス>
      # DBコンテナ作成&起動(例:`docker run -d -it --name mysql57 mysql57_jst:latest`)
      ホストOS% docker run -d -it --name <好きなDBコンテナ名> <作成したイメージ名>:<作成したタグ名>
      
    3. MySQLのタイムゾーンが日本時間になっているか確認する

    MySQLのタイムゾーンを日本時間にする

    1. 以下のコマンドを実行する

      # DBコンテナ作成&起動(DBコンテナがなければ)
      ホストOS% docker run --name <好きなDBコンテナ名> -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
      # DBコンテナに入る
      ホストOS% docker exec -it <作成したDBコンテナ名> bash
      # タイムゾーンのテーブルを取得
      DBコンテナ% mysql_tzinfo_to_sql /usr/share/zoneinfo/
      # タイムゾーンを日本時間にする設定ファイルを新規作成(conf.dディレクトリの配下であればファイル名は何でもOK)
      DBコンテナ% echo "" >> /etc/mysql/conf.d/etc-mysql.cnf
      DBコンテナ% sed -i -e "1i [mysqld]\n    default-time-zone='Asia/Tokyo'" /etc/mysql/conf.d/etc-mysql.cnf
      
      DBコンテナ% exit
      # DBコンテナの再起動(MySQL単体の再起動ができないので)
      ホストOS% docker restart <作成したDBコンテナ名>
      
    2. MySQLのタイムゾーンが日本時間になっているか確認する

    MySQLのタイムゾーンが日本時間になっているか確認する

    1. 以下のコマンドを実行する

      # DBコンテナに入る
      ホストOS% docker exec -it <作成したDBコンテナ名> bash
      # MySQLにログイン
      DBコンテナ% mysql -u root -p
      Enter password: root
      # タイムゾーン確認
      mysql> SHOW VARIABLES LIKE '%time_zone%';
      # 実際に日本の現在時刻と一致しているか確認
      mysql> SELECT NOW();
      

    おわりに

    • コロナのせいで、せっかくの連休なのに外出自粛というのはツラいですが、耐えましょう。。。

    参考

2
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?