golang-migrateでDBマイグレーション
golang-migrateとは?
Go言語で作成されたDBマイグレーションツールで、GO言語のライブラリとしてだけではなく、CLIからも利用できます。そのためJavaで開発されているprismatixというサービスでも利用することができます。
JavaのマイグレーションツールにFlywayやliquibaseといったものがあります。その中でこのツールの特徴は、マイグレーションを定義しているファイルをGitHubやAWS S3などから直接参照することができることです。(もちろんローカルのファイルシステムにも対応しています) また対応しているデータベースエンジンも多く、MySQLやPostgreSQL以外にもMongoDBなどにも対応しているなど、様々な場面で使うことができるツールだと思います。
環境構築
今回は手軽に試すためにdocker上で、golang-migrateとPostgreSQLを動作させて検証していきます。
( golang-migrateの公式Docker image 1がありますが、セットアップが難しくないため今回は手動でインストールします。)
1. PostgreSQLのコンテナを起動
% docker run --rm -it -p 5432:5432 -e POSTGRES_PASSWORD=password \ --name postgres postgres
[Note]
- コンテナに名前をつけて起動します
- 引数の環境変数
POSTGRES_PASSWORD
にpostgres
ユーザのパスワードを設定します
2. golang-migrateをインストールするコンテナを起動
以降はこのコンテナの中で作業します。
% docker run --rm -it --link postgres:postgres ubuntu:18.04 bash
[Note]
--link
にPostgreSQLのコンテナ名を指定し、DBにコンテナ内から ホスト名postgres
でアクセスできるようにします
3. golang-migrateをインストール
$ apt-get update && apt-get upgrade -y $ apt-get install -y curl gnupg2 vim $ curl -L https://github.com/golang-migrate/migrate/releases/download/v4.11.0/migrate.linux-amd64.tar.gz | tar xvz $ mv ./migrate.linux-amd64 /usr/bin/migrate
[Note]
- 執筆時点の最新版 v4.11.0 にて以降の検証を行っています
4. 動作確認用のpostgres-clientをインストール
PostgreSQLの公式にインストール手順2がありますので、それに従ってPostgreSQLのクライアントをインストールします。
$ echo 'deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main' > /etc/apt/sources.list.d/pgdg.list $ curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - $ apt-get update $ apt-get install -y postgresql-client-12
使ってみよう
golang-migrateをインストールして、公式のPostgreSQLのチュートリアルをやっていきます。
1. example
データベースを作成
PostgreSQLにマイグレーションを行うための example
データベースを作成します。
$ createdb -h postgres -U postgres example
2. マイグレーションのテンプレートを作成
golang-migrate
を使ってマイグレーションファイルのテンプレートを生成します。今回は migrations/example1
ディレクトリに create_users_table
のファイル名で生成します。
$ migrate create -ext sql -dir migrations/example1 -seq create_users_table /migrations/example1/000001_create_users_table.up.sql /migrations/example1/000001_create_users_table.down.sql
3. 作成されたテンプレートにそれぞれSQLを記載
作成された2つファイルは、更新用のSQLファイルと切り戻し用のSQLファイルを定義します。
000001_create_users_table.up.sql
に下記を記載します (更新用)
CREATE TABLE IF NOT EXISTS users( user_id serial PRIMARY KEY, username VARCHAR (50) UNIQUE NOT NULL, password VARCHAR (50) NOT NULL, email VARCHAR (300) UNIQUE NOT NULL );
000001_create_users_table.down.sql
に下記を記載します (切り戻し用)
DROP TABLE IF EXISTS users;
4. 1回目のマイグレーション実施
golang-migrate
でマイグレーションを行います。
$ export POSTGRESQL_URL='postgres://postgres:password@postgres:5432/example?sslmode=disable' $ migrate -database ${POSTGRESQL_URL} -path migrations/example1 up 1/u create_users_table (13.397ms)
5. example
にマイグレーションされているか確認
PostgreSQLのクライアントでデータベースに反映されているか確認してみます。
$ psql -h postgres -U postgres example example=# \d List of relations Schema | Name | Type | Owner -------+-------------------+----------+---------- public | schema_migrations | table | postgres public | users | table | postgres public | users_user_id_seq | sequence | postgres (3 rows) example=# \d users Table "public.users" Column | Type | Collation | Nullable | Default ---------+------------------------+-----------+----------+------------------- user_id | integer | | not null | nextval('users_user_id_seq'::regclass) username | character varying(50) | | not null | password | character varying(50) | | not null | email | character varying(300) | | not null | Indexes: "users_pkey" PRIMARY KEY, btree (user_id) "users_email_key" UNIQUE CONSTRAINT, btree (email) "users_username_key" UNIQUE CONSTRAINT, btree (username) example=# \q
users
テーブルと users_user_id_seq
シーケンスが作成されており、カラムも作成されているので成功しています。
[Note]
schema_migrations
はgolang-migrateが履歴管理などに利用しているテーブルです
6. 2回目のマイグレーションのSQLファイル作成
1回目と同様にテンプレートを作成し、編集を行ってマイグレーションします。
今回はマイグレーション中にトランザクションを使用します。
$ migrate create -ext sql -dir migrations/example1 -seq add_mood_to_users /migrations/example1/000002_add_mood_to_users.up.sql /migrations/example1/000002_add_mood_to_users.down.sql
それぞれ編集します。
000002_add_mood_to_users.up.sql
に下記を記載します (更新用)
BEGIN; CREATE TYPE enum_mood AS ENUM ( 'happy', 'sad', 'neutral' ); ALTER TABLE users ADD COLUMN mood enum_mood; COMMIT;
000002_add_mood_to_users.down.sql
に下記を記載します (切り戻し用)
BEGIN; ALTER TABLE users DROP COLUMN mood; DROP TYPE enum_mood; COMMIT;
6. 2回目のマイグレーション実施・確認
1回目と同様にマイグレーションを実行し、確認します。
$ migrate -database ${POSTGRESQL_URL} -path migrations/example1 up 2/u add_mood_to_users (9.1277ms) $ psql -h postgres -U postgres example example=# \d users Table "public.users" Column | Type | Collation | Nullable | Default ---------+------------------------+-----------+----------+------------------- user_id | integer | | not null | nextval('users_user_id_seq'::regclass) username | character varying(50) | | not null | password | character varying(50) | | not null | email | character varying(300) | | not null | mood | enum_mood | | | Indexes: "users_pkey" PRIMARY KEY, btree (user_id) "users_email_key" UNIQUE CONSTRAINT, btree (email) "users_username_key" UNIQUE CONSTRAINT, btree (username) example=# \q
無事にマイグレーションされていることが確認できました。
[応用編1] GitHubからマイグレーションファイルを取得してみよう
公式のGitHubにはSQLのexample があります。今回はそれを利用させていただき、認証やタグ指定などの確認を行うためにプライベートリポジトリへ次のように作成しました。
ツールに指定するGitHubのURIを変更することで、特定のブランチやタグを取得することができるため試します。
ブランチツリー
* f34fc01 (HEAD -> master, origin/master, origin/HEAD) add new file ($$$$) | * 735dddc (origin/develop, develop) Add files via upload (#) |/ * 4ae8484 (tag: v0.2.0) Add files via upload ($$$) * 23b249b (tag: v0.1.0) Add files via upload ($$) * 8435828 Add files via upload ($) * 2eaa8b3 Create README.md
リポジトリ内構造
ファイル名末尾に記載されているの $
#
の記号はブランチツリーの各コミットと対応させてありますので、以降の手順でマイグレーションされているファイルが正しいかの確認にご利用ください。
├── README.md └── migrations ├── 1085649617_create_users_table.down.sql ($) ├── 1085649617_create_users_table.up.sql ($) ├── 1185749658_add_city_to_users.down.sql ($$) ├── 1185749658_add_city_to_users.up.sql ($$) ├── 1285849751_add_index_on_user_emails.down.sql ($$) ├── 1285849751_add_index_on_user_emails.up.sql ($$) ├── 1385949617_create_books_table.down.sql ($$) ├── 1385949617_create_books_table.up.sql ($$) ├── 1485949617_create_movies_table.down.sql ($$$) ├── 1485949617_create_movies_table.up.sql ($$$) ├── 1585849751_just_a_comment.up.sql ($$$) ├── 1685849751_another_comment.up.sql ($$$) ├── 1785849751_another_comment.up.sql (#) ├── 1885849751_another_comment.up.sql (#) └── 1900000000_create_sample_table.up.sql ($$$$)
[Note]
- GitHubを利用した場合のURIのフォーマットは githubをご覧ください
URIにブランチなどの指定なしの場合
何も指定しない場合は、masterブランチのHEADが取得されてマイグレーションされていることが確認できます。
$ export POSTGRESQL_URL='postgres://postgres:password@postgres:5432/example?sslmode=disable' $ export SOURCE_URI='github://your-name:personal-access-token@your-owner/youre-repo/migrations' $ migrate -database ${POSTGRESQL_URL} -source ${SOURCE_URI} up 1085649617/u create_users_table (15.3183ms) 1185749658/u add_city_to_users (12.8733ms) 1285849751/u add_index_on_user_emails (10.8527ms) 1385949617/u create_books_table (11.0747ms) 1485949617/u create_movies_table (14.886ms) 1585849751/u just_a_comment (11.1459ms) 1685849751/u another_comment (13.8439ms) 1900000000/u create_sample_table (12.2614ms)
URIにDevelopブランチ指定ありの場合
URIに #develop
のようにブランチを指定すると、developブランチが取得されてマイグレーションされていることが確認できます。
$ export POSTGRESQL_URL='postgres://postgres:password@postgres:5432/example?sslmode=disable' $ export SOURCE_URI='github://your-name:personal-access-token@your-owner/youre-repo/migrations#develop' $ migrate -database ${POSTGRESQL_URL} -source ${SOURCE_URI} up 1085649617/u create_users_table (15.8906ms) 1185749658/u add_city_to_users (10.8608ms) 1285849751/u add_index_on_user_emails (16.6914ms) 1385949617/u create_books_table (14.0107ms) 1485949617/u create_movies_table (14.2851ms) 1585849751/u just_a_comment (9.2893ms) 1685849751/u another_comment (14.0647ms) 1785849751/u another_comment (12.8647ms) 1885849751/u another_comment (13.949ms)
URIにv0.1.0のタグ指定ありの場合
URIに #v0.1.0
のようにタグを指定すると、タグのリビジョンで取得されてマイグレーションされていることが確認できます。
$ export POSTGRESQL_URL='postgres://postgres:password@postgres:5432/example?sslmode=disable' $ export SOURCE_URI='github://your-name:personal-access-token@your-owner/youre-repo/migrations#v0.1.0' $ migrate -database ${POSTGRESQL_URL} -source ${SOURCE_URI} up 1085649617/u create_users_table (9.799ms) 1185749658/u add_city_to_users (13.4742ms) 1285849751/u add_index_on_user_emails (16.0135ms) 1385949617/u create_books_table (8.895ms)
[応用編2] AWS S3からマイグレーションファイルを取得してみよう
1. S3にマイグレーションファイルをアップロード
S3には先ほどと同様に公式のGitHubよりSQLのexampleをアップロードします。ディレクトリ構造はGitHubと同じですので、詳細はそちらを参照してください。
2. S3のアクセス権の設定
S3にアクセスするためユーザには AmazonS3ReadOnlyAccess
ポリシーを付与します。(検証目的以外で利用される場合には、アクセス範囲を絞ることをおすすめいたします)
3. マイグレーションを実行
執筆時点では、S3にアクセスするためのCredentialsの設定方法の記載がありません3が、AWS go sdkを利用しているため以下のように環境変数4に設定します。今回はS3バケットのみ東京リージョンにあるため、リージョンには ap-northeast-1
を指定しています。
$ export AWS_ACCESS_KEY_ID=YOUR_AKID $ export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY $ export AWS_REGION=ap-northeast-1
マイグレーションファイルが置いてあるS3を指定して実行します。
$ export POSTGRESQL_URL='postgres://postgres:password@postgres:5432/example?sslmode=disable' $ export SOURCE_URI='s3:///migrations' $ migrate -database ${POSTGRESQL_URL} -source ${SOURCE_URI} up 1085649617/u create_users_table (14.0349ms) 1185749658/u add_city_to_users (13.6978ms) 1285849751/u add_index_on_user_emails (16.2591ms) 1385949617/u create_books_table (17.9426ms) 1485949617/u create_movies_table (14.4656ms) 1585849751/u just_a_comment (8.4976ms) 1685849751/u another_comment (15.1989ms) 1900000000/u create_sample_table (14.7474ms)
[Note]
- GitHubを利用した場合のURIのフォーマットは aws_s3をご覧ください
[参考] Amazon Aurora (PostgreSQL互換) にマイグレーションしてみよう
以下のようなAmazon Aurora を作成してマイグレーションを行ってみました。
- リージョン: バージニア北部(us-east-1)
- インスタンスサイズ: t3.db.medium
- バージョン: Aurora PostgreSQL (Compatible with PostgreSQL 11.6)
今回は先述のGitHubのリポジトリから develop ブランチを指定し、Auroraにマイグレーションを試してみます。
$ export POSTGRESQL_URL='postgres://postgres:[email protected]:5432/example?sslmode=disable' $ export SOURCE_URI='github://your-name:personal-access-token@your-owner/youre-repo/migrations#develop' $ migrate -database ${POSTGRESQL_URL} -source ${SOURCE_URI} up 1085649617/u create_users_table (2.0493698s) 1185749658/u add_city_to_users (3.8259861s) 1285849751/u add_index_on_user_emails (5.6180448s) 1385949617/u create_books_table (7.4065352s) 1485949617/u create_movies_table (9.2197275s) 1585849751/u just_a_comment (10.9430546s) 1685849751/u another_comment (12.7785849s) 1785849751/u another_comment (14.5836142s) 1885849751/u another_comment (16.3808016s)
今回試したようなSQLでは問題なく動作しておりますが、作者公式サイトではAmazon Aurora (PostgreSQL互換)に対応していると明記しておりません。また使用する際は利用者様の責任においてご利用ください。