日頃の行い

個人的な日頃の行いをつらつら書いてます\\\\ ٩( 'ω' )و ////

docker-composeでmysqlにmigrationかけたい時にconnection refusedで失敗したときの対応

開発環境にdocker-composeを使っていて、
テーブルスキーママイグレーションをしようとしたらconnection refusedと言われて困った時の対処法です。
結論はマイグレーションをかける側はmysqlが立ち上がるまで待ちましょうという感じです。
(素のSQLでDBがmysqlなら /docker-entrypoint-migrations.dSQLを置くでもいいですね。

https://hub.docker.com/r/mathewhall/mysql_migration/

困っていた時に人づてに聞いてこのページにたどり着きました。
そこで wait-for とか使いましょうという空気感を受け取りました。

docs.docker.com

github.com

成功する場合と失敗する場合を検証してみました。
検証に使ったコードはこのレポジトリにおいてあります。
成功するパターンと失敗するパターンはそれぞれ make successmake fail で試せます。

github.com

失敗するパターンがこちら

app_1 | 2017/08/16 11:08:24 error: dial tcp 172.26.0.2:3306: getsockopt: connection refused

と出てしまってマイグレーションが走っていません。

$make fail
/Applications/Xcode.app/Contents/Developer/usr/bin/make docker/start conf=fail.yml
/usr/local/bin/docker-compose -f fail.yml build
db uses an image, skipping
Building app
... # 中略

app_1  | mv tmp/migrate.linux-amd64 bin/migrate
app_1  | make[1]: Leaving directory '/opt/app'
app_1  | make migrate/up
app_1  | make[1]: Entering directory '/opt/app'
app_1  | bin/migrate -path ./migrations -database 'mysql://root:root@tcp(db.local:3306)/test?x-migrations-table=migrate_schema_versions' -verbose up
db_1   | 2017-08-16 20:08:24 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
db_1   | 2017-08-16 20:08:24 0 [Note] mysqld (mysqld 5.6.36) starting as process 1 ...
app_1  | 2017/08/16 11:08:24 error: dial tcp 172.26.0.2:3306: getsockopt: connection refused
app_1  | Makefile:51: recipe for target 'migrate/up' failed
app_1  | make[1]: *** [migrate/up] Error 1
app_1  | make[1]: Leaving directory '/opt/app'
app_1  | Makefile:17: recipe for target 'start/fail' failed
app_1  | make: *** [start/fail] Error 2
app_1  | make: Leaving directory '/opt/app'
waitforondockercomposesample_app_1 exited with code 2

成功するパターンがこちら
繋がるまで待って、繋がったらマイグレーションを走らせてくれています。
便利。

app_1 | bin/migrate -path ./migrations -database 'mysql://root:root@tcp(db.local:3306)/test?x-migrations-table=migrate_schema_versions' -verbose up
app_1 | 2017/08/16 11:12:55 Start buffering 1/u AddHogeTable
app_1 | 2017/08/16 11:12:55 Read and execute 1/u AddHogeTable
app_1 | 2017/08/16 11:12:56 Finished 1/u AddHogeTable (read 71.110899ms, ran 227.120362ms)
app_1 | 2017/08/16 11:12:56 Finished after 303.666771ms
app_1 | 2017/08/16 11:12:56 Closing source and database

$make success
/Applications/Xcode.app/Contents/Developer/usr/bin/make docker/start conf=success.yml
/usr/local/bin/docker-compose -f success.yml build
db uses an image, skipping
Building app
... # 中略

app_1  | mv tmp/migrate.linux-amd64 bin/migrate
app_1  | make[1]: Leaving directory '/opt/app'
app_1  | /opt/wait-for db:3306 -- make migrate/up
db_1   | Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
db_1   | Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
db_1   | Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
db_1   | Warning: Using a password on the command line interface can be insecure.
db_1   |
db_1   |
db_1   | MySQL init process done. Ready for start up.
db_1   |
db_1   | 2017-08-16 20:12:54 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
db_1   | 2017-08-16 20:12:54 0 [Note] mysqld (mysqld 5.6.36) starting as process 1 ...
app_1  | make[1]: Entering directory '/opt/app'
app_1  | bin/migrate -path ./migrations -database 'mysql://root:root@tcp(db.local:3306)/test?x-migrations-table=migrate_schema_versions' -verbose up
app_1  | 2017/08/16 11:12:55 Start buffering 1/u AddHogeTable
app_1  | 2017/08/16 11:12:55 Read and execute 1/u AddHogeTable
app_1  | 2017/08/16 11:12:56 Finished 1/u AddHogeTable (read 71.110899ms, ran 227.120362ms)
app_1  | 2017/08/16 11:12:56 Finished after 303.666771ms
app_1  | 2017/08/16 11:12:56 Closing source and database
app_1  | make[1]: Leaving directory '/opt/app'
app_1  | bash
app_1  | make: Leaving directory '/opt/app'
waitforondockercomposesample_app_1 exited with code 0

docker-composeで他のコンテナのサービスに対して何かやりたい場合は、
立ち上がりきるまでちゃんと待ってあげないといけないみたいですね。
コンテナ内のサービスが立ち上がるまで待ってくれる便利コマンドを知れてよかったです。
めでたしめでたし。