Dockerfile
# サンプルは14.04ベースだったので16.04にしてみた
FROM ubuntu:16.04
# versionをあとで変更しやすいように
ENV MYSQLVER 5.7.20
ENV DEBIAN_FRONTEND=noninteractive
# 日本のミラーサイトのほうが早いのと、build-dep用にdeb-srcの有効化
RUN sed -i \
-e "s/archive.ubuntu.com/jp.archive.ubuntu.com/g" \
-e "s/# deb-src/deb-src/g" \
/etc/apt/sources.list
RUN apt update
RUN apt build-dep -y mysql-server
RUN apt install -y wget curl gdbserver
# mysqlのソース取得
WORKDIR /usr/src
RUN wget "http://ftp.jaist.ac.jp/pub/mysql/Downloads/MySQL-5.7/mysql-boost-${MYSQLVER}.tar.gz"
RUN tar xzf mysql-boost-${MYSQLVER}.tar.gz
# mysqlのソースをdebug付きでビルド
WORKDIR /usr/src/mysql-${MYSQLVER}
RUN CFLAGS=-O0 cmake \
-DWITH_PIC=1 \
-DWITH_DEBUG=1 \
-DWITH_INNODB_EXTRA_DEBUG=1 \
-DCMAKE_INSTALL_PREFIX="/opt/mysql57" \
-DDOWNLOAD_BOOST=1 \
-DWITH_BOOST=./boost
RUN make -j$(getconf _NPROCESSORS_ONLN) install
# my.cnf何かあったほうが良いので、ひな型からコピーしたが、エラー回避用に追加
RUN cp ./packaging/rpm-docker/my.cnf /etc/my.cnf
## 面倒なのでrootで実行します!
RUN sed -i -e "s/user=mysql/user=root/" /etc/my.cnf
RUN echo "explicit_defaults_for_timestamp=true" >> /etc/my.cnf
RUN echo "skip-name-resolve" >> /etc/my.cnf
# mysqld起動用のディレクトリがいくつかないので作成
RUN mkdir /var/lib/mysql-files
RUN mkdir /var/run/mysqld
# mysqldの初期化
RUN /opt/mysql57/bin/mysqld --initialize
EXPOSE 3306
EXPOSE 2345
VOLUME /usr/src
# skip-grant-tablesは、mysql側のアカウント作成の手間を省きたかったため。
CMD gdbserver :2345 /opt/mysql57/bin/mysqld --skip-grant-tables
dockerを動かすホスト
今回は ubuntu17.10 で動かした。
apt install -y docker.io
# vi /etc/group にて現在のユーザーをdockerグループに追加。
# 一度ログアウト、ログインしてdockerグループに属していることを確認。
# mysqlコマンドが必要。もしなければ以下で入れておく。
apt install -y mysql-client
wget "http://ftp.jaist.ac.jp/pub/mysql/Downloads/MySQL-5.7/mysql-5.7.20.tar.gz"
mkdir src
cd src
tar xzf mysql-5.7.20.tar.gz
docker run \
--rm \
-v $(pwd)/src/mysql-5.7.20:/usr/src/mysql-5.7.20 \
-v /etc/localtime:/etc/localtime \
-p 3306:3306 \
-p 2345:2345 \
-t --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
mysql-debug-5.7 \
sh -c "
cp /opt/mysql57/bin/mysqld /usr/src/mysql-5.7.20/;
gdbserver :2345 /opt/mysql57/bin/mysqld --skip-grant-tables
"
cp しているのは、ローカルにコピーしたほうが時間の短縮になるため。
# --cap-add=SYS_PTRACE --security-opt seccomp=unconfined をつけなかった場合、以下エラーになる
(gdb) run
Starting program: /usr/local/src/mysql-4.0.30/sql/./gen_lex_hash
warning: Error disabling address space randomization: Operation not permitted
Cannot create process: Operation not permitted
During startup program exited with code 127.
$ gdb
...
(gdb) file ./src/mysql-5.7.20/mysqld
# リモートに接続。上で fileを実行していなければ /opt/mysql57/bin/mysqld が読み込まれます。
(gdb) target remote :2345
Remote debugging using :2345
Reading /opt/mysql57/bin/mysqld from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /opt/mysql57/bin/mysqld from remote target...
Reading symbols from target:/opt/mysql57/bin/mysqld...done.
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
Reading symbols from target:/lib64/ld-linux-x86-64.so.2...Reading /lib64/ld-2.23.so from remote target...
Reading /lib64/.debug/ld-2.23.so from remote target...
(no debugging symbols found)...done.
0x00007ffff7dd7c30 in ?? () from target:/lib64/ld-linux-x86-64.so.2
# ローカルとリモートのPATHマッピング http://d.hatena.ne.jp/syasuda/20071208/1197116413
(gdb) set substitute-path /opt/mysql57/ ./src/mysql-5.7.20/
# ブレークポイントを指定
(gdb) b mysql_alter_table
# remoteでmysqldの起動
(gdb) c
/usr/bin/mysql -uroot -h 127.0.0.1
create database test;
use test;
create table test(id int);
alter table test add column no int;
alter table test add column no int;
を投入したところ、通常は以下出力となるが
mysql> alter table test add column no int;
Query OK, 0 rows affected (2 min 10.28 sec)
Records: 0 Duplicates: 0 Warnings: 0
以下で止まることを確認。
(gdb) bt
でソースファイル名と行番号が出力される。
(gdb) c
で停止された処理を続行。
ハマリポイント
mysql5.6以降を触っていなかったためmysqlの設定自体でハマった。
TIMESTAMP with implicit DEFAULT value is deprecated
[Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
- MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.1.4 サーバーシステム変数
- explicit_defaults_for_timestamp という WARNING | katz+
これから作るTIMESTAMPは「明示的に NOT NULL 指定」をしない限り「NOT NULL」じゃなくなる。
よってTIMESTAMPについて何も指定していなかったSQLで新しいテーブルに書き込むと現在時刻は自動的に入らず、「NULL」が入ります!
[mysqld]
explicit_defaults_for_timestamp=true
secure-file-priv設定のエラー
mysqld: Error on realpath() on '/var/lib/mysql-files' (Error 2 - No such file or directory)
[ERROR] Failed to access directory for --secure-file-priv. Please make sure that directory exists and is accessible by MySQL Server. Supplied value : /var/lib/mysql-files
- デフォルト値が mysql 5.7.6 で変更になった様子。 MySQL :: MySQL 5.7 Reference Manual :: 5.1.5 Server System Variables
- 日本語マニュアルは5.6止まりで、5.7.6の情報はなかった。
ディレクトリの名前に設定すると、LOAD_FILE() 関数と、LOAD DATA および SELECT ... INTO OUTFILE ステートメントの効果を制限し、そのディレクトリ内のファイルにのみ機能します。
mkdir /var/lib/mysql-files
--initialize
- MySQL :: MySQL 5.7 Reference Manual :: 4.4.2 mysql_install_db — Initialize MySQL Data Directory
- mysql5.7.6から
mysql_install_db
ではなくmysql --initialize
に変更になった。
--skip-name-resolve つけないと大量のWARNING
/var/run/mysqld がない
mkdir /var/run/mysqld
./src/mysql-5.7.20/data/がない
mkdir ./src/mysql-5.7.20/data/
接続できない
$ /usr/bin/mysql -uroot -h 127.0.0.1
ERROR 1130 (HY000): Host '172.17.0.1' is not allowed to connect to this MySQL server
--skip-grant-tables
オプションが必要だった。