golang-migrateをDocker上で実行するための備忘録。
背景
公式チュートリアルやQiita、Zennなどの記事では、ローカルマシンにインストールしたgolang-migrateを使う方法について書かれているものが多かった。CIや本番デプロイを考えるとDocker内で実行できた方が楽じゃない?と思ったのがきっかけ。
やってみた
マイグレーションファイル作成
migrate create -ext sql -dir migrations {description} で.up.sqlと.down.sqlを生成する。生成されたファイルは空なので、CREATE TABLEをテキトーに書いて保存する。
docker-compose.yml
docker-compose.ymlにdbとmigrateサービスを定義する。
services:
db:
image: mysql:8.0
container_name: db
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: app_db
MYSQL_USER: user
MYSQL_PASSWORD: password
TZ: Asia/Tokyo
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 10
command: --default-authentication-plugin=mysql_native_password
migrate:
image: migrate/migrate:v4.17.0
container_name: migrate
profiles: ["manual"]
depends_on:
db:
condition: service_healthy
volumes:
- ./migrations:/migrations
entrypoint: ["migrate"]
command:
[
"-path=/migrations",
"-database=mysql://user:password@tcp(db:3306)/app_db?charset=utf8mb4&parseTime=true&loc=UTC",
"up",
]
volumes:
mysql_data:
migrateのcommandにはマイグレーション実行コマンドを定義することで、コンテナ起動時にマイグレーションを行うようにしている。ただ、これだけだと、docker compose up をしたときに毎回マイグレーションが実行されてしまう。毎回実行されて困ることは多くないとは思うが、個人的には手動で実行できた方が嬉しいので、profiles: ["manual"] を指定した。これによって、手動でのみコンテナが起動(i.e. マイグレーションが実行)されるようにしている。
実行
dbコンテナが起動している状態で、docker compose run --rm migrateを実行すると、マイグレーションが実行される。
up以外のコマンド実行
docker-compose.ymlにupコマンドを定義しているため、普通に起動するとversionやforceなどのコマンドが実行できない。また、docker compose run --rm migrate version などとすると、-pathや-database も上書きされて消えてしまうため、エラーとなってしまう。
up以外のコマンドを実行したいときは、
docker compose run --rm migrate \
-path=/migrations \
-database="mysql://user:password@tcp(db:3306)/app_db?charset=utf8mb4&parseTime=true&loc=UTC" \
versionとして、-pathなども指定してあげないといけない。
感想
CIや本番デプロイを考えるとDocker内で実行できた方が楽じゃない?と思ったのがきっかけ。
と冒頭に書いたけど、よく考えたらデプロイのパイプラインの中で、golang-migrateがインストールされている、ある環境から本番DBに向けて実行したり、インストール済みイメージがあるのであればCIでも、それを使えばいいだけなので、使い道はなかったかも…

