ISUCON9 予選問題用のMySQLをDockerで立てる
これはなに
isucon.net ISUCON9予選問題の環境構築をするために上記の公式記事を参考にぽちぽちやっていた最中、 mysqlサーバーをホストに立てるのが環境を汚しそうで嫌だったので、Dockerで立ててみることにしました。
職場でdocker-compose up
くらいはするものの、ちゃんと自分でDockerで何かを構築するのは初めてだったので
いろいろ調べながらとりあえず課題のWebアプリが普通に動く最低ラインを目指してやったことの作業ログです。
環境
MacOS Catalina MacBook Pro 2017 3.1GHz デュアルコアIntel Corei5 メモリ 16GB
手順
CLIから起動
docker run
で、imageからcontainerを起動する。
imageはdocker hubからダウンロードしてくる。
$ docker run --name cli-mysql -e MYSQL_ROOT_PASSWORD=pass -d mysql:latest
ref. mysql - Docker Hub
Starting a MySQL instance is simple:
bash $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
... where some-mysql is the name you want to assign to your container, my-secret-pw is the password to be set for the MySQL root user and tag is the tag specifying the MySQL version you want. See the list above for relevant tags.
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9e3b15e64c77 mysql:latest "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 3306/tcp, 33060/tcp cli-mysql
起動はしており、3306と33060でmysqldの待ち受けはしているが、portのバインドができていないのでローカルからの接続はできない。
docker run --name cli-mysql -e MYSQL_ROOT_PASSWORD=pass -p 3306:3306 -d mysql:latest
--publish , -p : Publish a container’s port(s) to the host
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9e3b15e64c77 mysql:latest "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp cli-mysql
公開されたようだ。接続してみる。
$ mysql --port=3306 --host=127.0.0.1 --user=root -p Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.19 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
OK!
DockerfileからImageを作って起動
docker build PATH | URL
でimageを自作する。
PATH(a directory on your local filesystem)やURL(Git repository location)はcontextと呼ばれる。
docker build
は、Docker deamonにcontext内のファイル(.dockerignoreで指定されたファイルは除く)を送信し、contextルートに配置されたDockerfile
の手順にしたがって、Docker deamon内でimageをbuildする。(そのため、buildに必要のないファイルはきちんと.dockerignoreで指定しておいた方がbuildの速度は早くなる)
Docker deamonは、Dockerfileに記載された命令文を1つずつ独立した状態で実行しながら新しいimageを都度作っていき、最終的に得られたimageを出力する。 DockerfileのCOPY命令などでcontext内のファイルを参照しつつbuildを行う。
FROM mysql:latest ENV MYSQL_ROOT_PASSWORD=pass
$ docker build . Successfully built 855977a52a9d $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 855977a52a9d 7 seconds ago 547MB $ docker run --name file-mysql -p 3306:3306 -d 855977a52a9d # -eオプションの指定が消えた $ mysql --port=3306 --host=127.0.0.1 --user=root -p
imageのREPOSITORY, TAGの指定は docker build -t ${REPOSITORY}:${TAG}
で行う。Dorckerfileに記述するものではない。
$ docker build -t moeka-m/mysql:latest . $ docker images EPOSITORY TAG IMAGE ID CREATED SIZE moeka-m/mysql latest 855977a52a9d 16 hours ago 547MB
初期データを自動で読み込むように設定
Initializing a fresh instance
When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh, .sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data. SQL files will be imported by default to the database specified by the MYSQL_DATABASE variable.
ref. mysql - Docker Hub
containerを起動させると、/docker-entrypoint-initdb.d
に配置された.sh
,.sql
,.sql.gz
をアルファベット順に実行してDababaseを初期化しますよ、の意。
FROM mysql:latest ENV MYSQL_ROOT_PASSWORD pass # 文字コードの指定がないとinitial.sqlの実行で Data too long for column と言われて失敗する ENV LANG C.UTF-8 COPY . /docker-entrypoint-initdb.d
データの初期投入をするshellは要らなくなったので.dockerignore
に書いておく
init.sh
これで実行してみる。
$ docker build -t moeka-m/mysql:latest . $ docker run --name file-mysql -p 3306:3306 -d moeka-m/mysql:latest $ mysql --port=3306 --host=127.0.0.1 --user=isucari -p mysql > SHOW TABLES FROM isucari; +-----------------------+ | Tables_in_isucari | +-----------------------+ | categories | | configs | | items | | shippings | | transaction_evidences | | users | +-----------------------+ 6 rows in set (0.02 sec) mysql> SELECT id, name, price FROM isucari.items LIMIT 1; +----+---------------------------------------------------------------------------------------------------------------------+-------+ | id | name | price | +----+---------------------------------------------------------------------------------------------------------------------+-------+ | 1 | 浮くことなく世界中の4段階採用したっぷり入れロースタイルをスタッキング曲げ木の | 100 | +----+---------------------------------------------------------------------------------------------------------------------+-------+ 1 row in set (0.00 sec)
Webappから接続
Hostの環境変数に接続情報を入れておく
$ export MYSQL_HOST=127.0.0.1 $ export MYSQL_PORT=3306 $ export MYSQL_USER=isucari $ export MYSQL_DBNAME=isucari $ export MYSQL_PWD=isucari
あとは冒頭リンクの記事通りにWebアプリを起動すると無事に起動!
後記
ちなみにこの状態でベンチマーカーを起動させると
2020/03/28 21:59:01 main.go:180: === final check === 2020/03/28 21:59:01 main.go:212: 410 0 {"pass":true,"score":410,"campaign":0,"language":"Go","messages":[]}
これくらいのスコアになりました。 公式記事では初期スコアでも3020くらいいってたのでだいぶ遅いです。やっぱdockerで立てると遅くなるのかも。