2022年2月7日

Continuous Integration

CIの近代化:実際にどのように行うのか

継続的インテグレーション(CI)は、コードのチェックインやマージなどの何らかのイベント、または定期的なスケジュールによって起動される自動ビルドです。ビルドの最終目標はどこかにデプロイされることであり、CIの主な目標は、そのデプロイ可能なユニットをビルドして公開することです。

Continuous Integration illustration

 

残念ながら、コンピューターは人間のように言葉を理解することはできません。あなたのアイデア(ソースコードなど)を一般の人の手に届けるためには、ある種のビルドやパッケージングが必要です。ビルドの中では、ソースコードが機械で利用可能な形式に変換/コンパイルされます。通常、プログラミング言語には、ビルドのコンパイルとパッケージングを支援するビルド専用のツールがあります。 

ローカルな開発環境では、エンジニアは、品質保証のためにその機能を準備する前に、デプロイ可能なユニット全体のサブセットとなり得るローカルビルドを数十回作成するかもしれません。しかし、ソフトウェアは、真空の中で書かれるものではありません。最終的には、個々のエンジニアの作業は、より大きなチームの作業に統合される必要があります。こうして、CIの幕が開いたのです。

CIとは、コードのチェックインやマージなど、何らかのイベントをトリガーとして、あるいは定期的に行う自動ビルドのことです。ビルドの最終目標はどこかにデプロイされることであり、CIの主な目標は、そのデプロイ可能なユニットをビルドして公開することです。CI以外では、継続的デプロイメントや継続的デリバリー(CD)など、変更を本番環境に安全に取り込むことに重点を置いた分野もあります。

継続的インテグレーション、継続的デプロイメント、継続的デリバリーの違いとは

開発パイプラインについて語るとき、一般的な呼称として「CI/CDパイプライン」と言うことがあります。CI/CDを分解してみると、複数の分野が関わっていることがわかります。継続的インテグレーション、継続的デプロイメント、継続的デリバリーの「継続的」な部分は、この用語を束ねています。この継続的な側面は、変更の準備ができ次第、すぐに準備を整えることに重点を置いているため、基本的にはオンデマンドです。

継続的インテグレーション(CI)

簡単に言うと、CIはビルドの自動化です。しかし、ビルドにはコンパイルされたソースコードだけでなく、より多くのものが含まれることがあります。CIの最終アーティファクトは、リリース候補です。リリース候補は、デプロイされるアーティファクトの最終形態です。バグを発見し、その修正を特定するなど、アーティファクトを作成するために品質に関する手順が取られることもあります。パッケージング、配布、および構成は全て、リリース候補に含まれます。

例えば、JavaアプリケーションにはJARがあり、それはDockerイメージにパッケージされ、そのイメージが実行されるために必要な全ての環境設定が利用可能です。エンジニアは、Jenkins、CircleCI、Travis CI、Bamboo、Gitlab CI、Harnessなど、CIパイプラインを作成するためのツールを使用しています。DevOpsツールの比較ページで、ツールの包括的なリストを見ることができます。左側のCIツールでフィルタリングしてください。

継続的デプロイメント

ソフトウェアをデプロイする行為とは、ビルド/リリース候補の配布とインストールを指します。最近の分散型アプリケーションでは、アプリケーションノードの宛先やインスタンスが1つしかないことはありません。パフォーマンスや可用性の理由から、サービスは通常、クラスターにインストールされるか、複数の場所にインストールされるでしょう。継続的デプロイメントとは、最も抵抗の少ない方法で、できるだけ早く変更をデプロイし、利用可能にすることです。これは、特に厳密さを求める前の低レベルの環境には最適な方法です。

継続的デリバリー(CD)

ソフトウェアを提供することは、継続的な意思決定と見なすことができます。あなたのアイデアを安全な方法で生産に移すには、テストと承認という形で自信を深める練習をし、カナリアデプロイメントのような安全なデプロイメントの仕組みが必要です。継続的デリバリー(CD)とは、ユーザーに対して変更を自動で提供する機能です。CDには、監視、検証、変更管理、通知/ChatOpsなどの自動化プラクティスが含まれ、学際的なものとなっています。デプロイするためのアーティファクトがなければ、デプロイはできませんが、CIはデプロイするためのアーティファクトを提供します。

なぜCIを使用するのか

今日のソフトウェアエンジニアリング組織では、デプロイや継続的な検証(例えば、開発環境から品質保証環境へ)が可能なアーティファクトを持つことは賢明です。ソフトウェア技術者の仕事の主なアウトプットは、本質的に反復的です。実行可能なリリース候補が作られるまでに、いくつかのアーティファクトが作られることがあります。オンデマンドで構築し、統合と品質の道のりを歩むことができるのは、1日に何度も起こりうるビルドからです。「継続的インテグレーション入門」の共著者であるPaul Duvall氏によれば、CIは一言で、品質を向上しリスクを低減します。

cicd_pipeline_infograph

 CIのメリット

CIのアプローチにより、チームは手作業によるビルドの負担から解放され、ビルドの再現性、一貫性、可用性を高めることができます。ソフトウェアエンジニアリングチームの主要な作業アーティファクト(デプロイ可能なユニット)を定期的にデプロイできるようにすることは、ソフトウェアデリバリーライフサイクル全体にとって有益であり、共通のボトルネックを回避することによってエンジニア間の一貫したコラボレーションを可能にします。

再現性

開発者がローカルで実行するだけでなく、ビルドを外部化することで、ビルドのステップに多くの目が向けられるようになります。CIの構成は、 属人的なアプローチではなく、より広いチームが使用する資産となりえます。システムによって実行されるビルドは、繰り返し可能であり、一貫性を持たせることにつながります。

一貫性 

一貫したビルドを行う能力は、CIの主要な柱の1つです。反復可能なビルドができた後、CIがチーム内で成熟してくると、効率性と一貫性が向上します。一貫性があれば、ビルドをより簡単に利用できるようになります。

可用性

チームが必要とする同時ビルドの需要に合わせて拡張できること、そしてビルドを再作成できることが、ビルドの可用性になります。最新のコンテナ化されたビルドでは、アプリケーションバイナリーをビルドするだけでなく、より多くの馬力を必要とします。分散ビルドシステムは、それらのビルドの可用性を高めることを可能にします。ビルドは繰り返し可能で一貫性があるので、現代のソフトウェア開発の中核となるのは、プロセスのどの段階でも繰り返し可能であるとの考え方です。古いビルドや以前のバージョンも、過去のレシピを呼び出すだけで利用できるようになります。いつでもビルドを利用できることに重点を置くと、広範な技術をサポートするための課題が発生する可能性があります。

CIの課題

ビルドやリリース候補は、新しい言語、パッケージ、アーティファクトのテストパラダイムなど、開発技術の進歩に密接に追随するため、CIを実装して機能を拡張することは困難な場合があります。コンテナ化の導入時(Kubernetesコンテナについてもっと知る)技術革新のスピードが速くなるにつれて、建造に必要な火力も大きくなっています。

CIプラットフォームのスケーリング

「全てのコミットがビルドの引き金になるべき」というマントラに合わせてビルドの速度が上がると、開発チームでは、チームメンバー1人当たり1日に数回のビルドを生成する可能性があります。最新のコンテナ化されたビルドを生成するのに必要な火力は、従来のアプリケーションパッケージと比較して年々増大しています。

分散型CIプラットフォームを実行するために必要なインフラは、構築するアプリケーションと同じくらい複雑である可能性があります。新しいビルドノードをいつスピンアップし、いつスピンダウンするかの管理は、プラットフォームやエンドユーザーによって異なります。

テクノロジーの進化に対応するために

「テクノロジーにおいて唯一不変なものは、変化である」という格言は真実です。新たな言語、プラットフォーム、そしてパラダイムは、技術の進歩に伴って予想されることです。新しい技術を異種混在ビルドに含めたり、新しいテストパラダイムを受け入れたりすることは、一部の技術向けに設計された硬直したレガシーなCIプラットフォームでは難しいかもしれません。自前やレガシーなCIプラットフォームは、プラットフォームが構築された時点で企業内にあったもの向けに設計されているという点で、非常に硬直化しやすいと言えます。

CIプラットフォームをCDに拡張する

 

開発パイプラインの一部を自動化した最初のシステムであるため、ソフトウェアを本番環境に導入するための自動化を構築し続けることは自然な傾向でしょう。しかし、ユニットテストの失敗によるビルドの失敗は、複数のデプロイメントやリリース戦略を扱うこととは異なることに、組織はすぐに気づきます。デプロイの失敗は、システムを稼働していない状態にする可能性があります。

カナリアリリースのような安全なリリース戦略を取りながら、インフラとアプリケーションを一緒に作成しテストするために必要な厳密さは、合格/失敗のシナリオを決定するためにアプリケーションに関するチームの知識を体系化することを必要とします。アプリケーションを追加する負担は大きく、ビルドを高速に保つなど、CIのベストプラクティスに反する可​​能性があります。

CIのベストプラクティス

CIが進化するにつれて、より成熟したCIのアプローチを示唆するような実践があります。成熟したCIの実践は、スピード、アジリティ、シンプルさ、そして自動化された方法での結果の普及を可能にするはずです。

自動化されたビルドを高速に保つ

ビルドは一日中行われるため、ビルドを高速に自動化することは、エンジニアの効率化の核となります。ビルドを外部化することで、エンジニアのマシンやローカル環境をビルドのために拘束する必要がなくなるため、エンジニアはビルドが発生するたびに前進や調整を続けることができます。簡単に言えば、ビルドが速ければ速いほど、フィードバックを実装したり、CDソリューションでデプロイするためのリリース候補を作成したりすることができます。

全てのコミットは自動でビルドされるべき

ソフトウェアエンジニアにとって、共有リポジトリーでのコミット(あるいはマージ)は、ソフトウェア開発ライフサイクルを前進させる合図です。コミットとは、開発したものを試し始める準備ができていることをコミットすることです。CIでは、各コミットを潜在的なリリース候補として扱い、アーティファクトの構築を開始することが中核となります。これにより、デプロイを決定する際のリードタイムを短縮することができます。

小さなピース

マイクロサービスやCIでは、小さなピースが複雑さを軽減するのに役立ちます。ビルド、テスト、パッケージ、パブリッシュなど、より小さく機能的に独立したピースを持つことで、問題やボトルネックの特定がより容易になります。機能領域のいずれかに変更があった場合、その変更を微調整し、CIプラットフォーム内のステップを更新することができます。より小さなピースだと、特定のピースが他のシステムで実行される必要がある場合、機能を移行するための境界線を見つけることが容易となります。

CIを理解することはCDではない

CIとCDは別の分野であることを意識することで、CIパイプラインを設計する際にアンチパターンに陥るのを防ぐことができます。スモールピースと高速ビルドの目標を維持しながら、複数のフローを作成し、CIパイプラインにデプロイの信頼性をもたらすことは、負担になることがあります。CIプロセスは通常、デリバリープロセスよりも多く実行されます。特に開発中は、成功したリリース候補が作成されるまでに複数のビルドが発生するためです。一方CDはワークフローとして実行されるように設計されており、手作業による承認や判断のステップが発生する可能性がありますが、これはCIでは逆効果になります。

異種混在技術のサポート

CIを組織的に導入するためには、自動ビルドをサポートするカバレッジと、CIの実践を推進することが重要です。新しい言語、パッケージング、およびパラダイムは、テクノロジーにおいて常に存在します。包括的であることは、CIに限ったことではありませんが、エンジニアリングの効率化とSDLCの中核として、採用は極めて重要です。 

結果の透明性を確保する

ソフトウェア開発ライフサイクルにおいてフィードバックは非常に重要であり、エンジニアのローカル環境から初めて変更が出るのは、ほとんどの場合、CIプロセス/プラクティスによるものです。ビルドとテストの結果を明確、簡潔、かつタイムリーにチーム全体に伝えることは、エンジニアリングチームが調整し、成功するリリース候補に向けて前進するのに役立ちます。最初のビルドは、イテレーションが発生するため、複数回実行されることが予想されます。CIプラットフォームによって、特に結果の共有に関する実装が異なる場合があります。 

CIはどのように実施されるか

CIは、多くのエンジニアリング効率化の動きと同様に、プロセスとプラットフォームの一部です。CIを導入しようとする場合、ソースコードのイベントをトリガーとして機能させ、適切なインフラストラクチャとテストカバレッジを整備するために、いくつかの可動部品があります。 

ソースコード管理統合

コミットやマージをトリガーとしてビルドを行うには、ソースコード管理/バージョン管理システムと何らかの形で統合する必要があります。SCMのイベントをリッスンする機能が鍵となります。最近のソリューションでは、この統合をさらに一歩進めて、GitなどのSCMのソースコードプロジェクトと宣言形式でCIの構成を保存します。

分散型ビルドインフラストラクチャー

ローカルマシンでビルドを実行すると、リソースを大量に消費し、ビルド中にマシンのリソースのほとんどを使い果たす可能性があります。複数のエンジニアやチームが同時にビルドサーバーにアクセスすることを想定して、ある種の分散型かつ弾力的なインフラストラクチャーが必要です。リソースが不足するのは、実際のコンパイル、ビルド、パッケージングのステップの間だけです。その後、インフラを他の用途に転用することができます。最新のソリューションには、分散ビルドのための優れたサポートと実装があります。

適切なテストカバレッジ

パイプラインの後半でより適切なテストカバレッジでビルドプロセスに負担をかける誘惑があるとしても(例えば、QA環境への何らかのデプロイが発生したとき、または冗長なテスト)、品質演習はCIパイプラインで実行されるべきです。

CIテストとは?

CIテストは、アーティファクトに焦点を当てるべきであり、必ずしも環境に焦点を当てるべきではありません。 負荷テストなどの環境テストはデプロイが必要で、CIにはあまり向いていません。開発サイクルの早い段階でフィードバックが必要なテストは、複数回のデプロイを必要とするため、自動ビルド時に実行することが賢明です。

コード品質テスト

ビルド/パッケージングステップが開始される前に、合格すべき品質ゲートとしてコード品質テストがあります。ビルドのために全てのソースコードが収集されるとき、ソースコードの検査はこのステップで意味をなします。共通の設計、セキュリティー、および構文の改善を探すために、コード品質テストはCIパイプラインで一般的に見られるものです。

単体テスト・機能テスト

コードカバレッジは、ローカル開発環境と比較して、CIパイプラインで拡大する必要があります。ビルドは複数のワークストリームからなるかもしれないので、個々のエンジニアが取り組んできた単体テスト・機能テストの組み合わせをCIパイプラインでまとめてテストすることは理に適っています。ローカルのIDEベースのテストをCIプラットフォームで呼び出すようにすることは、テストの自動化への確かな一歩となります。


オープンソースの依存性スキャン 

依存関係や推移的依存関係の全ては、ビルドプロセスが開始されるまで利用できないかもしれません。CIプロセスにおいて、ビルドとパッケージングにおける依存関係をスキャンすることは、バイナリーディストリビューションがクリーンであるとマークできるように、非常に賢明なタイミングでしょう。例えば、Java JARディストリビューションとハウジングのDockerイメージをスキャンすることは、CIパイプラインにおいて理に適っていると言えるでしょう。これら全て、またそれ以上のことが、Harnessによって自動化できます。

 

Drone-YAML

Harnessでビルドとテストのプロセスを自動化する

CIがどの段階にあるかに関わらず、Harnessはお客様をサポートします。Harnessは、あらゆるソフトウェアデリバリーニーズに対応する最高のプラットフォームとして、業界をリードするCIとCD機能を提供します。

Harness Continuous Integration Platformの機能について、また、Harnessの友人からエンドツーエンドのソフトウェアデリバリープラットフォーム全体について学びましょう。

CIを学ぶために、私たちのeBook「継続的インテグレーションの近代化」をダウンロードしてください。


この記事はHarness社のウェブサイトで公開されているものをDigital Stacksが日本語に訳したものです。無断複製を禁じます。原文はこちらです。

Harnessに関するお問い合わせはお気軽にお寄せください。

お問い合わせ