「私たちは社内すべての CI ユースケースに使えるマネージドソリューションを探していました。また、実行するソフトウェアや使用するツールを管理するためのセルフホスト型エージェントも必要としていました。セルフホスト型エージェントが搭載された TeamCity Cloud は当社の 300 人を超えるエンジニアチームが喜んで活用しており、当社の生産性をレベルアップするカスタムメイドのソリューションを提供してくれました」
— Ivan Babiankou、Picnic ソフトウェアエンジニア
Picnic でスタッフソフトウェアエンジニアを務めている Ivan Babiankou と申します。現在は Java プラットフォームチームのメンバーです。以前の CI ソリューションの後継となるソリューションの選定と移行作業に従事していました。
Picnic は人が食品を購入する手段に革命を起こしています。オランダの 1 つの都市からスタートした Picnic ですが、現在では、ドイツ、フランス、オランダの 200 を超える都市でサービスを提供しています。Picnic は物理店舗を使用しないアプリオンリーのアプローチを採用しているため、何百万人ものユーザーが迅速かつ容易に食品を購入できています。
当社ではユーザー向けのモバイルアプリ以外にも、倉庫管理用の社内ソリューションを含む業務に不可欠な他のシステムの大部分を制作しています。また、ドライバーの配送ルートを計画したり、安全運転を支援したり、倉庫内で注文品のピッキング作業を行う際の経路を最適化したりするツールもすべて制作しています。
現在、Picnic には 300 人の開発者が在籍しています。社内のテックスタックには、GitHub、Java、Python、Swift、Kotlin、TypeScript、Angular、React、Android、iOS、MongoDB、Spring Boot などがあります。
JetBrains の TeamCity に関心を持つようになったのは 2021 年の終わりです。以前の CI ソリューションでは対応しきれなくなっていたことがきっかけですね。ビルドが遅い、ビルドキューが長い、という 2 つの大きな難題に直面していました。一番長いときでは、ビルド実行開始までの待機時間が 1 時間に達していました。
前のソリューションでは、主にビルドエージェントの数とサイズを大幅に増やしてビルドの合計時間を減らすというやり方でこの状況に対応しようとしていました。ただし、このソリューションではビルド速度に関する根本的な問題を解決できなかったため、この状況に適応できるものではありませんでした。そこで、より効果的でスピーディなソリューションを新たに探すことになったのです。
私たちは当社のテックスタックを全体的にサポートし、ビルドとアプリケーションテストの手法を標準化するのに役立つシステムを CI ソリューションの代わりに探していました。当社では、バックエンドのアプリケーション開発には Java と Python、社内の VCS には GitHub、モバイル開発には Kotlin、Swift、React Native を使用しています。
当初は 10 社のソリューションプロバイダーが候補でしたが、CircleCI、 TeamCity、GitHub Actions の 3 社に絞り込みました。一番の目標はキュー時間を最小限に抑えることと、ビルド時間を短縮することで CI のパフォーマンスを改善することでした。
また、セルフホスト型エージェントを使うという要件もありました。古いソリューションでは解析中にエージェントのツール一式をすばやくアップグレードできないことに気付きました。ビルドのたびにツールのインストールに 2~5 分もの時間を費やしていたのです。普通のビルドに 9 分程度かかることを考えると、その前の段階でさらに 3 分も使ってインストールすることには納得できませんでした。私たちが最新のツール一式や適切なパフォーマンス、ビルド作業を開始するのに必要なすべてが揃ったセルフホスト型エージェントを用意するという考えに最終的に至ったのは、そのような経緯があったからなのです。
CI ソリューションがクラウドにあるという点も、私たちにとっては外せない条件でした。Picnic では管理対象システム数を極力減らす努力をしています。CI を導入するなら自分たちで実行しなくて済むマネージドソリューションが欲しいと考えていたのです。また、クラウド内にセルフホスト型エージェントがあれば、自分たちが実行するソフトウェアや使用するツール一式を管理できます。そうすれば、使用するハードウェアからプレインストールするツールまで、ビルド環境全体を柔軟に管理できるようになるだけでなく、CI サーバーを管理する必要がなくなるのです。
当社の CI ユーザー数は約 300 人で、その多くは 200 件ほどのプロジェクトで活発かつ集中的にコミットしています。これらのプロジェクトでは TeamCity の極めて階層的な構造が採用されており、VCS ルートの数は 120 を超えています。
次に、当社には最大 40 件の並列ビルドに対応する 40 個のビルドエージェントがあります。毎日 1,100 件近くのビルドを実行し、1 日のビルド時間はトータルで 10,000 分近くに及びます。エージェントのスピンアップに要する時間は 2 分程度で、ビルドのキューがそれ以上長くなることは滅多にありません。
1 か月のビルド時間は、合計約 300,000 分に及びます。
TeamCity はすべての社内開発に使っています。プルリクエストを GitHub で開くと、CI がそれをビルドし、ユニットテスト、統合テスト、コンポーネントテストを実行してからフィードバックを表示します。TeamCity の役割は大体そこまでです。TeamCity はビルドアーティファクトを生成する段階まで使用されます。その後、アーティファクトはリポジトリにプッシュされて後のデプロイに使用されます。
すべての Linux エージェントと通常のビルドエージェントは、当社のクラウドプロバイダーである AWS で稼働しています。iOS アプリケーションに関しては、当社には社内ネットワーク経由で TeamCity に接続されている Mac mini が何台かあります。実は、iOS チームは TeamCity Cloud に移行する前からすでに TeamCity を現場で使用していたのです。
私たちはオンデマンドインスタンスでエージェントを実行しています。スポットインスタンスは今でも将来的な改善に使える魅力的なオプションであることには変わりありません。
私たちは独自のイメージを作成し、TeamCity のクラウドプロファイルを使用して複数のセルフホスト型エージェントを実行しています。これらのエージェントは実際には AWS の EC2 マシンです。当社では TeamCity と Packer を使ってエージェントの AWS イメージをビルドしています。
さらに、TeamCity でこれらのエージェントを起動テンプレートとクラウドプロファイルと併せて使用し、オンデマンドでビルドエージェントを起動しています。現在ではエージェントの存続時間は短く、単一のビルドにのみ使用されています。
私たちはキュー時間が 2 分もあり、そのうちの 1.5 分は AWS でのビルドエージェントのプロビジョニング完了待ち時間であることに気付きました。永続的で再利用可能なエージェントがあればこの問題に対処できます。それを念頭に置いて、スポットインスタンスを考慮していきたいと思います。
当社では TeamCity の UI で編集することを禁止するポリシーを採用しています。当社はパイプラインの標準化を目標の 1 つに掲げているため、構成をコードして使用することでそれを実現しています。
すべてのビルド構成は、それぞれのリポジトリに Kotlin コードとして格納されています。当社は TeamCity の Kotlin DSL をベースに独自の DSL を構築しました。その結果、20 行以内のコードでパイプラインを定義できるようになりました。
たとえば、Java アプリケーションをビルドするメインビルドが出来上がります。すべてのテストとコンポーネントテストが実行され、何も問題がなければビルドアーティファクトが適切なリポジトリにアップロードされます。
それ以外にも、コードの静的分析を行う別のジョブと SonarCloud で使用されるコードのナイトリー静的解析を行うジョブもあります。これらはすべて標準パイプラインの一部です。Java アプリケーションでパイプラインの基本的な要素だけを定義した場合は、標準的なパイプラインを初めから利用できます。
当社には大量のコンポーネントテスト(BDD)を実行するチームもいます。このようなテストは Python で記述していますが、メインアプリは Java で記述しています。アプリは Docker イメージにパッケージされています。また、実際のインフラ(データベースなど)を使ったビルドエージェントで Docker Compose 環境を起動してますが、サードパーティサービスはモックされています。動作テストは Docker Compose で稼働しているアプリに対して実行されます。
TeamCity が提供する Kotlin DSL では、自由に細かな調整を加えながらパイプラインを構築できます。ステップやトリガーなど、さまざまなものを変更できます。
当社では、プラットフォームチームが最高とみなすパイプラインをチームに提供するようにしています。たとえば、コンポーネントテストを同じエージェントのビルドパイプラインに組み込んだり、同じジョブに組み込んだりして実行しています。
非常に多くのコンポーネントテストを行うチームもいますが、残念ながらテストは並列化されていません。このような場合は、動作コンポーネントテストを複数のテストスイートに分割し、ビルドチェーンとして構成することを許可しています。
上記のようにメインビルドがアーティファクトを生成し、ユニットテストや単純で高速なテストを実行しています。これがうまくいけば、別々のエージェントで複数のインスタンスを使ってテストを実行する並列テストスイートを必要なだけ実行できます。
私たちが TeamCity について最も気に入っている点をお伝えします。
ビルドエージェントのデフォルト設定。当社は TeamCity に関心を持ち始めたとき、そのシステムが SSD を装着して処理能力が最適化されたエージェントを使用していることに気付きました。これにより、他の CI と比較して最高のパフォーマンスが提供されています。当社では提供されているエージェントを使用していませんが、このことは当社独自のエージェントに処理能力が最適化されたインスタンスを使用するきっかけとなり、パフォーマンス改善につながりました。
パフォーマンスモニター機能もかなり気に入っています。このようなパイプラインを実際に使用するチームはインスタンスのサイズを小、中、大のどれにするかを決めるのに非常に悩んでいましたが、パフォーマンスモニターが提供する有用なインサイトを頼りにデバッグ作業を手軽に行えるようになりました。
一方の難点についてですが、TeamCity でビルドするプロジェクト全体のメトリクスがあれば非常に助かります。なぜなら、現在 TeamCity ではメトリクスがプロジェクト単位でしか提供されていないからです。たとえば、すべての Java プロジェクトのメトリクスを確認する手段がないのです。
また、Kotlin DSL は Java に不慣れなエンジニアにとっては特に習得しにくい言語であるのも事実です。
すべてのプロジェクトを TeamCity に移行したところで、ビルドエージェントやスポットインスタンスなどを使っていろいろと実験してみたいと思います。
適切な実験をするため、ビルドメトリクスを計画的に取り込んでいます。このようなメトリクスはすべて TeamCity にありますが、すべてのプロジェクトのメトリクスやその経時変化を確認できないことが大きな壁となっています。
このような情報を基にすれば、最適化をさらに進めるための意思決定を行えるようになるでしょう。真っ先に改善して集中すべきことや、微調整によってパフォーマンスがどのように改善または低下するかを判断できるということです。現在のところ、当社はこのような情報をすべて集約する外部サービスを構築することを検討しています。初期設定のままで利用できるものならなお良いですね!
また、最適化へ向けた取り組みにも着手し、永続的なエージェントを用意するか、事前にウォームアップできるエージェントのプールを導入することで、エージェントの起動にかかる無駄な時間を排除するように努める予定です。
Picnic ではエンドツーエンドのテストをさらに構築する取り組みも行っています。それもまた、TeamCity で実行するプロジェクトになります。それができたら、当社の CI/CD を完全に TeamCity に移行するかどうかを新たに検討する必要があります。
Tadeas Kriz、Brightigy 社 CTO 兼共同創設者
Space のウェブフックを TeamCity で利用することで、レビュー済みのブランチを構築して QA 向けにデプロイし、ブランチをマージする前にテストできるようになったため、コードレビューを大幅に改善することができました。 また、誰が欠勤しているかをトラッキングすることもより簡単になりました。
Piotr Polus 氏、フロントエンドテックリーダー、Miquido
当社が JetBrains を選んだ理由は、使いやすさ、構成の柔軟さ、プラグインの入手しやすさの 3 つです。
Wooseong Kim、Tangunsoft APAC 地区チャネルリードおよびパートナーシップマネージャー
JetBrains を使うと、無駄のないプロレベルの、メンテナンス可能なコードを最高の品質で記述することができます。