Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Sansan CI チームの CI (継続的インテグレーション)

はじめに

こんにちは。Sansan 事業部 プロダクト開発部 CI チームの 中田 です。

突然ですが、CI チームと聞いてどんな仕事を想像しますか? 一般的に IT 分野で CI というと 継続的インテグレーション (Continuous Integration) の略です。 ところが Sansan では違います。Sansan で CI というと Sansan Customer Intelligence (Sansan CI) というものを指し、継続的インテグレーションとは全くの別物です。そして、この Sansan CI の開発を担当しているのが私たち CI チームです。 この Sansan CI がどういうものかは次で軽く紹介しますが、本記事では Sansan CI チームで 継続的インテグレーション をどう実現しているかについての話をしようと思います。

Sansan CI の紹介

Sansan CI というのは、Sansan の名刺を名寄せする技術を応用し、名刺データはもちろん、Salesforce をはじめとする外部サービスの様々なデータを統合し、総合的な顧客データベースを提供することを目的とした Sansan の新機能です。2017 年後半から開発が開始され、2018 年 2 月にサービスインしました。

Sansan CI のアーキテクチャ

製品としては Sansan の機能として位置付けられている一方で、システム的には Sansan 本体からは独立しています。そもそも使用しているクラウドプラットフォームからして違います。Sansan 本体は AWS ですが、Sansan CI は Microsoft Azure です。

f:id:Nakatsuchi:20190129193801p:plain:w400

ゼロベースでシステムを構築するにあたり、Sansan CI では Function as a Service (FaaS) を全面的に使用したクラウドネイティブなアーキテクチャを採用しました。FaaS といえば AWS の Lambda が有名ですが、Azure にも Azure Functions という FaaS サービスがあります。これほど Azure Functions を積極的に使い込んだシステムは他にあまり多くの例がないのではないかと思います。

また、Azure には一般的な Web アプリケーションを簡単に動かせる Azure App Service という PaaS サービスがあります。Sansan CI の目に見える Web GUI の部分にはこの App Service が使用されています。

継続的インテグレーション

露骨な言い方をすれば、継続的インテグレーションとは、ソースコードの統合、ソースコードからの成果物のビルド、そして成果物の運用環境へのデプロイという一連の作業を自動化することです。それによって、開発成果のリリースにかかる手間を軽減し、リリースサイクルを早めることができます。継続的インテグレーションには大抵専用のツール (以下CIツール) が使用されます。有名なものとしては、Jenkins や Circle CI などがあります。

Azure Pipelines の利用

Sansan CI ではCIツールとして Azure Pipelines を採用しています。この Pilpelines は Azure DevOps Services というクラウドサービス群のうちの一つです。Azure DevOps Services は Azure の一部として改名される以前は Visual Studio Team Services (VSTS) と呼ばれていました。実は Sansan CI は Microsoft Azure を使用しており、当初 Pipelines の前身である VSTS を採用したのは同じ Microsoft のツールなら無難だろうとの理由からです。

Pipelines は CI/CD ツールとしてのビルド、テスト、デプロイという一連の機能を備えています。Sansan CI のサービスイン当初から使用してきましたが、特に大きな不都合を感じたことはなく、優れたツールだという印象です。具体的な良い点としては、

  • ビルドやデプロイのための設定が容易です。私は Sansan CI チームに入るまで CI/CD ツールを一から設定して使った経験がなかったのですが、特に苦労なくパイプラインを作れてしまいました。
  • Azure Functions や Azure AppService へのデプロイが簡単に行えます。外部のプラグインなどは必要なく、リストからデプロイ先のサービスを選ぶだけです。アプリケーションの開始・停止など、様々な Azure のオペレーションもデプロイ時に行えたりします。
  • C# (.NET) のサポートが強力です。他のツールでは冷遇されることの多い C# ですが、Azure ファミリーだけあってネイティブで対応しています。もちろん C# の他にも Node.js や Java など、メジャーなプラットフォームには一通り対応しています。
  • マネージドサービスのため、サーバーのセットアップや運用の手間がありません。また、お金さえ払えばいくらでも並列でビルドやデプロイを実行できます。

といったところです。

Sansan CI は FaaS を多用したアーキテクチャを採用しているため、デプロイ対象のアプリケーションの数が多く、今でもどんどん増え続けています。そのうえ、まだ若いシステムですのでインフラにも頻繁に変更が加えられており、その度にデプロイの設定変更が発生します。そのような事情から、ビルドとデプロイの設定追加や変更が容易に行えることは特に重要でした。

Sansan CI のビルドとリリース

ビルド

Azure Pipelines によるビルドは、ビルドを行うための設定を「ビルドパイプライン」として定義しておき、そのパイプラインを実行してソースコードから「ビルド」と呼ばれる成果物を生成します。一つのビルドは複数のアプリケーションパッケージを含むことができます。次の図は Azure Functions で実行させるための C# アプリケーションのビルドパイプラインの例です。

f:id:Nakatsuchi:20190129203831p:plain
ビルドパイプラインの例

Sansan CI の場合、Azure に対して小さな複数の Function アプリケーションを一度にデプロイする必要があるため、関連する複数の Function アプリケーションをまとめて一つの Git リポジトリに入れています。そして、原則として Git リポジトリごとに一つのビルドパイプラインを定義し、リポジトリ全体から一つのビルドを生成しています。複数のアプリケーションを含むリポジトリであったとしても常にリポジトリ全体を一度にビルドします。リポジトリのバージョンとビルド成果物のバージョンが常に一致するようにしておくことでバージョン管理がシンプルになるからです。Sansan CI ではリポジトリを比較的小さく分割しているため、リポジトリ全体のビルドにかかる時間は問題になりません。

ビルドパイプラインは以前は Azure Pipelines の画面上で GUI で定義していましたが、現在は YAML ファイルを使用したパイプライン定義がサポートされたためテキストベースに移行しました。作成した YAML ファイルはそれぞれビルド対象のリポジトリにチェックインされています。ソースコードと一緒にビルドパイプライン定義を管理することによって、ソースコードとパイプライン定義の間のバージョンの不整合が起きにくい形になっています。

リリース

Azure Pipelines によるリリースは、本番環境やステージング環境などリリース対象となる各「ステージ」へデプロイを行うための設定を「リリースパイプライン」として定義しておき、パイプラインとビルドを関連付けた「リリース」を作成します。そして、そのリリースを各ステージに実際にデプロイしていきます。先に説明した通り Azure Functions へのデプロイでは複数の Function アプリケーションを一度にデプロイする必要があるため、一つのリリースパイプラインの中でビルドに含まれる複数のアプリケーションパッケージを一度にデプロイするようにパイプラインを定義しています。次の図は Azure Functions へのデプロイを行うリリースパイプラインの例です。

f:id:Nakatsuchi:20190129213152p:plain
リリースパイプラインの例

この図のパイプラインでは、まずステージング環境へデプロイした後、人間による手動のリリース承認を経てプロダクションにデプロイされるようになっています。このように、リリースを許可するための条件を定義することも可能です。

Azure Pipelines の機能としては複数のビルドから一つのリリースを作ったり一つのビルドから複数のリリースを作ったりすることもできますが、今のところ、Sansan CI では一つのビルドに対して一つのリリースを作るようにしています。特に拘りがあってそうしているわけではなく、今後例えばドメインAをデプロイした後にドメインBをデプロイしなければならないといった複雑な考慮が必要になれば変わっていくと思います。

一方、Web アプリケーションをデプロイする場合は、リリース時に次の図のステップを自動的に実行するようにパイプラインを定義しています。 1. デプロイ用のスロット (App Service の機能で、アプリの複数のバージョンを一つのサイトにデプロイできる) を起動する 2. デプロイ用のスロットに対してアプリケーションをデプロイする 3. デプロイ用のスロットと本稼働用のスロットを入れ替える 4. デプロイ用のスロットを停止する こうすることにより、デプロイ時に Web サイトが応答しなくなるのを回避しています。実際の設定画面は下のようになります。わかりやすいですね。

f:id:Nakatsuchi:20190129214056p:plain:w300
実際のデプロイ設定画面

リリースパイプラインは Azure Pipelines の GUI で定義しています。ビルドパイプラインの YAML ファイルでデプロイまでしてしまうことも可能ですが、そこまではやっていません。デプロイはインフラの変更や運用対応の影響を受けて設定を変更するケースが多く、ソースコードとはライフサイクルが異なっているためです。

おわりに

Sansan CI での継続的インテグレーションの実践について紹介させていただきました。 いろいろと格好付けたことを書いてしまいましたが、CI ツールを触るときには必要以上に凝りすぎないように気をつけるのが大切だと思っています。特に Sansan CI はまだまだ変化の激しいフェーズですので、パイプラインのメンテがプロダクトの進化の足枷にならないようにバランスを意識していきたいです。

© Sansan, Inc.