MySQL on Docker with UTF-8 CHARSET

2016年3月7日 at 2:02 PM 2件のコメント

ちょっとした自分用メモです。
以前、デモで MySQL の Docker コンテナを作成した際、オフィシャルの Docker イメージを利用した場合、たとえ、下記を /etc/mysql/conf.d/charset.cnf に指定しても作成した DB のテーブルが latin1 になってしまう問題にあいました。

     [mysqld]'; 
      skip-character-set-client-handshake
      character-set-server=utf8
      collation-server=utf8_general_ci
      init-connect = SET NAMES utf8
      [client]
      default-character-set=utf8

そこで、docker-entrypoint.sh を追記して、DB 作成時に明示的に utf8 を渡すように変更しました。
(docker-entrypoint.sh の追記箇所)

# 前略
# 引数で書く所をファイル中に記載
DATADIR="/var/lib/mysql"
MYSQL_ROOT_PASSWORD="supersecret"
MYSQL_DATABASE="artist-db"
MYSQL_USER="mysql"
MYSQL_PASSWORD="mysql"
MYSQL_CHARSET="utf8"

# 中略 
                if [ "$MYSQL_DATABASE" ]; then
                        echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ${MYSQL_CHARSET:+CHARACTER SET $MYSQL_CHARSET} ;" >> "$tempSqlFile"
                fi
# 後略

これで、Docker コンテナの MySQL で UTF-8 を扱えるようになるかと思います。

MySQL 用の Dockerfile

FROM mysql:5.7

RUN { \
      echo '[mysqld]'; \
      echo 'skip-character-set-client-handshake'; \
      echo 'character-set-server=utf8'; \
      echo 'collation-server=utf8_general_ci'; \
      echo 'init-connect = SET NAMES utf8'; \
      echo '[client]'; \
      echo 'default-character-set=utf8'; \
    } > /etc/mysql/conf.d/charset.cnf

COPY ./docker-entrypoint.sh /tmp/entrypoint.sh
COPY ./start-up.sh /tmp/start-up.sh
RUN chmod a+x /tmp/entrypoint.sh
RUN chmod a+x /tmp/start-up.sh

ENTRYPOINT ["/tmp/start-up.sh"]
EXPOSE 3306
CMD ["mysqld"]

DB を作成するためのスクリプトファイル(docker-entrypoint.sh)

#!/bin/bash
set -e

# if command starts with an option, prepend mysqld
if [ "${1:0:1}" = '-' ]; then
        set -- mysqld "$@"
fi
# 引数で書く所をファイル中に記載
DATADIR="/var/lib/mysql"
MYSQL_ROOT_PASSWORD="supersecret"
MYSQL_DATABASE="artist-db"
MYSQL_USER="mysql"
MYSQL_PASSWORD="mysql"
MYSQL_CHARSET="utf8"

if [ "$1" = 'mysqld' ]; then
        # read DATADIR from the MySQL config
        DATADIR="$("$@" --verbose --help 2>/dev/null | awk '$1 == "datadir" { print $2; exit }')"
        if [ ! -d "$DATADIR/mysql" ]; then
                if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" ]; then
                        echo >&2 'error: database is uninitialized and MYSQL_ROOT_PASSWORD not set'
                        echo >&2 '  Did you forget to add -e MYSQL_ROOT_PASSWORD=... ?'
                        exit 1
                fi
                
                echo 'Initializing database'
                mysqld --initialize-insecure=on --datadir="$DATADIR"
                echo 'Database initialized'
                
                # These statements _must_ be on individual lines, and _must_ end with
                # semicolons (no line breaks or comments are permitted).
                # TODO proper SQL escaping on ALL the things D:
                
                tempSqlFile='/tmp/mysql-first-time.sql'
                cat > "$tempSqlFile" <<-EOSQL
                        -- What's done in this file shouldn't be replicated
                        --  or products like mysql-fabric won't work
                        SET @@SESSION.SQL_LOG_BIN=0;
                        
                        DELETE FROM mysql.user ;
                        CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
                        GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ;
                        DROP DATABASE IF EXISTS test ;
                EOSQL
                
                if [ "$MYSQL_DATABASE" ]; then
                        echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ${MYSQL_CHARSET:+CHARACTER SET $MYSQL_CHARSET} ;" >> "$tempSqlFile"
                fi
                
                if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
                        echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" >> "$tempSqlFile"
                        
                        if [ "$MYSQL_DATABASE" ]; then
                                echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" >> "$tempSqlFile"
                        fi
                fi
                
                echo 'FLUSH PRIVILEGES ;' >> "$tempSqlFile"
                
                set -- "$@" --init-file="$tempSqlFile"
        fi
        
        chown -R mysql:mysql "$DATADIR"
fi

exec "$@"

MySQL の起動用スクリプト(start-up.sh)

#!/usr/bin/env bash
/tmp/entrypoint.sh mysqld --datadir=/var/lib/mysql --user=mysql 

ファイルを作成したのち、Dockerfile を保存している場所で下記のコマンドを実行して Docker イメージを作成

$ docker build -t tyoshio2002/mysql:5.7 .

作成した Docker イメージを起動

$ docker run -d -p 3306:3306 tyoshio2002/mysql:5.7

で MySQL を起動できるかと思います。

※ オフィシャルのイメージに対して、文字コードを指定できるようにしてほしいというリクエストが多数上がっているので、オフィシャル側で対応してほしいですね。他に良い方法をご存知の方がいらっしゃったら教えてください。

広告

Entry filed under: Microsoft Azure. Tags: , , .

Java on Microsoft Azure 情報のまとめ記事 Java サーバの使用状況のアンケートのお願い

2件のコメント

  • 1. Shinichi Akiyama (@shakiyam)  |  2016年3月7日 10:01 PM

    https://hub.docker.com/_/mysql/ の Using a custom MySQL configuration file に記述にあるように、自分で書いた設定ファイルをマウントしてあげれば簡単にできますよ。

    • 2. Yoshio Terada  |  2016年3月8日 10:50 AM

      そうなんですね、ありがとうございます。
      自分がやった時は作成された DB だけが latin1 になっていたので、作成時も明示し回避しました。


Java Champion & Evangelist

ご注意

このエントリは個人の見解であり、所属する会社の公式見解ではありません

カレンダー

2016年3月
« 1月   4月 »
 123456
78910111213
14151617181920
21222324252627
28293031  

カテゴリー

Twitter

clustermap

ブログ統計情報

  • 933,001 hits

Feeds


%d人のブロガーが「いいね」をつけました。