リクルートテクノロジーズにおけるtoB業務支援サービスの開発基盤について
西方 聖一
この記事について
この記事はRecruit Engineers Advent Calendar 201716日目の記事です。
こんにちは、16日目の記事ですが今日は18日です!
自分の担当日をすっかり忘れていて、慌てて記事を書いているのが今です。
業務支援サービスとは
本記事ではクライアントの業務を効率化するために提供しているSaaSを指しています。
現在私が携わっているプロジェクトでは別の記事で紹介されているボイラープレートを使ってフロントエンドの開発を行っています。
BFFを利用し、APIサーバを含めると
- React
- Redux
- Node.js
- Kotlin
- Spring Boot
- AWS
- GCP
上記を利用して開発/運用しています。
現状アプリケーションコード以外にTerraformを使ってAWS/GCPリソースをコード化して管理しているのはCIとの相性が良いためです。なので現在作業と言えばコードを書いているぐらいでそれ以外に何かした記憶が最近ありません・・・。
アプリケーションの稼働環境はECS上で稼働させており、モニタリング/トラッキングにはアプリケーションが吐き出すログをGCPのBigQueryへ流しています。
これらを使って利用者が使いやすいサービスに拘り業務支援サービスを開発しているのが、現在の弊社の状況です。
開発基盤
ここでタイトルの本題へ話が移ります。
サービス開発において効率的にユーザへ価値を提供するためには、如何に効率良く開発が行えるか、その基盤を用意しておくべきだと考えています。本記事では私が携わっているプロジェクトで用意した開発基盤についてご紹介します。
まずは自分が開発していて、どうだったらストレス無く開発が行えるか考えてみました。
- ローカル環境で全ての機能が本番と同じように動作すること(S3へのファイルアップロード機能とか面倒ですよね)
- PRがオープンされたら、レビュー用の環境が立ち上がってコードレビューと一緒に動作確認も行いたい
- CIサーバはよろしくスケールアウトして欲しい
- マージしたら即デプロイして欲しい
これを実現するための開発基盤を今のプロジェクトで用意しました。
フロー
下記が開発〜レビューのフローです。PRのレビューを迅速に行えることを目的としています。
こちらがCIサーバを使ってデプロイするまでのフローです、どちらもとても単純ですね。単純であればある程扱いやすいし変更しやすいので気に入っています。
CI
去年のアドベントカレンダーに引き続きCIは、droneを利用しています。
GKE上でdroneのクラスタが稼働しています。
PRレビュー用環境
PR毎にレビュー環境が欲しくなります。これを実現するためにDeisを利用してレビュー用の環境を都度立ち上げて、PRがクローズしたら環境を閉じます。
コードレビューとテストはレビューアが実施します。
ビルド/デプロイ
これは単純です。CIサーバでDockerイメージをビルドし、ECRへpushします。ECRへpushしたらecs-deployを利用してECSのコンテナを入れ替えているだけです。
※現在AWS/GCP共にTerraformでリソースの管理を行っていますが、ecs-deploy
実行時に管理しているtask_definitionのバージョンがtfstate内のファイルと相違してしまうので、ecs-deploy
実行後は必ずterraform refresh
を実行するようにしています。
また、プロジェクト初期の段階ではローカルから実行するためにterraform
やecs-deploy
をdockerから実行するようなスクリプトを用意していました。これは、開発者間でterraform
やecs-deploy
のバージョン相違を無くす事を目的としています。
実際の物とは少々異なりますが、下記がそのスクリプトのサンプルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
#!/bin/bash -eu # Terraform version readonly TERRAFORM_DOCKER_IMAGE_VERSION=0.11.1 usage() { echo "Usage: $0 [-e environment] [-b bucket] subcommand" 1>&2 } pull_image() { docker pull hashicorp/terraform:${TERRAFORM_DOCKER_IMAGE_VERSION} } run() { local sub_command="$1" local environment="$2" local bucket="$3" local mount_dir=$(git rev-parse --show-toplevel) rm -rf ${mount_dir}/terraform/.terraform docker run --rm -it \ -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \ -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \ -e AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION} \ -v ${mount_dir}/terraform:/$(basename ${mount_dir}) \ -w /$(basename ${mount_dir}) \ --entrypoint /bin/sh \ hashicorp:${TERRAFORM_DOCKER_IMAGE_VERSION} \ -c "terraform init -backend-config='bucket=${bucket}' -backend-config='key=${environment}'&& terraform get && terraform ${sub_command} -var aws_access_key=${AWS_ACCESS_KEY_ID} -var aws_secret_access_key=${AWS_SECRET_ACCESS_KEY}" } while getopts e:b:h OPT do case $OPT in e) ENVIRONMENT=$OPTARG ;; b) BUCKET=$OPTARG ;; h) usage exit ;; \?) usage exit 1 ;; esac done shift $((OPTIND - 1)) case "$@" in plan) pull_image run plan ${ENVIRONMENT} ${BUCKET} ;; apply) pull_image run apply ${ENVIRONMENT} ${BUCKET} ;; destroy) pull_image run destroy ${ENVIRONMENT} ${BUCKET} ;; refresh) pull_image run refresh ${ENVIRONMENT} ${BUCKET} ;; *) usage exit 1 ;; esac |
上記のようにdocker経由でterraformを実行することによって、開発者間のバージョン差分を無くしています。
ここまでが、今のプロジェクトで用意した開発のための仕組みです。
ローカル環境
次に、ローカル環境に移ります。
現在担当しているサービスでは、メールとS3を利用しているので、ローカルでの開発には下記のDockerイメージを利用しています。
それぞれの利用シーンは下記の通りです。
- Minio
S3互換のオブジェクトストレージのため、S3と連携する機能を開発する際に利用しています。 - Minio mc
Minioを操作するためのCLIツールです。CLI上からバケットを作成する事が可能なので、アプリケーションで利用するバケットのプロビジョニングで利用しています。 - MailHog
MailCatcherにインスパイアを受けたSMTPサーバです。WebUIが見やすく、APIも用意されているのでターミナルから出たくない時も助かっています。
下記が実際に利用しているdocker-compose.yml
です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
version: '3.3' services: minio: image: minio/minio command: server /data volumes: - minio-data:/data - minio-config:/root/.minio ports: - "9000:9000" environment: - MINIO_ACCESS_KEY=access_key_id - MINIO_SECRET_KEY=secret_key - MINIO_REGION=ap-northeast-1 minio-mc: image: minio/mc links: - minio entrypoint: > /bin/sh -c " while ! nc -z minio 9000; sleep 1; done; sleep 5; mc config host add minio http://minio:9000 access_key_id secret_key S3v4; mc mb --region ap-northeast-1 minio/app; mc policy download minio/app; exit 0; " mailhog: image: blueimp/mailhog ports: - "1025:1025" - "8025:8025" volumes: minio-data: driver: local minio-config: driver: local |
上記のDockerイメージを使って現在とても快適に開発が行えています。
現状ローカルは特に何か工夫している点はありませんが、気付いていないだけで負はあるかもしれないですね。
最後に
ユーザにより良い体験を素早く提供するために用意した、開発のための基盤についてご紹介しました。
後回しにしがちな開発のための仕組みですが、多少我慢して時間を確保し用意することで得られるリターンは馬鹿に出来ないと思います。
今後の展望を少し挙げると、feature toggleの運用自動化(新機能のエラーレートが上がらなければ徐々に機能開放するユーザを増やして最終的に100%配信にする等)の仕組みを用意出来たらなと考えております。
この記事が同じtoB業務支援サービスを提供している方々の参考になれば幸いです。