更新日:2025年2月20日

27分で読めます

CI 入門:ジョブを順序どおりに、並列に、または順不同で実行する方法

継続的インテグレーション (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 内で最初のテストを実行する

ドキュメントによると、CI の実行に必要なのは .gitlab-ci.yml ファイル内に 以下の2 行のコードを追加することだけでした。

      test:
  script: cat file1.txt file2.txt | grep -q 'Hello world'

    

コミットして...無事にビルドが成功しました。 CI内でビルドに成功 では、2 つ目のファイルの「world」という文言を「Africa」に置き換え、何が起こるか確認してみましょう。 CI内でビルドに失敗 ビルドは予想どおり失敗します。 ここで、自動化テストが完成しました。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ビルド結果をダウンロード可能にする

次にすることは、顧客に納品するコードをパッケージ化することです。ソフトウェア開発プロセスのこの部分も自動化してしまいましょう。 まず、CI に別のジョブを定義する必要があります。このジョブは「package」という名前にしましょう。

      test:
  script: cat file1.txt file2.txt | grep -q 'Hello world'

package:
  script: cat file1.txt file2.txt | gzip > package.gz

    

よって、今ここにはタブが 2 つあります。 2つのタブ ― 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

    

構成ファイルは見たところ問題なさそうです。

  • アプリケーションをコンパイル、テスト、パッケージ化するために、3 つの連続したステージを作成しました。
  • コンパイル済みアプリを次のステージに渡すと、コンパイルを 2回実行する必要がなくなります(それにより実行が高速化されます)。
  • パッケージ化されたアプリケーションは、今後も使用できるようビルドアーティファクトとして保管します。

どのDockerイメージを使用するのか学ぶ

ここまでは順調です。しかし、CIビルドにはまだ時間がかかります。ログを見てみましょう。 ruby3.1 ここに注目してください。Ruby 3.1とあります。 なぜ Ruby が必要なのかといえば、GitLab.com が ビルド実行 (英語版) に Docker イメージを使用しており、デフォルトで (英語版) ruby:3.1 イメージを使用するからです。間違いなく、このイメージには必要のないパッケージが多数含まれています。Google で検索して調べたところ、alpine というイメージがあり、ほとんど空の Linux イメージであることが分かりました。 それでは、.gitlab-ci.ymlimage: alpine を追加して、このイメージを使用したいと明示的に指定しましょう。 うまくいきました。パイプラインの実行が3 分ほど短縮できたようです。 ビルド速度を短縮 パブリックイメージはたくさんあるようです。

  • mysql
  • Python
  • Java
  • php それにより、我々の技術スタックに適したものを選ぶことができます。不必要なソフトウェアが含まれていないイメージを指定することで、ダウンロード時間が最短で済みます。

複雑なシナリオに対応する

さて、ここで新しいクライアントが、アプリを .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 が欠落しているために失敗したビルドmkisofsalpine イメージに含まれていないことが原因です。まずはこのパッケージをインストールする必要があります。

欠落しているソフトウェアやパッケージの対応

Alpine Linux Web サイト (英語版) によると、mkisofsxorrisoパッケージと 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(有向非巡回グラフ):より高速で柔軟なパイプラインのために

ステージを定義して、テストに合格した場合にのみパッケージジョブを実行するようにしました。後のステージに定義されているジョブに対し、いくつかのジョブのステージ順序を並び替えて先に実行させたい場合はどうすればいいでしょうか。場合によっては、従来のステージ順序がパイプライン全体の実行時間を遅くしてしまう可能性があります。 テストステージに、実行に時間のかかる負荷の高いテストがいくつか含まれており、それらのテストが必ずしもパッケージジョブに関連していないとします。この場合、テストの完了を待たずにパッケージジョブを開始できれば、より効率的になります。それには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-gzpack-iso が、package ステージ内で並列実行されています。 パイプラインのイラスト

高度なパイプラインの構築

ここからは、高度なパイプラインを構築する方法を説明します。

CIパイプラインに自動テストを実装

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 を使うと、マージリクエストのウィジェットエリア内でテストレポートを簡単に確認できます。コードレビュー、パイプラインステータス、テスト結果を一か所にまとめることで、あらゆることがよりスムーズに効率よくできるようになります。 アクセシビリティレポート

アクセシビリティ・マージリクエスト・ウィジェット
コード品質マージリクエストウィジェット

ご意見をお寄せください

このブログ記事を楽しんでいただけましたか?ご質問やフィードバックがあればお知らせください。GitLabコミュニティフォーラムで新しいトピックを作成してあなたの声を届けましょう。

フィードバックを共有する

フォーチュン100企業の50%以上がGitLabを信頼

より優れたソフトウェアをより速く提供

インテリジェントなDevSecOpsプラットフォームで

チームの可能性を広げましょう。