更新日:2025年2月20日
27分で読めます
継続的インテグレーション (CI) 入門:CI は初めてですか?GitLab CI の使い方を学び、最初のCIパイプラインをGitLabでビルドしてみましょう。

継続的インテグレーション (CI) (英語版) のことを何一つ知らず、ソフトウェア開発ライフサイクルに どうして CI が必要なのか (英語版) 分からない、と仮定しましょう。 いま、あるプロジェクトで作業をしていて、そこには2つのテキストファイルから成るコードがあるものとします。さらに、これらの2つのファイルには「Hello world」というフレーズが含まれている必要がある、という点に注意してください。 このフレーズが含まれていなければ、開発チームがその月のお給料を受け取れないことになるかもしれないくらい、重要なポイントです。 そこで、責任感のあるソフトウェアデベロッパーが、顧客にコードを納品する前に実行する、短いスクリプトを書きました。 以下のような非常に洗練されたコードです。
cat file1.txt file2.txt | grep -q "Hello world"
ここでの懸念事項はチームには10名のデベロッパーがいて、人的要因がコードの品質に大きな影響を及ぼす可能性があるという点です。 1週間前、新しくチームに入ったメンバーがこのスクリプトを実行し忘れ、3件のクライアントに機能しないビルドが納品されるという事態が発生しました。この事態の解決にあたり、幸いにもコードは既にGitLab にあり、ビルトインの CI があることが分かりました。さらに、あるカンファレンスで、テスト実行にCIを使うのが一般的ということを耳にしていました。
ドキュメントによると、CI の実行に必要なのは .gitlab-ci.yml ファイル内に 以下の2 行のコードを追加することだけでした。
test:
script: cat file1.txt file2.txt | grep -q 'Hello world'
コミットして...無事にビルドが成功しました。
では、2 つ目のファイルの「world」という文言を「Africa」に置き換え、何が起こるか確認してみましょう。
ビルドは予想どおり失敗します。
ここで、自動化テストが完成しました。GitLab CI は、DevOps 環境内でソースコードのリポジトリに新しいコードをプッシュするたびにこのテストスクリプトを実行します。
注: 上記例では、file1.txt と file2.txt がGitLabランナーを実行するホストに存在すると仮定しています。
この例を実際に GitLabで実行するには、以下のようにファイルを作成するコードを実行した後、テストスクリプトを実行する必要があります。
test:
before_script:
- echo "Hello " > | tr -d "\n" | > file1.txt
- echo "world" > file2.txt
script: cat file1.txt file2.txt | grep -q 'Hello world'
なお、分かりやすくするために、この 2 つのファイルは既にホストに存在していると仮定し、以降の例では作成しないものとします。
次にすることは、顧客に納品するコードをパッケージ化することです。ソフトウェア開発プロセスのこの部分も自動化してしまいましょう。 まず、CI に別のジョブを定義する必要があります。このジョブは「package」という名前にしましょう。
test:
script: cat file1.txt file2.txt | grep -q 'Hello world'
package:
script: cat file1.txt file2.txt | gzip > package.gz
よって、今ここにはタブが 2 つあります。
しかし、新たに作成されるファイルがダウンロードできるようにビルドの「アーティファクト」であることを指定し忘れてしまいました。。修正するには、artifacts セクションを追加します。
test:
script: cat file1.txt file2.txt | grep -q 'Hello world'
package:
script: cat file1.txt file2.txt | gzip > packaged.gz
artifacts:
paths:
- packaged.gz
修正した結果を確認すると、アーティファクトが作成されダウンロードできるようになっています。
しかし、ここで修正が必要な新たな問題があります。2 つのジョブは現在は並列実行されていますが、テストに失敗した場合、アプリケーションをパッケージ化しないように変更をする必要があります。
そこで「package」ジョブは、テストが成功した場合のみ実行するものとします。stages を指定し、ジョブの実行順序を定義しましょう。
stages:
- test
- package
test:
stage: test
script: cat file1.txt file2.txt | grep -q 'Hello world'
package:
stage: package
script: cat file1.txt file2.txt | gzip > packaged.gz
artifacts:
paths:
- packaged.gz
上記のようになりました。 ちなみに、コンパイル (我々のケースでは2つのファイルを連結することを意味します) には時間がかかるため、2 回も実行したくはありません。コンパイルは別のステップとして定義しましょう。
stages:
- compile
- test
- package
compile:
stage: compile
script: cat file1.txt file2.txt > compiled.txt
artifacts:
paths:
- compiled.txt
test:
stage: test
script: cat compiled.txt | grep -q 'Hello world'
package:
stage: package
script: cat compiled.txt | gzip > packaged.gz
artifacts:
paths:
- packaged.gz
それでは、アーティファクトを見てみましょう。
この「コンパイル」ファイルを常にダウンロード可能にする必要はないようです。一時的なアーティファクトとして「20 分」で保存期間切れとなるよう、expire_in を設定します。
compile:
stage: compile
script: cat file1.txt file2.txt > compiled.txt
artifacts:
paths:
- compiled.txt
expire_in: 20 minutes
構成ファイルは見たところ問題なさそうです。
ここまでは順調です。しかし、CIビルドにはまだ時間がかかります。ログを見てみましょう。
ここに注目してください。Ruby 3.1とあります。
なぜ Ruby が必要なのかといえば、GitLab.com が ビルド実行 (英語版) に Docker イメージを使用しており、デフォルトで (英語版) ruby:3.1 イメージを使用するからです。間違いなく、このイメージには必要のないパッケージが多数含まれています。Google で検索して調べたところ、alpine というイメージがあり、ほとんど空の Linux イメージであることが分かりました。
それでは、.gitlab-ci.yml に image: alpine を追加して、このイメージを使用したいと明示的に指定しましょう。
うまくいきました。パイプラインの実行が3 分ほど短縮できたようです。
パブリックイメージはたくさんあるようです。
さて、ここで新しいクライアントが、アプリを .gz ではなく、.iso イメージとしてパッケージ化してほしい、と希望しているとします。CI がすべての作業を行なってくれるため、コードにはジョブを 1 つ追加するだけです。ISO イメージはmkisofsコマンドを使用して作成できます。構成ファイルは次のようになります。
image: alpine
stages:
- compile
- test
- package
# ... "compile" and "test" jobs are skipped here for the sake of compactness
pack-gz:
stage: package
script: cat compiled.txt | gzip > packaged.gz
artifacts:
paths:
- packaged.gz
pack-iso:
stage: package
script:
- mkisofs -o ./packaged.iso ./compiled.txt
artifacts:
paths:
- packaged.iso
ジョブ名は同じにする必要はありません。ジョブ名が同じだと、ソフトウェア開発プロセスの同じステージでジョブを並列実行できません。そのため、ジョブやステージの名前が同じになるのは、偶然のことだと考えてください。
さて、ビルドは失敗しました。
mkisofs が alpine イメージに含まれていないことが原因です。まずはこのパッケージをインストールする必要があります。
Alpine Linux Web サイト (英語版) によると、mkisofs は xorrisoパッケージと cdrkit パッケージの一部です。次のコマンドを実行することでパッケージをインストールできます。
echo "ipv6" >> /etc/modules # enable networking
apk update # update packages list
apk add xorriso # install package
CI ではこれらは他のコマンドと何ら変わりません。script セクションで実行する必要があるコマンドの全リストは、このようになります。
script:
- echo "ipv6" >> /etc/modules
- apk update
- apk add xorriso
- mkisofs -o ./packaged.iso ./compiled.txt
構文的に正しくするため、パッケージのインストールに関連したコマンドは before_script 内に置きましょう。before_script を構成の最上位レベルで使うと、そのコマンドがすべてのジョブの前に実行されることに留意してください。今回は特定のジョブの前で実行させます。
ステージを定義して、テストに合格した場合にのみパッケージジョブを実行するようにしました。後のステージに定義されているジョブに対し、いくつかのジョブのステージ順序を並び替えて先に実行させたい場合はどうすればいいでしょうか。場合によっては、従来のステージ順序がパイプライン全体の実行時間を遅くしてしまう可能性があります。
テストステージに、実行に時間のかかる負荷の高いテストがいくつか含まれており、それらのテストが必ずしもパッケージジョブに関連していないとします。この場合、テストの完了を待たずにパッケージジョブを開始できれば、より効率的になります。それにはDAG (有向非巡回グラフ) が役立ちます。特定のジョブのステージ順序を変えるためには、ジョブの依存関係 (通常のステージの順序をスキップするもの) を定義します。
GitLab には、ジョブ間の依存関係を作成する特殊キーワード needs があります。これを使うことで、依存しているジョブが完了するとすぐにジョブを前倒しで実行できるようになります。
次の例では、テストジョブが完了するとすぐにパックジョブが実行を開始します。そのため、将来誰かがテストをテストステージに追加した場合に、新しいテストジョブの完了を待たずにパッケージジョブが実行を開始します。
pack-gz:
stage: package
script: cat compiled.txt | gzip > packaged.gz
needs: ["test"]
artifacts:
paths:
- packaged.gz
pack-iso:
stage: package
before_script:
- echo "ipv6" >> /etc/modules
- apk update
- apk add xorriso
script:
- mkisofs -o ./packaged.iso ./compiled.txt
needs: ["test"]
artifacts:
paths:
- packaged.iso
.gitlab-ci.yml の最終バージョン:
image: alpine
stages:
- compile
- test
- package
compile:
stage: compile
before_script:
- echo "Hello " | tr -d "\n" > file1.txt
- echo "world" > file2.txt
script: cat file1.txt file2.txt > compiled.txt
artifacts:
paths:
- compiled.txt
expire_in: 20 minutes
test:
stage: test
script: cat compiled.txt | grep -q 'Hello world'
pack-gz:
stage: package
script: cat compiled.txt | gzip > packaged.gz
needs: ["test"]
artifacts:
paths:
- packaged.gz
pack-iso:
stage: package
before_script:
- echo "ipv6" >> /etc/modules
- apk update
- apk add xorriso
script:
- mkisofs -o ./packaged.iso ./compiled.txt
needs: ["test"]
artifacts:
paths:
- packaged.iso
パイプラインが作成できました!ステージは 3 つの連続したステージで、ジョブ pack-gz と pack-iso が、package ステージ内で並列実行されています。

ここからは、高度なパイプラインを構築する方法を説明します。
DevOps において、ソフトウェア開発戦略の重要なルールは、素晴らしいユーザーエクスペリエンスを備えた優れたアプリを作成する、というものです。ここでは、CI パイプラインにいくつかのテストを追加し、プロセス全体の早い段階でバグを検出、修正しましょう。この方法なら、問題が大きくなる前や新しいプロジェクトに移る前に問題を修正できます。 GitLabにはさまざまな テスト 用にすぐ使えるテンプレートがあり、これらを使用することで作業が簡単になります。必要な手順は、CI の構成にテンプレートを追加するだけです。 この例では、アクセシビリティテスト (英語版) を追加します。
stages:
- accessibility
variables:
a11y_urls: "https://about.gitlab.com https://www.example.com"
include:
- template: "Verify/Accessibility.gitlab-ci.yml"
a11y_urls 変数をカスタム化し、Web ページの URL を挿入して、Pa11y と コード品質 のテストを行います。
include:
- template: Jobs/Code-Quality.gitlab-ci.yml
GitLab を使うと、マージリクエストのウィジェットエリア内でテストレポートを簡単に確認できます。コードレビュー、パイプラインステータス、テスト結果を一か所にまとめることで、あらゆることがよりスムーズに効率よくできるようになります。
