Closed20

AWS CodeBuildからDBマイグレーションを実行する方法を調査

Yuma ItoYuma Ito

やりたいこと

CodeBuildを使って、RDSへのDBマイグレーションを実行したい。
さらにCode Pipelineと合わせて使うことで、自動デプロイ時にDBマイグレーションを自動的に実行できるようになる。

知りたいこと

  • 必要なIAMポリシーは何か
  • CodeBuildで実行するコマンドや操作

前提

  • ECSとRDSを利用している
  • DB:PostgreSQL
  • 言語:TypeScript
  • ORマッパー:Sequelize
Yuma ItoYuma Ito

まずはCodeBuildのビルドプロジェクトを作成する。
CodeBuildからRDSに接続するためにはVPCの設定が必要だが、一旦後回しにする。

ソースは「GitHub」を選択し、自分の公開リポジトリを指定。

無料枠で実施する場合、インスタンスタイプをgeneral1.smallにする必要がある。
以下の用に設定した。

  • オペレーティングシステム: Amazon Linux 2
  • ランタイム: Standard
  • 環境イメージ: aws/codebuild/amazonlinux2-x86_64-standard:3.0
  • 環境タイプ: Linux
  • コンピューティング: 3 GB メモリ、2 vCPU (general1.small)

使用するランタイムによって、サポートしているイメージが異なる。
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-compute-types.html
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-available.html

Yuma ItoYuma Ito
  1. buildspec.ymlの作成
    CodeBuildのプロジェクトのランタイムや実行コマンドを定義する

https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html

  1. npm initでpackage.jsonの生成
  2. sequelizeをインストール
    DBはPostgreSQLなので、関連パッケージも合わせてインストールする。
$ npm install --save sequelize
$ npm install --save pg pg-hstore # Postgres

https://sequelize.org/master/manual/getting-started.html
4. GitHubにプッシュした後、AWSコンソールから「ビルドを開始」を押して、ビルドを開始する

Yuma ItoYuma Ito

先にRDSを作っておく。(時間がかかるので)

  • データベースエンジン:PostgreSQL 12.5
  • インスタンスタイプ: db.t2.micro
  • ストレージタイプ: 汎用
  • ストレージ: 20GiB
Yuma ItoYuma Ito

マイグレーションコードの用意をした後、buildspeck.ymlにDBマイグレーションのコマンドを追加した

どのフェーズに追加するべきかは迷ったが、ビルドの後だと思ったので、post_buildフェーズにした。

buildspec.yml
phases:
  post_build:
    commands:
      - echo This phease is post_build at `date`
      - echo exec DB migration
      - npm run db:migrate
Yuma ItoYuma Ito

CodeBuild用のネットワーク環境の整備

  • サブネットを作成
    • CodeBuildを配置するPrivateサブネット
    • NATゲートウェイを配置するPublicサブネット
  • Privateサブネット用のルートテーブルの作成
    • 0.0.0.0/0のターゲットには作成するNATゲートウェイを指定
  • NATゲートウェイを作成
    • Elastic IPでIPアドレスを割り当て
  • セキュリティグループの作成
    • CodeBuildのセキュリティグループ
  • RDSのセキュリティグループのインバウンドルールにCodeBuildのセキュリティグループからのアクセスを許可する設定を追加
Yuma ItoYuma Ito

CodeBuildからRDSへの接続はできたが、RDS内部にデータベースを作成していなかった。
以下のエラー

Sequelize CLI [Node: 12.19.1, CLI: 6.2.0, ORM: 6.6.2]

Loaded configuration file "config/config.json".
Using environment "development".

ERROR: database "db-migration-test" does not exist

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! code-build-db-migraiton@1.0.0 db:migrate: `sequelize db:migrate`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the code-build-db-migraiton@1.0.0 db:migrate script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2021-03-28T13_48_01_711Z-debug.log

RDS内部にデータベースを作成して、もう一度トライしたらできるのではないか。

Yuma ItoYuma Ito

マイグレーションコードの用意

  1. sequelize-cliをインストール
$ npm install -D sequelize-cli
  1. Sequelizeのプロジェクトを初期化
$ npx sequelize init

configファイルなどが生成される

config/config.json
{
  "development": {
    "use_env_variable": "DATABASE_URL"
  }
}
  1. マイグレーション用のファイルを生成
$ npx sequelize migration:generate --name create-schema

自動的に生成されたjsファイルを編集。今回はスキーマを作成するのみ。

migrations/create-schema.js
'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    queryInterface.createSchema('test_schema');
  },

  down: async (queryInterface, Sequelize) => {
    queryInterface.dropSchema('test_schema');
  }
};

https://sequelize.org/master/class/lib/dialects/abstract/query-interface.js~QueryInterface.html#instance-method-createSchema

Yuma ItoYuma Ito
  1. NPMスクリプトにコマンドを定義(任意)
package.json
{
  (略)
  "scripts": {
    "db:migrate": "sequelize db:migrate",
  }
  (略)
}
  1. ローカル環境で実行して動作確認する
    Dockerでマイグレーション実行用コンテナ(node実行環境)とDBコンテナを作成して確認した。
$ npm run db:migrate
Yuma ItoYuma Ito

つまづいた部分

Dockerの扱いに慣れていない

ローカル環境でDockerイメージの作成、コンテナを立ち上げることに時間がかかってしまった。
最初からdocker-composeを使ってやれば少しは早かったかもしれない。

Yuma ItoYuma Ito

CodeBuildからGitHubにアクセスできなくなった。

CodeBuildに割り当てるセキュリティグループのアウトバウンドルールを削除してしまったため。

Yuma ItoYuma Ito

CodeBuildをVPC内で実行するためのネットワーク設定に時間がかかった

  • サブネットの作成
    • パブリックサブネットとプライベートサブネットの違いはインターネットゲートウェイへのルーティングが設定されているかどうかの違い
  • NATゲートウェイの作成
    • NATゲートウェイはプライベートサブネットからインターネットにアクセスするために必要。
    • NATゲートウェイ自体はパブリックサブネットに配置し、Elastic IPを割り当てる。
    • ブライベートサブネットのルートテーブルにNATゲートウェイを設定する
Yuma ItoYuma Ito

CodeBuildからRDSへの接続でタイムアウトが発生した

CodeBuildのセキュリティグループのアウトバウンドルールでpsqlが許可されていなかった。

Yuma ItoYuma Ito

後片付け

コスト削減のため、検証の終わりには作成したインスタンスを削除する。

  • そのままにしておくとお金がかかるもの
    • ✅ RDS
    • ✅ NATゲートウェイ
    • ✅ Elastic IP
  • そのままでもお金はかからないが作成したもの
    • ✅ 各セキュリティグループ/サブネット/ルートテーブル
    • ✅ CodeBuild(ビルド時間にお金がかかるので)
このスクラップは2021/08/07にクローズされました