本文へスキップします。

本文へ

【全Qt】
【全・Qt】SRAロゴ
H1

技術記事:CI/CD

技術記事

アプリケーション開発に自動化を。CI/CDとは?

(掲載 2024年2月16日)

CICD

最近のソフトウェア開発プロセスでは、継続的インテグレーション(CI)と継続的デプロイメント (CD) が重要な役割を果たします。ただし、組織内で CI/CDを導入するのは困難な場合があります。特定の作業成果物やワークフローに合わせてカスタマイズする必要があるため、多くの場合、試行錯誤が必要になります。不必要な行き詰まりを最小限に抑えるために、CI/CDシステムの使用と構成に関するノウハウの一部を共有するとともに、CI/CDの必要性についてもご紹介します。



1. CI/CDとは?

1.1. なぜCI/CDなのか?

コードレビューはすでに開発プロセスに不可欠な部分となっており、コード品質向上に大きく貢献していることは広く知られています。ここで、CIプロセスがコードを追加した際の自動レビューアであると想像してください。変更がリポジトリにプッシュされるたびに、「レビュー担当者」であるCIは、ソフトウェアがすべてのプラットフォーム上で正常にビルドされ、すべてのテストに合格したことを確認してから次に進みます。CIビルドには、コンパイラの警告をキャッチし単体テストを検証するだけでなく、他の潜在的な問題を特定するための静的分析ツール (C++の場合はClangやClazyなど) やその他のリンターやサニタイザーを含めることもできます。このようにコンピューターの恩恵を受けた自動コードレビューは、すべてのプラットフォームにわたって品質と安定性を維持するのに役立ちます。これだけでも、CIをセットアップするための時間投資は正当化されます。

もう1つの側面はコードの一貫性です。開発者がIDE上で、改行、括弧/中括弧の配置、スペース、コメント、識別子のフォーマットを個別に構成するような設定をしている場合、コードベースが大規模になると、複数の異なるスタイルが混在しやすくなってしまいます。このような競合するスタイルは、コードの読みやすさや一貫性を阻害する原因となります。CIビルドでは、ツールを使用して、一貫したフォーマットがすべてのソースファイルに適用されていることを確認できます。これは、大規模で分散したチームで作業する場合に特に役立ちます。さらに、これらのツールは、変数名とコメントのスペルミスをチェックできます。CIシステム内でこれらのチェックを実行することで、自動的に同じ基準に準拠するため、人間がレビューをしてフォーマットの問題について時間をかけて議論する必要はなくなります。

最後に、開発者は自分で単体テストを実行する必要がありますが、便宜上、変更によってすぐに影響を受けるテストに集中することがよくあります。そこでCIは、開発者に2つのメリットを提供します。まず、CIシステムは制限されたセットだけでなくすべてのテストを実行するため、開発者が見逃していた可能性のある予期せぬ問題を発見することができます。次に、開発者の貴重な時間を節約できます。開発者は、必要なだけのローカルテストを実施し、コードのチェックに合格することを確認できます。CIテストは専用のCIシステムで非同期に実行されるため、包括的なテストが行われることがわかります。

1.2. CI/CIのために必要なこと

少なくとも、すべての開発者が作業する共有リポジトリが必要です。後のセクションでは、オンプレミスまたはクラウドソリューションにCIを実装する方法とその理由について説明します。ただし、オンプレミスソリューションを実装する場合は、専用のCIサーバーと、プロジェクトの規模と複雑さに応じて、複数のCIワーカーマシンが必要になります。

専任のCI担当者が必要かどうかは、選択したCIシステムによって異なりますが、専任の担当者がいた方が良いでしょう。それが不可能な場合は2,3人で分担することも可能ですが、彼らの仕事は頻繁に中断されることになります。基本的に、CIの知識と責任を全エンジニアリングスタッフに分散するシステムもあれば、専任のCIチームに集中させるシステムもあります。

使用するCIツールチェーンによっては、セットアップは非常に簡単で、簡単な場合は1~2日で完了します。例えば、GitHub Actions(および同様のクラウドベースのサービス)は、すでに構成され動作しているプリペイドサービスを提供します。ビルドに合わせてカスタマイズする方法を理解する必要がありますが、ビルドマシンを入手してセットアップする必要はありません。

一方、JenkinsやBuildbotのようなソリューションでは、サーバーのセットアップ、ソフトウェアのインストール、ワーカーマシンのセットアップ、OSのアップデートを行い、プロジェクト用にカスタマイズする必要がある。WindowsやMacのようなユーザー中心のOSは、実際にはサーバーとして実行することを想定していないので、おそらくChefやAnsibleのような自動化システムと、リブート・ログインやアプリケーションのクラッシュがCIプロセスを停止させないようにするための無人運転のための特別なセットアップが必要になるでしょう。しかし、JenkinsやBuildbotは、CI環境の完全な制御をより容易に行えるという利点があります。

適切なアプローチを決定するには、この記事のクラウドとオンプレミス、および個々のツールに関するセクションを参考にしてください。

1.3. 段階的な導入が可能

プロジェクトの開始時には、CIを効果的にするために多くのテストを行う必要はありません。前述したように、他のプラットフォームでのコンパイル、静的分析の実行、フォーマットチェッカーの実行などからも多くの価値が得られます。ただし、重要な項目を検証する少数の効果的なテストから簡単に始めることができます。テストを書くのはそれほど難しいことではありませんが、おそらく予想以上に頻繁に失敗するでしょう。テストフレームワークはシンプルなものから始め、バグを見つけ修正しながら新しいテストを蓄積していきます。

2. 一般的な適用方法

2.1. 2つのCI

うまく機能するCIシステムは、開発ワークフローの一部を自動化し、全体的な品質を大きく向上させます。しかし、CIシステムの最も重要な特性の一つはスピードです。CIビルドは高速である必要があります。コミットがリポジトリにプッシュされたら、開発者はすぐにフィードバックを得るべきです。フィードバックが遅いほど、開発者はそれを頼りにしなくなり、無視したくなるでしょう。ただ、大規模で複雑なプロジェクトでは、どれだけマシンの性能が良くてもビルドの時間はかかるものです。そこで、少なくとも2つ、夜間、そしてコミット毎のCIビルドを行うことをお勧めします。

開発者が変更をコミットするたびにいつでも実行されるクイックビルドは、事前にビルドされた依存関係やキャッシュを可能な限り利用します。また、このビルド時に実行される静的チェッカーやサニタイザーは、包括性よりも効率性重視の設定にすべきです。そうすることで、開発者は自分の変更に対するフィードバックが即座に受け取れるようになり、開発の効率が向上します。

一方、夜間ビルドはゼロから行うべきです。ソースディレクトリと空のバイナリディレクトリだけで始めます。あなたのコードにとって意味のある静的チェックを全てオンにして、必要なインストーラーとパッケージャーを全て含めます。すべての開発者が同じタイムゾーンにいる場合、夜間ビルドはクイックビルド時と同じマシンを使用することができます。或いは開発が24時間行われている場合、1日1回全体をビルドするための専用のマシンが必要になるかもしれません。

顧客と共同でテストを行うなど、開発チームが定期的にアップデートを社外と共有する必要がある場合には、そのパッケージング用に、もうひとつビルド構成が必要になるかもしれません。このビルドはゼロから行うため、クイックビルドよりも完成度が高くなりますが、網羅的なチェックを行う夜間ビルドの結果を流用することで少し軽量にすることができます。また、このビルドは開発者がオフサイトのテストチームとやり取りする際に、一日に数回実行することができます。あるいは、パッケージングの速さによってはクイックビルドに組み込むことも可能です。

2.2. CIゲートのオーバーライド

CIワークフローの開発者ツール(GitHub、Gerrit、Bitbucketなど)には通常、CIゲートチェックインというオプションがあります。このステップでは、コミットがメインブランチにマージされる前に、CIシステムが開発者の変更を検証する必要があります。これにより、すべてのコミットがコンパイラと単体テストに適切に合格することが保証されます。

ただし、開発ワークフローではCIゲートチェックインをオプションにすることはお勧めしません。開発者がCIのビルドをスキップしたり、CIの結果をバイパスしたりする習慣が身につくと、CIによって提供される価値が大きく低下する可能性があります。なぜなら、CIシステムが正しく動作しない場合、開発者がそれをオーバーライドする可能性があるためです。

例えば、CIシステムでネットワークの問題が発生したためにビルドに時間がかかりすぎる場合、開発者はCIチェックをバイパスすることを選択する場合があります。根本的なCIビルドの問題に対処するよりもチェックをバイパスする方が簡単なため、チームは最終的にCIの使用を完全に止めてしまう可能性があります。

このことは、CIシステムが信頼でき、迅速で、正確でなければならないことを強調しています。コミットごとにCI検証することを強制するためには、CIシステムが継続的な保守を受け、一貫して適切に動作することを保証することが不可欠です。

2.3. Webアプリケーション以外でのCD

CI手法には幅広い適用性がありますが、継続的デプロイメント(CD)の実装は開発の種類によって異なります。Web開発の領域でCI/CDツールの品質の良いことは注目に値します。Web開発におけるCDのプロセスは、プラットフォームが単一で配布エンドポイントが限られるため、比較的単純です。ソースコードのコミットが有効であると判断されて検証されると、変更はすぐに公開されます。

組込みやデスクトップ開発におけるCDには、いくつ特別な手順がかあります。まず、アプリケーションのダウンロード可能なバージョン、つまり、サポートされているすべてのプラットフォーム用のインストーラーやOTAパッケージを作成する必要があります。次に、それらのパッケージファイルのURLとそのバージョンを指すメタデータファイルを公開します。最後に、ユーザーによって手動で開始されるか、自動プロセスによって開始され、ターゲットマシンはパブリックにアクセス可能なメタデータファイルを参照してインストーラーまたはアップデートを見つけ、それが現在のソフトウェアよりも新しいかどうかをチェックしたうえで、ダウンロードしてインストールします。

CI/CDシステムにおけるこれらのモデルの大きな違いは、一般にデスクトップおよび組込みシステム開発では、CDをメインブランチから直接行うべきではないことです。(ターゲットが単一の非常に安定したハードウェアプラットフォームである場合は例外が発生する可能性がありますが、事前に計画しておいても問題ありません。)

必要となるブランチはいくつか考えられます:

  • 通常の作業はメイン開発ブランチで行われ、CIシステムはこのブランチから実行されます。
  • ユーザー向けのCDプロセスはより細かい制御が必要なため、テスト可能なパッケージの生成に使用される別のリリースブランチで実行されます。リリースマネージャーがソフトウェアの準備が完了したと判断すると、このブランチから正式なバージョンのリリースとしてパッケージ化されます。

2.4. クラウドCIとオンプレミスCI

クラウドベースのCIシステムを使用するべきなのでしょうか、それとも独自のオンプレミスシステムを構築すべきでしょうか?

クラウドベースのCIはそのシンプルさが非常に魅力的です。すべての作業は他の誰かが行っています。購買部門を通じてハードウェアを購入したり、IT部門と協力したり、大容量のハードディスクや強力なプロセッサを注文したり、多数のソフトウェアをすべてインストールして構成したりする必要はありません。これらがすべてサービスとして提供されているクラウドCIシステムは、すぐに使い始めることができます。

CIのニーズが急速に変化し、規模を拡大したり縮小したりする場合も同様です。新しいVMを自動的に構成したり、CIサーバールーム用に新しいマシンを取得したりするよりも、必要に応じてクラウド資産を拡大または縮小する方がはるかに簡単です。CIを迅速に強化したり、大きく拡張したりする必要がある場合は、クラウドベースのシステムを使用してください。

さらに、GitHubやGitLabなどのクラウドホスティングプラットフォームをすでに使用している場合は、GitHub Actionsなどの関連するクラウドベースのCIソリューションを組み込むことが非常に簡単になります。

クラウドはCIに参入する非常に簡単な方法ですが、考慮すべき2つの大きな要素があります。1つ目はコストです。CIシステムを実行すると、クラウド上のCPUやストレージの使用料が発生し、1日に何度も複数のクロスプラットフォームビルドが生成されることになります。クラウドプロバイダーにとっては、かなり高額な投資となる可能性があり、実際、オンプレミスを導入する最大の理由はおそらくコストでしょう。

もう1つの理由は、データプライバシーかもしれません。物理的な場所、セキュリティ手法、またはデータ処理ルールによってコードやデータの保存を制限するプライバシーとセキュリティの規制により、クラウドの使用が困難になる可能性があります。地域(例えばヨーロッパのGDPRへの準拠)、業界(軍事や医療データの取扱い要件の遵守)または自社のITやサイバーセキュリティの方針によって、厳しいデータプライバシーやセキュリティの規則に従う必要がある場合は、おそらくオンプレミスにする必要があるでしょう。

3. 解決策の検討

現時点で、3つのCIソリューションが議論の大半を占めています。他にも多くのCI/CDシステムが使用されていますが、新しいCI/CDシステムを立ち上げるチームでは、この3つのいずれかが選択肢に入ってくるでしょう。それぞれの主な違いは、CI作業が専用チームに集中しているか、プロジェクト内のすべての開発者に分散しているか、CIシステムがクラウドベースであるかどうかです。

3.1. Buildbot

Buildbotは、すべてのCI情報を一元管理するオンプレミスソリューションです。これを使えば、ビルドするプロジェクトとビルド方法を指定できます。Python、Webkit、LLVM、Mecurial、Blender、GDB、Gentoo Linux、Yoctoなど、多くの重要なプロジェクトでBuildbotが使用されています。

Buildbotは、CIソフトウェアを最新の状態に保つためにシステム管理者が必要です。ビルドマスターとワーカーの両方にVMを使用することを前提としています。独自のハードウェアを用意し、それに応じてこの環境をセットアップする必要があります。Buildbotを使用すると、ワーカー間の負荷分散と特定のワーカーへのプロジェクト固定の両方をサポートします。

Buildbotの設計には長所と短所があります。

長所:

  • シングルポイント:メンテナーは、新しい静的分析ツールの追加や新しいチェックセットに対する検証など、すべてのプロジェクトに影響を与える変更を迅速に行うことができます。
  • スケーラブル:同じツールチェーンを使用する複数のプロジェクトでは、Buildbotを使用したスケーリングが簡単です。
  • 柔軟性:このシステムは非常に設定しやすく、チームの好みのワークフローに合わせることができます。Pythonコードを使用するため、優れた柔軟性がありますが、簡単なユースケースに合わせてセットアップすることも容易です。

短所:

  • メンテナー:Buildbotには、設定を簡単に制御するためのユーザーフレンドリーなWebポータルがなく、その代わりにコードや設定ファイルを変更する必要があります。つまり、システムを効果的にメンテナンスするには、専任のBuildbot担当者またはチームが必要になります。
  • 複雑さ:柔軟性には複雑さ伴います。プロジェクトの数が増えるほど、設定の複雑さが急速にエスカレートし、セットアップに対する技術的な要求が厳しくなってきます。
  • SaaS非対応:Buildbotは、個別のサーバーを作成できるにもかかわらず、プロジェクトやユーザーを個別のアクセスグループに分けるなど、複数の外部クライアントにサービスを提供するために必要なコンセプトがサポートされていません。

全体的に、Buildbotは(言語、フレームワーク、依存関係の点で)多くの類似したプロジェクトを扱い、簡単にスケールする必要がある場合に優れたツールです。Buildbotは、ワークフローでは一貫性があるが、依存関係では比較的ユニークなプロジェクトが多数ある場合に適しています。ただし、この場合、Jenkinsも実行可能な代替手段になります。これについては次に説明します。

3.2. Jenkins

Jenkinsもオンプレミスソリューションです。BuildbotのCIコンフィギュレーションへの集中型アプローチとは異なり、Jenkinsはビルドを駆動するコンフィギュレーションファイルのセットとして、CI情報をソースリポジトリ全体に集中させたり配布したりする柔軟性を提供します。Jenkinsは、FaceBook、Netflix、Udemy、Twitchなどの企業でも広く使われています。

Jenkinsはいくつかの点でBuildbotに似ています。Buildbotと同様に、非常に単純なユースケースでない限り、Jenkinsにはシステムを管理する管理者が必要です。ビルドマスターとワーカーの両方にVMを使用し、Buildbotのセットアップに必要な作業と同様に、必要なハードウェアを提供し、環境を設定する責任があります。さらに、オンプレミスとクラウドの両環境をサポートし、環境間でタスクの負荷を分散したり、タスクを特定の環境に固定したりできます。

柔軟性と使いやすさを考慮すると、2つの環境の違いが明らかになり始めます。

長所:

  • 非集中型:集中型のCI構成も可能ではありますが、必須ではありません。非集中型であれば、Jenkinsでは開発者がプロジェクト単位でCI設定を簡単に変更できます。
  • さまざまなツール、言語、ライブラリ、プラットフォームのセットを備えたプロジェクトが多数ある場合、プロジェクト内のCI構成も簡単になります。
  • オンプレミスでの使いやすさ:Jenkinsはプラグアンドプレイのセットアップを提供するために、柔軟なプラグインアーキテクチャを採用することで、一般的なユースケースでの使用が容易です。そのシンプルさは、Jenkinsの深い知識を持つ人が使用する場合に特に顕著になります。プロジェクトとビルド設定を管理するためにクリーンなWebインターフェースを使用しているため、単純なユースケースでは専任の担当者すら必要ないかもしれません。
  • SaaS対応:Jenkinsは、ユーザー管理、セキュリティ、可視性に関する堅牢な機能を提供し、複数のクライアントまたは顧客を含むプロジェクトをサポートするCI/CD環境を構築することが可能です。

短所:

  • 変更:CIコンフィギュレーションは(多くの場合)ソースツリー全体に分散しているため、グローバルな変更を一貫して実装するのが難しい場合があります。
  • スケール:同様に、Jenkinsは複数のプロジェクトを追加したり変更したりするときに、スケールが難しくなることがあります。
  • 適応性:すべての設定が最初から提供されるわけではなく、プラグインがすべてのユースケースをカバーしているわけでもありません。必要なものが既存のワークフローから外れている場合は、プラグインのカスタマイズや修正が必要になります。この場合、Jenkins固有のスクリプト言語であるGroovyを使用することになります。Groovyは柔軟性がありますが、Buildbotで使用されるPythonコードほど便利ではありません。

Jenkinsは理解、設定、使用が簡単なので、「CIを始めたばかりで、オンプレミスのソリューションが必要な」場合に最適なツールです。Jenkinsは、ワークフローには一貫性があり、依存関係では比較的独特なプロジェクトが多数ある場合に適しています。Jenkinsはその動作方法に関してより「こだわりが強い」ため、明確なワークフロー要件を持つ多くのプロジェクトを抱えるチームでは使いにくいかもしれません。Jenkinsのセットアップには専任のCI担当者を置かなくて済むかもしれませんが、専任の担当者(またはチーム)がいると大きなメリットが得られるという点ではBuildbotと似ています。

3.3. GitHub Actions

GitHub Actions(GHA)はクラウドベースのCIソリューションで、GitHubユーザー向けのオプションであり、GitHubがフリーミアムオプションとして提供しています(オープンソースは無料、プライベートリポジトリは有料)。Jenkinsのように、プロジェクトに含まれる設定ファイルを使用します。

長所:

  • 使いやすさ:GHAは使い方が簡単で、GHAは使い方が簡単で、よくある問題を処理するための環境やスクリプトがにあらかじめ用意された、初心者にとても優しいソリューションです。
  • 公開プロジェクト:GHAは完璧に理にかなっており、オープンソースプロジェクトに貢献し、CIシステムを必要としている人に最適です。
  • メンテナンス:保守作業はクラウドサービス経由で行われるため、専任のCI担当者は必要ありません。

短所:

  • プラットフォーム:GHAはGitHubのエコシステムに縛られているため、オンプレミスのソリューションが必要な場合、GitHub以外のシステムを使いたい場合、またはリポジトリプラットフォームに柔軟性が必要な場合はGHAを使うことはできません。
  • コスト:JenkinsやBuildbotがオープンソースで自由に利用できるのに対し、GHAはプライベートリポジトリで利用するためには費用がかかります。

GHAは、CIを始めるために最も簡単な方法を提供します。組織外からもコードの貢献を受け付けるプロジェクトの場合は、オープンソースプロジェクトに最適なGHAの使用を検討するとよいでしょう。(これは、CIシステムがビルドプロセスの一部としてユーザーがサブミットしたコードを実行できるためでもあります。安全でない可能性のあるコントリビューションはすべてサーバー環境に封じ込める必要があります)ただし、GHAには、民間企業にとって使いづらい制限があります。また、ここではGitHub用のGHAについてのみ説明しましたが、GitLab用のGitLab CI/CDやBitbucket用のBitbucket Pipelinesなど、他の多くの一般的なリポジトリ・プラットフォームにも同様の長所と短所を持つ同様のソリューションがあります。

3.4. CIヘルパー

デスクトップや組込み開発向けの注目すべきツールがいくつかあります。これらは明示的にCIソリューションとして設計されたわけではありませんが、CIプロセスの合理化に大きく貢献しています。

  • cmake-presets:複数の異なるビルド構成を作成できるようにすることで、CMakeビルドツールの機能を強化します。CMakeは、環境変数、依存関係の場所、ビルドが必要なファイルやモジュールの設定により、ビルドの構造を定義します。CMakeプリセットを使用すると、ビルドプロセスのさまざまな部分を異なるプリセット構成に整理することができます。これにより、CIに特化したビルド構成を作成し、標準的な開発者のビルドプロセスと並行して使用することができます。この機能は、環境の多くを複数のビルドタイプで共有するような大規模プロジェクトで特に役立ちます。
  • pre-commit:Gitのpre-commitフックを管理するためのフレームワークで、ファイルがコードレビューのためにサブミットされる前に特定の処理を実行できるようにします。これを使用して、静的コードチェッカーやコードフォーマットツールをセットアップし、開発者のコンピュータ上でそれらの機能を実行して迅速に対応できます。このアプローチにより、CIシステムの負荷が大幅に軽減されます。


SRAでは、CI/CD環境の構築サービスを提供しています。ご興味ある方はSRAの営業担当もしくは問合せページまでお気軽にご相談ください。


出典:KDAB's Software Development Best Practices: CI and CD
KDAB日本語トップページ