GitHub ActionsでPrismaマイグレーション実行

はじめに

こんにちは! 株式会社インダストリー・ワンのエンジニア、角田です。

インダストリー・ワンでは、クライアントのサービス開発以外にも様々な取り組みを行っていますが、その中の一つにプロダクトのベースとして使うための、スターターキットの開発があります。
今回はその中で私が担当した、GitHub Actions で Prisma の DB マイグレーションを実行するようにした改善について、試行錯誤の中で得られた知見を共有したいと思います。

開発環境(一部)

前提として、以下のツールを用いて開発しています。

背景・目的

本プロジェクトでは GitHub Actions を使って、CI/CD を行っています。
今回説明したいポイントに絞ると、以下の流れとなっています。

As Is

flowchart TD
    A(マイグレーションファイル\n作成) --> B(GitHubへpush)
    B --> C(デプロイ開始)
    C --> D(本番環境\nマイグレーション\n実行)
    D --> E{成否}
    E --> |成功| F(サービス起動)
    E --> |失敗| G(サービス起動失敗)

この場合、デプロイ開始後に本番環境でマイグレーション実行しているため、マイグレーション時のエラーが存在してもデプロイでき、サービス起動失敗してしまう問題がありました。
そのため以下のように変更し、GitHub Actions でテスト用マイグレーションを追加したいと考えました。

To Be

flowchart TD
    A(マイグレーションファイル\n作成) --> B(GitHubへpush)
    B --> C(テスト用マイグレーション)
    C --> D{成否}
    D -->|成功| E(デプロイ開始)
    D -->|失敗| F(デプロイ中止)
    E --> G(本番環境\nマイグレーション\n実行)
    G --> H(サービス起動)

こうすることでデプロイ開始前にマイグレーションの成否確認ができ、
マイグレーションのエラー時は、デプロイを中止させることができるという狙いです。

成果物

作成した GitHub Actions の設定ファイルがこちらになります。
ここに定義したテスト用マイグレーションの処理を push 時に行います。

.github/workflows/migration_test.yml

name: Migration test
# 既存のメインActionから呼び出し実行する
on:
  workflow_call:
# 環境変数に postgresql の接続文字列を定義(schema.prismaでDBに接続するときに使う)
env:
DB_USER: postgres
DB_PASSWORD: passw0rd
DB_HOST: localhost
DB_PORT: 5432
DB_NAME: postgres
DB_SCHEMA: public
DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?schema=${DB_SCHEMA}

jobs:
migration_test:
runs-on: ubuntu-latest

    # サービスコンテナを利用しpostgresqlを使えるように設定
    services:
      postgres:
        image: postgres
        env:
          POSTGRES_PASSWORD: passw0rd

        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          # tcp port 5432をサービスコンテナ→ホストにマッピング
          - 5432:5432

    # GitHub Actionsの実行
    steps:
      - name: Check out repository code
        uses: actions/checkout@v3

      - name: install pnpm
        run: npm install -g pnpm@7.25.1

      - name: install packages
        run: pnpm install

      - name: Run Migration
        run: pnpm --filter=<マイグレーションファイルがあるパッケージ> prisma migrate deploy

ハマった箇所

筆者の知見不足もあり、上記の完成系に持っていくには色々と試行錯誤がありました。 その中で、自身の備忘録も兼ねて、得られた知見を共有いたします。

ちなみに筆者の事前理解としては、こんなレベルでした。

  • Github Actions:知見なし。
  • Prisma:知見なし。別のORMは知見あり。
  • Docker:Dockerの概念は知っている。
  • Postgres SQL:知見あり。

得られた知見としては、以下のようなものがありました。

GitHub Actionsを動かすには

詳細

プロジェクトルートに、.github/workflows/フォルダ配下にymlファイルがあれば動かすことができます。 yml内部のon:に、実行するタイミングを記載すれば、そのタイミングでjob:に記載されたジョブが実行されます。

成果物 では、"workflow_call:"を指定しており、既存のメインActionとなるymlから呼び出すようにしています。 メインymlの詳細は割愛しますが、on:に"push:"を指定しており、プッシュ時に実行されるようになっています。

GitHub Actionsの詳細は公式ページ参照。
docs.github.com

GitHub Actionsでコンテナを使いたい場合、サービスコンテナを使うと吉

詳細

マイグレーションを行うために、一時的なDB環境が必要であり、それを構築するためのコンテナが必要でした。 GitHubは、サービスコンテナという、コンテナを作成できる機能を持っています。これを使えば自前でコンテナの作成コマンドを打つ必要がありません。
(私はそれを知らず、最初ワークフローの中でdocker-compose upを実行して、Dockerコンテナを作ろうとしていました。。(汗) docs.github.com

サービスコンテナの接続文字列のデフォルト値

詳細

成果物 のenv:で接続文字列を指定していますが、最初はこれらを何に指定すれば良いか、分かりませんでした。
以下のJavaScriptコードの例で接続文字列を指定しているのですが、なぜそのように決まるか疑問でした。
docs.github.com

postgresのDockerイメージを確認したところ、以下のようにデフォルト値が決まっていました。

  • ユーザ名(POSTGRES_USER):postgres
  • DB名(POSTGRES_DB):POSTGRES_USERの値

ユーザーが必須で指定しなければいけないのは、POSTGRES_PASSWORDのみということでした。
hub.docker.com

またホスト名ですが、ランナーマシン上でジョブを直接実行する場合、"localhost"か "127.0.0.1"を使ってサービスコンテナにアクセスできます。
docs.github.com

結果的に、以下のように決まります。

  • ユーザ名:postgres
  • DB名:postgres
  • ホスト名:localhost

それ以外のパスワードとポート番号は、 成果物 にて、以下のように記載しています。

jobs:
  migration_test:
...

    services:
      postgres:
        image: postgres
        env:
          POSTGRES_PASSWORD: passw0rd
...
        ports:
          # tcp port 5432をサービスコンテナ→ホストにマッピング
          - 5432:5432

prismaマイグレーションの流れ

詳細

ご存知の方には言わずもがなですが、大まかに以下の流れとなります。

  1. スキーマの変更
  2. schema.prisma の更新
  3. マイグレーションファイルの作成
  4. マイグレーション実行(コンテナ等で、DB に接続できる準備が必要)

www.prisma.io

.envファイルの用途

詳細

schema.prisma を作成する場所に.env ファイルがあれば、内部に定義されている文字列を、環境変数として扱ってくれます。
今回のケースでは、既にローカルで動かすための.env ファイルが存在していたため、.env ファイルではなく 成果物 の env:で環境変数を指定する形をとりました。
.env ファイルの記載例:

env:
  DB_USER: postgres
  DB_PASSWORD: passw0rd
  DB_HOST: localhost
  DB_PORT: 5432
  DB_NAME: postgres
  DB_SCHEMA: public
  DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?schema=${DB_SCHEMA}

www.prisma.io

.env以外のファイルを使用して環境変数を設定するには

詳細

dotenv - npm

を使用します。 以下は、.env の代わりに.env.migration_test を使用する例です。

dotenv -e .env.migration_test -- prisma migrate deploy

GitHub Actions のワークフローで使用する場合は、以下のようにインストール処理が必要です。

run: pnpm add -w dotenv-cli

今回は最終的に使いませんでしたが、ローカルで使用する.env とは異なるファイルを使いマイグレーションを行うことも検討していました。その中で得られた知見でした。
www.prisma.io

.envファイルに記載された環境変数を使わないようにするには

詳細

GitHub Actions の yml ファイルに、"env:"を記載しておけば、そちらが優先して使用されます。

まとめ

今回は GitHub Actions で Prisma マイグレーション実行の設定をする中で、得られた知見を共有させていただきました。
こういった知見がない分野で試行錯誤しながら実施することは、大変な一面がありましたが、経験豊富なメンバーから助言をもらいながら進めることができました。結果的に自身の成長につながったと思います!
以上、最後まで読んでくださり、ありがとうございました。

おわりに

インダストリー・ワンでは一緒に働く仲間を募集しています。
少しでも興味を持っていただいた方は、是非以下から応募していただければと思います。もちろんカジュアル面談からでも OK!
どうぞ宜しくお願いいたします。

herp.careers