2020年9月17日

TypeScript、PostgreSQL & Prismaを使用したバックエンド:CIとデプロイメント

シリーズの第4部では、GitHub Actionsを使用して継続的インテグレーション(CI)と継続的デプロイメント(CD)を構成し、バックエンドをテストしてHerokuにデプロイします。

Backend with TypeScript, PostgreSQL & Prisma: CI & Deployment

はじめに

このシリーズの目標は、具体的な問題(オンラインコースの採点システム)を解決することにより、最新のバックエンドにおけるさまざまなパターン、問題、アーキテクチャを探索し、実証することです。

ライブストリームの録画は上記で利用可能であり、この記事と同じ内容をカバーしています。

シリーズで取り上げる内容

このシリーズでは、バックエンド開発のあらゆる側面におけるデータベースの役割に焦点を当て、以下を取り上げます。

トピックパート
データモデリングパート1
CRUDパート1
集計パート1
REST APIレイヤーパート2
バリデーションパート2
テストパート2
パスワードレス認証パート3
認可パート3
外部APIとの統合パート3
継続的インテグレーションパート4(現在)
デプロイメントパート4(現在)

最初の記事では、問題領域のデータモデルを設計し、シードスクリプトを作成しました。このスクリプトはPrisma Clientを使用してデータをデータベースに保存します。

シリーズの2番目の記事では、最初の記事のデータモデルとPrismaスキーマの上にREST APIを構築しました。Hapiを使用してREST APIを構築し、HTTPリクエストを介してリソースに対するCRUD操作を実行できるようにしました。

シリーズの3番目の記事では、JSON Web Tokens(JWT)をHapiとともに使用してREST APIを保護し、メールベースのパスワードレス認証と認可を実装しました。さらに、ユーザーが許可されている操作を定義するために、リソースベースの認可を実装しました。

今日学ぶこと

この記事では、GitHub ActionsをCI/CDサーバーとしてセットアップし、テストを実行してバックエンドをHerokuにデプロイするワークフローを定義します。Herokuでは、バックエンドとPostgreSQLデータベースをホストします。

Herokuはサービスとしてのプラットフォーム(PaaS)です。サーバーレスデプロイメントモデルとは対照的に、Herokuを使用すると、リクエストがなくてもアプリケーションは常に実行されます。サーバーレスには、コストの削減や運用オーバーヘッドの削減など、多くの利点がありますが、このアプローチでは、サーバーレスアプローチに共通するデータベース接続のチャーンとコールドスタートの課題を回避できます。

Prismaを使用するアプリケーションのデプロイメントパラダイム間のトレードオフの詳細については、Prismaのデプロイメントドキュメントを参照してください。

注:ガイド全体を通して、手順を正しく実行したかどうかを検証できるさまざまなチェックポイントがあります。

前提条件

GitHub Actionを使用してバックエンドをHerokuにデプロイするには、以下が必要です。

  • Herokuアカウント。
  • Heroku CLIがインストールされていること。
  • メール送信用のSendGrid APIトークン(シリーズのパート3で作成したもの)。

継続的インテグレーションと継続的デプロイメント

継続的インテグレーション(CI)は、個々の開発者からの作業をメインコードリポジトリに統合し、統合バグを早期に捕捉し、共同開発を加速するために使用される手法です。通常、CIサーバーはGitリポジトリに接続されており、コミットがリポジトリにプッシュされるたびに、CIサーバーが実行されます。

継続的デプロイメント(CD)は、変更を迅速かつ一貫してデプロイできるように、デプロイメントプロセスを自動化することに関心のあるアプローチです。

CIとCDは異なる責任に関係していますが、関連性があり、同じツールを使用して処理されることがよくあります。この記事では、GitHub Actionsを使用してCIとCDの両方を処理します。

継続的インテグレーションパイプライン

継続的インテグレーションでは、主要な構成要素はパイプラインです。パイプラインは、変更によってバグやリグレッションが導入されないようにするために定義する一連のステップです。たとえば、パイプラインには、テスト、コードリンター、TypeScriptコンパイラーを実行するステップが含まれる場合があります。いずれかのステップが失敗した場合、CIサーバーは停止し、失敗したステップをGitHubに報告します。

プルリクエストを使用してコード変更が導入されるチームで作業する場合、CIサーバーは通常、すべてのプルリクエストに対してパイプラインを自動的に実行するように構成されます。

前の手順で作成したテストは、APIのエンドポイントへのリクエストをシミュレートすることで機能します。これらのエンドポイントのハンドラーはデータベースと対話するため、テストの実行時間中はバックエンドのスキーマを持つPostgreSQLデータベースが必要です。次のステップでは、GitHub Actionsを構成して、(CI実行時間中の)テストデータベースを実行し、マイグレーションを実行して、テストデータベースがPrismaスキーマと一致するようにします。

注:CIは、作成したテストと同じくらい優れています。テストカバレッジが低い場合、テストに合格しても、誤った安心感が生まれる可能性があります。

GitHub Actionsでワークフローを定義する

GitHub Actionsは、継続的インテグレーションに使用できる自動化プラットフォームです。GitHubのイベントに基づいてワークフローを調整するためのAPIを提供し、GitHubからコードをビルド、テスト、デプロイするために使用できます。

GitHub Actionsを構成するには、yamlを使用してワークフローを定義します。ワークフローは、さまざまなリポジトリイベント(例:コミットがリポジトリにプッシュされたとき、またはプルリクエストが作成されたとき)で実行するように構成できます。

各ワークフローには複数のジョブを含めることができ、各ジョブは複数のステップを定義します。ジョブの各ステップはコマンドであり、テストされている特定のコミットのソースコードにアクセスできます。

注:CIサービスはパイプラインに対して異なる用語を使用します。たとえば、GitHub Actionsは同じものを指すためにワークフローという用語を使用します。

この記事では、リポジトリのgrading-appワークフローを使用します。

ワークフローを見てみましょう

grading-appワークフローには、testdeployの2つのジョブがあります。

testジョブは次のことを行います。

  1. リポジトリをチェックアウトします。
  2. nodeを構成します。
  3. 依存関係をインストールします。
  4. servicesを使用して起動されるテストデータベースにデータベーススキーマを作成します。
  5. テストを実行します。

注:servicesは、追加のサービスを実行するために使用できます。上記のtestジョブでは、テストPostgreSQLデータベースを作成するために使用されています。

deployジョブは次のことを行います。

  1. リポジトリをチェックアウトします
  2. 依存関係をインストールします
  3. 本番データベースに対してマイグレーションを実行します
  4. Herokuにデプロイします

注:on: pushは、プッシュされたすべてのコミットに対してワークフローをトリガーします。if: github.event_name == 'push' && github.ref == 'refs/heads/master'条件は、deployジョブがmasterに対してのみトリガーされるようにします。

リポジトリをフォークしてワークフローを有効にする

GitHub actionsを構成できるように、GitHubリポジトリをフォークすることから始めます。

注:すでにリポジトリをフォークしている場合は、オリジンリポジトリのmasterブランチから変更をマージしてください

フォークしたら、Githubのアクションタブに移動します

有効にするボタンをクリックしてワークフローを有効にします

これで、コミットをリポジトリにプッシュすると、GitHubがワークフローを実行します。

Heroku CLIログイン

CLIを使用してHerokuにログインしていることを確認してください

Herokuアプリを作成する

バックエンドアプリケーションをHerokuにデプロイするには、Herokuアプリを作成する必要があります。クローンされたリポジトリのフォルダーから次のコマンドを実行します。

注:YOUR_APP_NAMEの代わりに、任意のユニークな名前を使用してください。

チェックポイント Heroku CLIは、アプリが正常に作成されたことをログに記録する必要があります

HerokuでPostgreSQLデータベースをプロビジョニングする

次のコマンドでデータベースを作成します。

チェックポイント:データベースが作成されたことを確認するには、次の内容が表示されるはずです

注:Herokuは、アプリケーションランタイム用にDATABASE_URL環境変数を自動的に設定します。Prisma Clientは、Prismaスキーマで構成された環境変数と一致するため、DATABASE_URLを使用します。

GitHubでビルド時のシークレットを定義する

GitHub Actionsが本番データベースのマイグレーションを実行し、バックエンドをHerokuにデプロイするには、GitHubワークフローで参照されている4つのシークレットを作成します。

注:ビルド時のシークレットとランタイムシークレットの間には区別が必要です。ビルド時のシークレットはGitHubで定義され、GitHub Actionsの実行時間中に使用されます。一方、ランタイムシークレットはHerokuで定義され、バックエンドで使用されます。

シークレット

  • HEROKU_APP_NAME:前の手順で選択したアプリの名前。
  • HEROKU_EMAIL:Herokuにサインアップしたときに使用したメールアドレス。
  • HEROKU_API_KEY:Heroku APIキー
  • DATABASE_URL:デプロイ前に本番データベースのマイグレーションを実行するために必要なHerokuの本番PostgreSQL URL。

本番DATABASE_URLを取得する

データベースがプロビジョニングされたときにHerokuによって設定されたDATABASE_URLを取得するには、次のHeroku CLIコマンドを使用します。

チェックポイント:出力にURL(例:postgres://username:password@ec2-12.eu-west-1.compute.amazonaws.com:5432/dbname)が表示されるはずです

HEROKU_API_KEYを取得する

Heroku APIキーは、Herokuアカウント設定から取得できます

Heroku API key in the Heroku account settings

GitHubでシークレットを作成する

4つのシークレットを作成するには、リポジトリ設定に移動し、Secretsタブを開きます

GitHub repository secrets

[New secret]をクリックし、シークレット名(例:HEROKU_APP_NAME)に名前フィールドを使用し、値を設定します

チェックポイント:4つのシークレットを作成した後、次の内容が表示されるはずです

GitHub repository secrets

Herokuで環境変数を定義する

バックエンドには、ランタイム時に環境変数としてアプリケーションに渡される3つのシークレットが必要です

  • SENDGRID_API_KEYSendGrid APIキー
  • JWT_SECRET:JWTトークンの署名に使用されるシークレット。
  • DATABASE_URL:Herokuによって自動的に設定されたデータベース接続URL。

注:JWT_SECRETは、ターミナルで次のコマンドを実行して生成できます:node -e "console.log(require('crypto').randomBytes(256).toString('base64'));"

Heroku CLIで設定するには、次のコマンドを使用します。

チェックポイント:環境変数が設定されたことを確認するには、次の内容が表示されるはずです

ワークフローをトリガーしてテストとデプロイを実行する

ワークフローが構成され、Herokuにアプリが作成され、すべてのシークレットが設定されたので、ワークフローをトリガーしてテストとデプロイを実行できます。

ビルドをトリガーするには、空のコミットを作成してプッシュします

コミットをプッシュしたら、GitHubリポジトリの[Actions]タブに移動すると、次の内容が表示されるはずです

コミットメッセージを含むテーブルの最初の行をクリックします

testジョブのログを表示する

testジョブのログを表示するには、[test]をクリックすると、各ステップのログを表示できます。たとえば、下のスクリーンショットでは、テストの結果を表示できます

Herokuへのデプロイメントを検証する

deployジョブがHerokuに正常にデプロイされたことを検証するには、左側の[deploy]をクリックし、[Deploy to Heroku]ステップを展開します。ログの最後に次の行が表示されるはずです

ブラウザからAPIにアクセスするには、クローンされたリポジトリフォルダーから次のHeroku CLIコマンドを使用します。

これにより、https://YOUR_APP_NAME.herokuapp.com/を指すブラウザが開きます。

チェックポイント:ブラウザに{"up":true}が表示されるはずです。これは、ステータスエンドポイントによって提供されます。

バックエンドログを表示する

バックエンドのログを表示するには、クローンされたリポジトリフォルダーから次のHeroku CLIコマンドを使用します。

ログインフローをテストする

ログインフローをテストするには、REST APIへの2つの呼び出しを行う必要があります。

まず、APIのURLを取得します

curlを使用してログインエンドポイントにPOST呼び出しを行います

メールで8桁のトークンを確認し、2番目の呼び出しを行います

チェックポイント:レスポンスは200の成功ステータスコードを持ち、JWTトークンを含むAuthorizationヘッダーが含まれている必要があります

まとめ

バックエンドがデプロイされ、実行されています。よくできました!

GitHub Actionsワークフローを定義し、Herokuアプリを作成し、PostgreSQLデータベースをプロビジョニングし、GitHub Actionsを使用してバックエンドをHerokuにデプロイすることにより、継続的インテグレーションとデプロイメントを構成しました。

リポジトリにコミットして変更をプッシュすることにより新機能を導入すると、テストとTypeScriptコンパイラーが自動的に実行され、成功した場合、バックエンドがデプロイされます。

Herokuダッシュボードにアクセスすると、メモリ使用量、応答時間、スループットなどのメトリクスを表示できます。これは、バックエンドがさまざまなトラフィック量をどのように処理するかについての洞察を得るのに役立ちます。たとえば、バックエンドへの負荷が増加すると、応答時間が遅くなる可能性があります。

TypeScriptとPrisma Clientを使用することで、通常はランタイムで検出され、デバッグが必要になる可能性のあるタイプエラーのクラスを排除できます。

バックエンドの完全なソースコードはGitHubで見つけることができます。

Prismaはリレーショナルデータベースの操作を容易にすることを目指していますが、基盤となるデータベースとHeroku固有の詳細を理解することは役立ちます。

質問がある場合は、Twitterでお気軽にお問い合わせください。

次回の投稿をお見逃しなく!

Prismaニュースレターにサインアップ