👻

ent. と atlasを用いたバージョン管理型マイグレーションのやり方

2024/07/20に公開

1. はじめに

GolangでORMを使うなら ent. がおすすめ!の記事で、ent.の紹介をした続きになります。
前回は、atlasを利用したバージョン管理型マイグレーションのやり方を説明せずに省いたので、今回はその紹介になります。
atlasについての説明やスキーマの可視化については、ent. と atlas を利用したスキーマの可視化で説明しているので、よければ読んでみて下さい!

2. 開発環境

以下に、筆者の開発環境と本記事で利用するリポジトリを記載します。

  • golang v1.21.4
  • docker 4.16.2
  • postgresql 16.1
  • ent. v0.12.5
  • atlas v0.15.1-04e0010-canary

https://github.com/KaiTakabe0301/entdemo_versioned

3. atlasを利用したマイグレーションのバージョン管理

今回は、ent.のQuick Introductionの内容に対して、マイグレーションのバージョン管理を行おうと思います!
以前の記事で、ent.についてはある程度説明しているので、冗長な箇所はサクッと説明していきます。

3-1. atlasのインストール

まずは、atlasのインストールしましょう。
私は以下のようにbrewを利用してインストールしました。

$ brew install ariga/tap/atlas

brew以外の方法でインストールしたい方は、installationを参照して下さい。

インストールが完了したら、以下のようにコマンドが動作するか確認しておきましょう。

$ atlas -h

正常にインストールが完了していると、以下のように出力されます。
沢山コマンドがありますが、主に利用するのはmigrateコマンドになります。

A database toolkit.

Usage:
  atlas [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  help        Help about any command
  license     Display license information
  login       Log in to Atlas Cloud.
  logout      Logout from Atlas Cloud.
  migrate     Manage versioned migration files
  schema      Work with atlas schemas.
  version     Prints this Atlas CLI version information.

Flags:
  -h, --help   help for atlas

Use "atlas [command] --help" for more information about a command.

3-2. Userスキーマの作成

以下の順序で、Userスキーマを作成します。

今回の学習用のディレクトリを作成し、Userスキーマを作成します。

$ mkdir entdemo_versioned

$ cd entdemo_versioned

$ go mod init entdemo

$ go run -mod=mod entgo.io/ent/cmd/ent new User

生成されたuser.goに、以下の内容を記述します。

entdemo_versioned/ent/schema/user.go
package schema

import (
	"entgo.io/ent"
	"entgo.io/ent/schema/field"
)

// User holds the schema definition for the User entity.
type User struct {
	ent.Schema
}

// Fields of the User.
func (User) Fields() []ent.Field {
	return []ent.Field{
		field.Int("age").
			Positive(),
		field.String("name").
			Default("unknown"),
	}
}

// Edges of the User.
func (User) Edges() []ent.Edge {
	return nil
}

3-3. データベースの準備

スキーマからテーブルを作成するためのDBを準備します。
DBはdocker-composeで準備するので、以下のようにdocker-compose.ymlを作成します。

touch docker-compose.yml
docker-compose.yml
version: "3.8"

services:
  postgres_versioned:
    image: postgres:16.1-alpine
    container_name: postgres_versioned
    environment:
      POSTGRES_DB: entdemo
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
    volumes:
      - ./data/db_data/volume:/var/lib/postgresql/data

準備ができたら、コンテナを起動させます。

docker-compose up -d

3-4. マイグレーション

atlasを用いたバージョン管理型のマイグレーションには方法が2つありますが、公式でお勧めされている手法を試したいと思います。

3-4-1. atlas migrate diffを用いた方法

ターミナルから、atlasを用いてマイグレーションファイルを生成する方法です。

3-4-1-1. マイグレーションファイルの作成

まず、以下のコマンドを実行します。

$ atlas migrate diff add_user_schema \
  --dir "file://ent/migrate/migrations" \
  --to "ent://ent/schema" \            
  --dev-url "docker://postgres/16/test?search_path=public"

正常に実行されると、以下の2つのファイルがent/migrate/migrations/の中に生成されます。

  1. {timestamp}_{diffコマンドで指定した名前}.sql
    • マイグレーションを行うファイルです。今回、私の環境では20240212102205_add_user_schema.sqlという名前でした。
  2. atlas.sum
    • マイグレーションディレクトリの完全性を保証するファイルです。
    • マイグレーションの順序や内容が後から変更された場合に、開発者が対処するために利用されます。

3-4-1-2. マイグレーションが完了していないことを確認する

現時点では、マイグレーションは実行されていません。
これを確認するために、atlas migrate statusを実行して確認してみましょう。

$ atlas migrate status \
  --dir "file://ent/migrate/migrations" \
  --url "postgres://postgres:password@localhost:5432/entdemo_versioned?search_path=public&sslmode=disable"

このコマンドから、以下のことがわかります。

  • Migration StatusがPENDINGなので、実行されていないマイグレーションファイルがあることがわかります。
  • Current Versionから、まだ一度もマイグレーションが実行されていないことが確認できます。
  • Next Versionから、次に実行される予定のマイグレーションを確認することができます。
  • Executed Filesから、過去に実行されたマイグレーションファイルの数がわかります。現時点では、何も実行されていないので0です。
  • Pending Filesから、待機中のマイグレーションファイルの数がわかります。今回は20240212102205_add_user_schema.sqlが控えているので、数が1になっています。
Migration Status: PENDING
  -- Current Version: No migration applied yet
  -- Next Version:    20240212102205
  -- Executed Files:  0
  -- Pending Files:   1

3-4-1-3. マイグレーションの実行

それでは、migrationを実行してみましょう。

$ atlas migrate apply \
  --dir "file://ent/migrate/migrations" \
  --url "postgres://postgres:password@localhost:5432/entdemo_versioned?search_path=public&sslmode=disable"

マイグレーションが完了すると、以下のように出力されます。

Migrating to version 20240212102205 (1 migrations in total):

  -- migrating version 20240212102205
    -> CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "age" bigint NOT NULL, "name" character varying NOT NULL DEFAULT 'unknown', PRIMARY KEY ("id"));
  -- ok (16.220259ms)

  -------------------------
  -- 96.437614ms
  -- 1 migrations
  -- 1 sql statements

3-4-1-4. マイグレーションの完了を確認

もう一度、マイグレーションのステータスを確認してみましょう。

$ atlas migrate status \
  --dir "file://ent/migrate/migrations" \
  --url "postgres://postgres:password@localhost:5432/entdemo_versioned?search_path=public&sslmode=disable"

以下のようにステータスが更新されていることがわかります。
これで、無事にマイグレーションが完了しました!

Migration Status: OK
  -- Current Version: 20240212102205
  -- Next Version:    Already at latest version
  -- Executed Files:  1
  -- Pending Files:   0

3-5. マイグレーションのdown

4章のatlas cloudとの連携を行う前に、適応したマイグレーションをdownしておきましょう。
downには、以下のようにatlas migrate donwコマンドを利用します。

$ atlas migrate down \
  --dir "file://ent/migrate/migrations" \
  --url "postgres://postgres:password@localhost:5432/entdemo_versioned?search_path=public&sslmode=disable" \
  --dev-url "docker://postgres/16/dev?search_path=public" \

ちなみに、--dry-runオプションを付与すると、実際にdonwは実行されず、以下のように処理の内容を確認することができます。

Migrating down from version 20240212102205 (1 migration in total):

  -- checks before reverting version 20240212102205
    -> SELECT NOT EXISTS (SELECT 1 FROM "users") AS "is_empty"
  -- ok (2.683552ms)

  -- reverting version 20240212102205
    -> DROP TABLE "users"
  -- ok (2.686391ms)

  -------------------------
  -- 2.688966ms
  -- 1 migration
  -- 1 sql statement

4. atlas cloudとの連携

最後に、atlas cloudと連携してみましょう!
ここでは、atlas cloudのopenプラン以上のアカウントを持っている前提で話を進めます。

4-1. atlas cloudにmigration ディレクトリをプッシュ

まず、atlas cli上でログインします。

$ atlas login <アカウント名>

次に、ent/migrate/にcdします。

$ cd ent/migrate

最後に、ent/migrate/ で、atlas migrate pushコマンドを用いて、migrations/の内容をpushします。

$ atlas migrate push entdemo --dev-url "docker://postgres/15/dev?search_path=public"

無事にpushが完了すると、以下のようにatlas cloud上にentdemoの内容が表示されます。

4-2. atlas.hclを用いたマイグレーション

今回はatlas.hclを用いて、atlas cloudと連携しながらマイグレーションを行おうと思うので、以下の内容でatlas.hclを作成します。

ent/migrate/atlas.hcl
env "local" {
  url = "postgres://postgres:password@localhost:5432/entdemo_versioned?search_path=public&sslmode=disable"
  migration {
    dir = "atlas://entdemo"
  }
}

あとは、以下のコマンドでmigrationを実行して下さい。

$ atlas migrate apply --env local

正常にマイグレーションが実行されると、以下のように出力されます。

Migrating to version 20240212102205 (1 migrations in total):

  -- migrating version 20240212102205
    -> CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "age" bigint NOT NULL, "name" character varying NOT NULL DEFAULT 'unknown', PRIMARY KEY ("id"));
  -- ok (35.192543ms)

  -------------------------
  -- 103.639911ms
  -- 1 migration
  -- 1 sql statement
https://<あなたのアカウント名>.atlasgo.cloud/deployments/<一意の数値>

atlas cloudとの連携も確認してみましょう。
まず、Migrationsタブには、以下のように実行された内容が記録されていきます。

そして、Databasesのタブには、スキーマごとにMigrationの情報が記録されていきます。

5.Github Actionsとatlas cloudの連携

最後に、簡単なworkflowを作成して、Github Actionsとatlas cloudを連携してみましょう!

5-1.Github Actionsの準備

まず、Set Up CIの案内に従って、以下のようにTokenを作成します。

後は表示されている手順に従って、Github CLIを操作するだけです。

atlasの拡張機能をインストールして

gh extension install ariga/gh-atlas

必要な権限スコープを持つ新しい認証トークンを取得し

$ gh auth refresh -s write:packages,workflow

Github actionsのworkflowのPRを作成します。

$ gh atlas init-action --token <あなたのToken>

あとは、作成されたPRをmainブランチにマージするだけです。

5-2. Github Actionsの挙動を確認

それでは、Github Actionsの挙動を確認してみましょう。

まず、ent/schema/user.goにemailフィールドを追加して、マイグレーションファイルを作成します。

ent/schema/user.go
			Positive(),
		field.String("name").
			Default("unknown"),
+		field.String("email").
+			Default("unknown"),
	}
}
$ atlas migrate diff \
  --dir "file://ent/migrate/migrations" \
  --to "ent://ent/schema" \
  --dev-url "docker://postgres/16/test?search_path=public"

後は、これらの変更を含んだPRを作成します。

正常に、Github Actionsが動作すると、以下のようにCIが動作するので、問題がなかったらmainブランチにマージをしましょう!

5-3. atlas cloudのCI Runsの確認

atlas cloud上で、どのように表示されているか確認しておきましょう!
まず、今回のPRに関連して、色々とCIが実行されていることがわかります。

CIの内容を確認すると、以下のようにlintが実行され、どのフィールドが追加されたかが一目でわかるようになっています。

まとめ

長らく時間が空いてしまいましたが、今回はatlasを用いたバージョン管理型マイグレーションの紹介を行いました!
atlas + atlas cloudをCI/CDに組み込めば、マイグレーションの自動化も安全に実行できそうな気配を感じます!
現時点では、あまりドキュメントを読み込めていないので、今後も色々手探りで遊んでみながら便利な使い方などを見つけたら、また記事にしてみようと思います。
atlasやatlas cloudの便利な利用方法をご存じの方がいたら、是非コメント欄などで教えてもらえると嬉しいです!

Discussion