🐳

Nitro + Drizzleプロジェクトで使用していたPlanetScaleを、Dockerで構築したMySQL環境に移行する

2024/03/24に公開

こんにちは、合同会社Stegの @keigo です。今回は、Nitro + Drizzle + PlanetScaleの組み合わせで構築されたWebバックエンドアプリケーションのデータベースを、PlanetScaleの利用をやめてオンプレミスのMySQL環境へ移行した際の作業について紹介します。
なお、MySQL環境はDockerを利用して構築します。

背景

PlanetScaleは、2024/4/8をもって無料で使えるHobbyプランが廃止されます。

https://planetscale.com/docs/concepts/hobby-plan-deprecation-faq

お金を払ってでも使いたいくらい素晴らしいサービスですが、立ち上げたばかりのプロジェクトであるということから、ランニングコストをなるべく抑える目的で、データベースは別の方法で構築することにします。

検討した移行先

マネージドサービス

  • Supabase Database
  • Cloudflare D1
  • Vercel Postgres
  • Neon

非マネージドサービス

  • VPSやVM等にMySQLサーバを直接インストール
  • VPSやVM等にDockerコンテナの形でMySQLサーバを構築

上記に挙げたマネージドサービスは全てPostgreSQL互換であったため、VPSやVM等にDockerコンテナの形でMySQLサーバを構築することにしました。

移行作業

移行前は、MySQLベースのPlanetScaleに対し、DrizzleというORMを使用して接続していました。DrizzleにはPlanetscale用のクライアント実装が用意されています。
接続設定のソースコードは以下の通りです。

// db/index.ts
import { connect } from "@planetscale/database";
import { drizzle } from "drizzle-orm/planetscale-serverless";
import * as schema from "./schema";

const runtimeConfig = useRuntimeConfig();
const conn = connect({
    host: runtimeConfig.DATABASE_HOST,
    username: runtimeConfig.DATABASE_USERNAME,
    password: runtimeConfig.DATABASE_PASSWORD,
});

export const db = drizzle(conn, {schema});

接続設定はこの1つのファイルで完結しているため、この接続設定を変更するだけで、アプリケーションのコードを変更することなく移行作業を完了することができます。

MySQLの環境をDockerで構築し、接続先の情報を取得

compose.yamlを以下のように作成します。

version: '3.8'

services:
  db:
    image: mysql:8.3.0
    container_name: database_container
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASE: example
      MYSQL_USER: example
      MYSQL_PASSWORD: example
    ports:
      - "3306:3306"
    volumes:
      - database_data:/var/lib/mysql

volumes:
  database_data:

以下のコマンドで立ち上げれば、3306番ポートでMySQLサーバにアクセスできるようになります。

docker compose up

drizzle.config.tsファイルを作成

各設定項目は、プロジェクトのディレクトリ構造に合わせて適宜変更してください。
https://orm.drizzle.team/docs/migrations

import 'dotenv/config';
import type { Config } from 'drizzle-kit';

export default {
  schema: './db/schema.ts',
  out: './drizzle',
  driver: 'mysql2',
  dbCredentials: {
    host: 'localhost',
    user: 'xxx',
    password: 'xxx',
    database: 'xxx',
    port: 3306,
  },
} satisfies Config;

接続部分のコードを修正する

これまでデータベースとの接続に@planetscaleライブラリやdrizzle-orm/planetscale-serverlessを使用していましたが、これらをmysql2 クライアントを利用した接続に切り替えます。

import mysql, { type ConnectionOptions } from 'mysql2/promise';
import { drizzle } from "drizzle-orm/mysql2";
import * as schema from "./schema";

const connectionOptions: ConnectionOptions = {
    host: 'localhost',
    user: 'xxx',
    password: 'xxx',
    port: 3306,
    database: 'xxx',
};
export const connection = await mysql.createConnection(connectionOptions);

export const db = drizzle(connection, { 
    schema: schema,
    mode: 'default' 
});

sqlファイルを生成する

schemaファイルをもとに、Migration用のsqlファイルを生成します。

npx drizzle-kit generate:mysql

Migrationを実行

生成したsqlファイルをもとに、Migrationを実行します。tsxをインストールしていない場合は、インストールが要求されます。

npx tsx db/migrate.ts

実行が正常に完了すると、スキーマ情報に沿ってテーブルやカラムが作成されます。

Drizzle Studioで確認

Drizzle Studioを使用することで、ブラウザ上でデータベースの確認・編集が可能です。

画像は公式サイトから引用

https://orm.drizzle.team/drizzle-studio/overview

以下のコマンドを使用してDrizzle Studioを起動します。

npx drizzle-kit studio

おわりに

Drizzleが提供するマイグレーション機能を用いることで、データベースの移行を簡単に完了することができました。
元々スキーマファイルが作成されており、移行前後で同じMySQLを使用していたため、作業はスムーズに進みました。

Steg Inc.

Discussion