社内システムのインフラをHerokuからAWSに移行した話

こんにちは。株式会社PRVENT開発部、バックエンドチームの横川です。
2021年1月に未経験から入社して現在はRubyやGoを書いて仕事してます。
今回は社内システムのインフラをHerokuからAWSへ移行した話を書こうと思います。

はじめに

元々弊社のシステムのインフラは全てHerokuでしたが、現在AWSへの移行を進めており
1つ目に社内システム「Mystar PRO」の移行が2021年7月に完了し、2つ目に弊社のCRMシステム、通称「CRM」(そのまんまw)の移行が2022年3月に完了しました。
弊社には現在インフラ専門のエンジニアはいないので、基本的にはプロダクトの担当者がインフラまで担当しています。
今回は自分が担当している「CRM」をAWSへ移行した話になります。

CRMを簡単に紹介

弊社の提供している「生活習慣改善プログラム」のプログラム開始までのフロー(お申し込み 〜 プログラム開始)をユーザー様ごとに管理できるシステムです。
モノシリックなRailsアプリで、自分が入社して最初にキャッチアップしたプロダクトです。

デプロイ先の決定

まずはデプロイ先ですが

  • コンテナでデプロイしたい
  • マネージドなサービスを使用したい
  • 7月に移行した「Mystar PRO」の バックエンドがECS × Fargate で稼働している

上記の理由から 「CRM」もECS × Fargate で動かすこととしました。

Dockerイメージ作成

Herokuではコンテナでのデプロイをしていなかったので、まずはDockerイメージの作成から取り掛かりました。
開発用のDockerfile(ベースイメージruby:<version>)は先人が用意してくれていましたが、そのままECRへpushして脆弱性をスキャンした所とんでもない数の脆弱性が検出されたため、新しくruby:<version>-alpineをベースイメージにしたデプロイ用のDockerfileを作成しました。
その結果 重要度が高い物を含め200ほどあった脆弱性が、重要度が低いもの1つだけになりました。
ruby:<version>-alpineは軽量なLinuxディストリビューションで有名なAlpineがベースになっていて、脆弱性のあるパッケージが初期段階では入っていないためだと考えられます。
ただ、ruby:<version>-alpineのようなAlpineベースのイメージだとruby:<version>のようなDebianベースのイメージと違い、Railsを動かすために必要なパッケージのいくつかが初期段階から入ってないため、Dockerfileにそれらをインストールするための記述が必要になってきます。
ちなみに今回作成したDockerfileの中身はこんな感じです。

FROM ruby:2.7.5-alpine3.15

ENV BUNDLE_JOBS=2
ENV APP_ROOT /usr/src/crms
ARG RAILS_MASTER_KEY

WORKDIR $APP_ROOT

RUN echo 'gem: --no-rdoc --no-ri' >> ~/.gemrc \
  && gem update --system \
  && gem install bundler -v 2.3.4

RUN apk update && apk add --no-cache postgresql-dev tzdata yarn libxml2-dev curl-dev make gcc libc-dev g++

COPY Gemfile $APP_ROOT
COPY Gemfile.lock $APP_ROOT
RUN bundle install

COPY . $APP_ROOT
RUN yarn install
RUN bundle exec rake assets:precompile RAILS_ENV=production

EXPOSE 3000

CMD ["ash", "startup.sh"]

変数 RAILS_MASTER_KEY は codebuildでのビルド時に引数で受け取るようにしていて、startup.shでDBマイグレーションRailsサーバーを起動するコマンドを実行しています。

AWS環境構築

Docker環境も用意できたので続いてAWS環境の構築です。
この時の自分はAWSの経験で言うと、入社前にEC2へのデプロイを一度したことあるくらいのレベルだったので、まずはECS × Fargateで簡単なシステムのデプロイを試した後CRMの環境構築に取り掛かりました。
DBやECSのスペックは大体Herokuのスペックに合わせて作成し、自動デプロイにcodepipeline を使用しました。

社内システムとの連携

動作環境の構築が終わった後、CRMが連携している社内システムとの連携を考える必要がありました。
というのも、CRMのデータは先に出てきた「MystarPRO」というプロダクトとも連携しており、定期バッチでCRMのDBに接続し特定のデータが更新されているかを確認し、更新されていればMystarPROのDBへ反映しています。 
「MystarPRO」と「CRM」のAWSアカウントは別になっていて、MystarPRO側のAWSアカウントで定期バッチが動いているため、CRM側のDBのセキュリティグループで別アカウント(MystarPROアカウント)からの通信を許可する必要がありました。
今回詳しくは書きませんが「VPC ピアリング」という機能を使用して接続できるようにしました。
これにより、別アカウントの2つのVPC間で同じネットワーク内に存在しているかのように通信できます。 docs.aws.amazon.com

移行手順の作成

環境構築も完了し動作確認も終えたので最後に移行作業当日の計画を立てました。
実はCRMは「MystarPRO」以外にも連携しているシステムがあり、その中の一つにユーザー様から弊社のサービスへ直接お申し込みをしていただく自社開発のLPサイトとAPIで連携をしています。
お申し込みのタイミングはユーザー様次第なのでダウンタイムが発生しないのが望ましく、その辺りも考慮して計画を立てる必要がありました。
過去のLPサイトからのお申し込み時間から移行作業する日時を決めて、移行中迷わないように細かく手順をまとめていきました。

移行作業

ついに移行当日です。
定期バッチが参照するCRMのDB接続先の変更も必要になるので、「MystarPRO」を担当する先輩エンジニアの方にも立ち会っていただき作業を開始しました。
数日前に、staging環境を移行していたので作業は比較的スムーズに進みました。
VPCピアリングの設定ミスで、定期バッチがうまく動かず少し焦りましたがすぐに原因も特定でき一件落着。
一番怖かったデータ移行作業も無事完了。本番での動作確認をして最後にHerokuをメンテナンスモードにして作業終了!
準備期間を含めおよそ半年間かけて行ってきた移行作業が完了しました。

移行後

早速、移行の翌日バグの報告が入りましたw
とあるデータの表示が今までは日時の降順だったのに対し、移行後は昇順になっていました。(動作確認時は気づかなかった...)
おそらくDBが変わったことによる影響と断定し、Rails側でソートすることで事なきを得ました。
その後は特にバグの報告はなく、CPU, メモリ使用率も問題なく今も安定稼働しています。

まとめ

AWSに移行したことにより、セキュリティ面を強化できましたしHerokuの制限を受けなくなり、他のAWSサービスや今後AWSへ移行する他のプロダクトとの連携もしやすくなったと思います
それと実は今回、初めてTerrraformを触ってAWS環境のほとんどをTerraformで作りました。
キャッチアップに少し時間がかかった部分もありますがとても良い経験を積めたと感じています。
まだまだ知らないことばかりなので、今後も色々なAWSのサービスやインフラ技術にキャッチアップしていきたいと思います。
オンプレを全く知りませんが、クラウドインフラ便利で触ってて楽しいですね!それではまた〜!