Site cover image

fhhm’s blog

🌀golang-migrateをDocker上で実行する

golang-migrateをDocker上で実行するための備忘録。

背景

公式チュートリアルやQiita、Zennなどの記事では、ローカルマシンにインストールしたgolang-migrateを使う方法について書かれているものが多かった。CIや本番デプロイを考えるとDocker内で実行できた方が楽じゃない?と思ったのがきっかけ。

ℹ️
Goはあまり触ったことがないし、業務で使ったこともないので、Dockerから実行するのは邪道な可能性はある😇

やってみた

マイグレーションファイル作成

migrate create -ext sql -dir migrations {description}.up.sql.down.sqlを生成する。生成されたファイルは空なので、CREATE TABLEをテキトーに書いて保存する。

docker-compose.yml

docker-compose.ymldbmigrateサービスを定義する。

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:

migratecommandにはマイグレーション実行コマンドを定義することで、コンテナ起動時にマイグレーションを行うようにしている。ただ、これだけだと、docker compose up をしたときに毎回マイグレーションが実行されてしまう。毎回実行されて困ることは多くないとは思うが、個人的には手動で実行できた方が嬉しいので、profiles: ["manual"] を指定した。これによって、手動でのみコンテナが起動(i.e. マイグレーションが実行)されるようにしている。

実行

dbコンテナが起動している状態で、docker compose run --rm migrateを実行すると、マイグレーションが実行される。

Image in a image block

up以外のコマンド実行

docker-compose.ymlupコマンドを定義しているため、普通に起動するとversionforceなどのコマンドが実行できない。また、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でも、それを使えばいいだけなので、使い道はなかったかも…