golang-migrateをシンプルに使う

目次

はじめに

アプリ開発を進めていると、必ずぶつかるのが「データベースのテーブル定義をどう管理するか」という問題です。最初は手作業で CREATE TABLE を流していても、チーム開発になった途端、「誰がどの順番で何を流したのか分からない」という状態に陥ります。

この記事では、シンプルで導入しやすいマイグレーションツール golang-migrate を、Docker 経由で使う方法を初学者向けに解説します。Go の知識は不要です。Docker が動く環境さえあれば誰でも試せます。

そもそもマイグレーションとは

マイグレーションとは、データベースのスキーマ(テーブルやカラムの構造)の変更履歴を、ファイルとしてバージョン管理する仕組みのことです。

たとえば「users テーブルに age カラムを追加する」という変更を SQL ファイルとして保存しておけば、別の開発者やステージング環境でも、同じ手順を再現できます。Git で管理されたファイルを順番に適用していくイメージです。

up と down の考え方

マイグレーションファイルは通常、適用用の up.sql と、巻き戻し用の down.sql の二本セットで作成します。「やり直したい」「一つ前の状態に戻したい」というときに down が使えるため、安全に試行錯誤できます。

golang-migrate の仕組み

golang-migrate は、指定したフォルダ内の SQL ファイルを順番に DB へ適用してくれるツールです。Go 製ですが、公式が Docker イメージを配布しているため、Go をインストールする必要はありません。

ポイントは、マイグレーション用コンテナを毎回使い捨てで起動し、同じ Docker ネットワーク上にある DB コンテナへ接続するという流れです。図にすると次のようになります。

Docker Network (sample-app_default) migrate コンテナ (使い捨て) SQL を流して終了 DB コンテナ (常駐) MySQL など SQL 適用 db/migrations/*.sql

migrate コンテナはローカルの SQL ファイルをマウントして読み込み、ネットワーク越しに DB コンテナへ接続して SQL を流します。実行が終わると --rm オプションにより自動で消えるため、ホスト環境を汚しません。

実際にやってみる

マイグレーションファイルを用意する

プロジェクト直下に db/migrations/ フォルダを作り、命名規則に従って up と down のファイルを置きます。先頭の連番がバージョン番号になります。

db/migrations/
├── 000001_create_users_table.up.sql
└── 000001_create_users_table.down.sql

中身は普通の SQL です。

-- 000001_create_users_table.up.sql
CREATE TABLE users (
  id     BIGINT AUTO_INCREMENT PRIMARY KEY,
  name   VARCHAR(255) NOT NULL,
  email  VARCHAR(255) NOT NULL UNIQUE
);
-- 000001_create_users_table.down.sql
DROP TABLE users;

DB コンテナを起動する

事前に docker compose で DB を立ち上げておきます。

docker compose up db -d
docker ps

docker ps の NAMES 列に表示される名前(例: sample-app-db-1)が、後ほど接続文字列で使うホスト名になります。同様に docker network ls_default が付くネットワーク名も控えておきます。

接続テスト

いきなり SQL を流すのではなく、まずは末尾を version にして接続確認だけ行います。

docker run --rm \
  --network sample-app_default \
  -v "$(pwd)/db/migrations:/migrations" \
  migrate/migrate \
  -path=/migrations/ \
  -database "mysql://appuser:apppass@tcp(sample-app-db-1:3306)/appdb" \
  version

error: no migration と表示されれば、接続には成功していて、まだ何も適用されていない正常な状態です。

マイグレーションを実行する

末尾を up に変えるだけで、未適用の SQL がすべて適用されます。

docker run --rm \
  --network sample-app_default \
  -v "$(pwd)/db/migrations:/migrations" \
  migrate/migrate \
  -path=/migrations/ \
  -database "mysql://appuser:apppass@tcp(sample-app-db-1:3306)/appdb" \
  up

適用後にもう一度 version を実行すると、現在のバージョン番号が返ってきます。一つ前に戻したい場合は末尾を down 1 にします。

まとめ

golang-migrate は、SQL ファイルと Docker さえあれば導入できる、非常にとっつきやすいマイグレーションツールです。覚えることは「up と down のファイルを書く」「使い捨てコンテナで適用する」の二つだけ。最初は version で接続確認、慣れてきたら updown を行き来して、安心して試行錯誤できる開発環境を整えていきましょう。

長いコマンドは Makefile やシェルスクリプトにまとめておくと、チーム内で共有しやすくなります。

目次