YakumoのAWS開発環境とデプロイパイプラインの紹介

こんにちは、Yakumoチームの@ueokandeです。 本日はYakumoプロジェクトで構築したAWS開発環境とデプロイパイプラインについて紹介します。

What is Yakumo?

背景

Yakumoプロジェクトは2018年1月にスタートした、米国市場向けのkintone.com開発プロジェクトです。 現在米国市場向けにリリースしているkintoneは日本のcybozu.comと同じ基盤で提供しています。 そのため海外からレイテンシが大きいという問題や、販売管理システムを共通して使っているため米国市場向けの施策が打ちにくいといった課題があります。 そこで米国を含むグローバル市場向けにkintoneの価値を早く提供できるよう、今の日本のインフラからkintone.comを切り出して別のインフラで提供することにしました。 Yakumoプロジェクトは現在のkintone.comのAWS移行プロジェクトになります。

更に詳しい背景情報は以下の資料をどうぞ。

Yakumoプロジェクトの技術的な挑戦

Yakumoプロジェクトはビジネス面だけでなく、技術面や開発体制も新たなチャレンジが多いです。 今のcybozu.comではデプロイ作業がSREチーム任せになってしまっているため、SREチームとアプリケーション開発チームとの間でノウハウが分断してるという課題があります。 また長年蓄積されたレガシーシステムが多く、新しいリリースフローの導入も容易ではありません。 そのためYakumoでは他の製品に先駆けて、新たなDevOpsQAな開発フローにチャレンジしています。 国内のインフラに関しては、刷新プロジェクトNecoが別に進んでいます。

Yakumoプロジェクトはまず、チーム編成を技術レイヤーで分断しない構成にしました。 そのためにチーム内で開発・テスト・運用までのフローが完結できる体制づくりにチャレンジしています。 単体テストから受入試験まで自動で実施して、その後のデプロイもas codeとして形にしています。 元kintone開発者やSREを含めて全ての開発者が各フローに携われるようになってます。

この記事では、Yakumoの開発環境と構築したデプロイパイプラインについて紹介します。

Yakumoの開発環境

YakumoプロジェクトではkintoneをAWS上に構築します。 そのために販売管理システムを米国向けに作り直し、非同期ジョブやサービスディスカバリなどのミドルウェア群もAWS上で利用できるよう移植しました。 またMySQLやオブジェクトストレージにAWSのマネージドサービスを利用しています。 kintone本体やkintoneが利用する各ミドルウェアは、Amazon Elastic Container Service for Kubernetes (Amazon EKS) を使ってKubernetesクラスタにデプロイします。

Yakumoチームでは複数のサブチームに分かれて開発を進めています。 開発速度を上げるために、それぞれのサブチームごとに独立した環境を用意しています。 この独立した環境をYakumoではPlaneと呼んでいます。 たとえばIgaチームは用意されたIga Plane上で開発を進めます(Yakumoのサブチームは忍者の隠れ里から命名されてます)。 masterブランチにマージされた成果物のためにMaster Planeを用意してあり、Master Planeではドッグフーディング用のkintoneがデプロイされています。

各Planeは1つのAWSアカウント内に同居して、それぞれのPlane間はネットワーク的に分離されています。 仮にPlane上の環境を壊したとしても、他の開発者に影響が無いので安心して開発を進められます。

Yakumoの開発環境

デプロイパイプライン

PlaneへのデプロイはCircleCIによって自動化されており、pushされたらデプロイが自動で開始します。 そのため人の手によるデプロイ作業はほぼ無く、GitHub上にマージしてしばらく待てば、利用可能な環境が用意されます。

YakumoのCloudFormationや全てのミドルウェアはモノレポで管理しています。 各Planeのブランチへのpushがデプロイのトリガーになっています。 たとえばIga Planeにデプロイするには、igaブランチに変更をマージしてpushします。 開発はトピックブランチを作成して、それぞれのPlane環境で動作が確認できればマージというフローにしています。

現在のデプロイパイプラインは以下のようになっています。 それぞれのステップについて順を追って説明します。

YakumoのCircleCI Workflow

各ミドルウェアのビルド

この段階ではミドルウェアごとにビルドジョブを分離して、それぞれ並列に実施します。 各ミドルウェアで単体テストが通過すれば、成果物をDockerレジストリやS3にアップロードします。

ビルドでできあがった成果物は、ソースコードのハッシュ値を付けてアップロードします。 例えばDockerイメージはイメージタグにハッシュ値を、Lambdaの場合はS3のキー名にハッシュ値を利用します。 各ミドルウェアにバージョンという概念が存在せず、常にpushした最新の成果物がAWS上へデプロイ可能になります。

CloudFormationの適用

次のステップはCloudFormationの適用です。 CloudFormationはスタック単位でPlaneごとに分離して、別々のRDSやEKSクラスタを構築します。 Plane間で共有してるリソース(IAMや外部サービスのトークン)以外は、互いのPlaneには変更の影響しません。 またネットワーク的にも分離されています。 そのため開発時のCloudFormationの実験や更新も、他の開発者に迷惑をかける事なく実施できます。

CloudFormationは適用時間短縮のために、一定の単位でファイルを分割して、複数のCloudFormationを並列して実行します。 それぞれのCloudFormation間で依存関係があるので、YAMLをパースして依存関係にそった順序で適用するツールを作りました。

Kubernetes上にデプロイ

この時点で各PlaneごとのAWSリソースがデプロイされ、Kubernetesが利用可能な状態になりました。 このステップではkintoneの動作に必要な各ミドルウェアをAmazon EKS上にデプロイします。

YakumoではKubernetesマニフェストをGoのテンプレートを埋め込んだYAMLで記述して、独自のツールで生成してます。 HelmやKubernetss 1.14から標準で用意されてるKustomizeといった、Kubernetesマニフェストをカスタマイズする仕組みはいくつかあります。 しかしYakumoでは以下の理由から、テンプレートを元にマニフェストを生成するツールを作りました。

  • AWS上で生成されるID (ARN) を参照する必要がある
  • Plane名やアーカイブのハッシュ値を埋め込む必要がある

HelmやKustomizeを使っても別途ツールが必要になりそうなので、現段階ではHelmやKustomizeなどの導入はまだしてません。

テスト

ここまでのジョブで、kintoneがAWS上にデプロイされて利用可能な状態になりました。 最後のステップとして、構築した環境が正常に動作するかを試験します。 このステップでは自動化したE2Eテストを実際に構築した環境に対して流し、単体テストでは検知できない不具合やリグレッションを検知します。 E2EテストはKubernetes上にJUnitをコンテナ化したものと、Selenium HubおよびSelenium Nodeをデプロイすることで実施しています。

すべてのテストを流すととても時間がかかるので、一部の重要なテストケースを抜き出したスモークテストのみを実施しています。 すべてのテストケースはDailyで実行されます。

全てのスモークテストが通って不具合が無いとわかれば、開発者はmasterブランチに変更をマージします。

まとめ

この記事ではYakumoの開発環境とDevOpsQAについて紹介しました。 プロジェクトがスタートして1年ちょっとですが、開発チームが湯水のようにCircleCIを利用しており、これまでに300,000を超えるCircleCIジョブが実行されました。

まだまだ新しいことばかりで試行錯誤な部分もありますが、Yakumoの成果物やノウハウは国内の製品開発にも生かされる予定です。 国内外合わせて、ユーザーに最大の価値を提供できるようなプロダクト開発を目指していきます!