チュートリアル複雑なパイプラインの作成

このチュートリアルでは、小さなステップを繰り返しながら、徐々に複雑なCI/CDパイプラインを設定していきます。パイプラインは常に完全に機能しますが、ステップごとに機能が増えていきます。

このチュートリアルを終えると、GitLab.com 上の新しいプロジェクトとDocusaurus 上のドキュメントサイトが完成します。

このチュートリアルを完了するには

  1. ドキュサウルスのファイルを格納するプロジェクトを作成します。
  2. 初期パイプライン設定ファイルを作成します。
  3. サイトを構築するジョブを追加します。
  4. サイトをデプロイするジョブの追加
  5. テストジョブの追加
  6. マージリクエストパイプラインの使用開始
  7. 重複する設定を減らす

前提条件

  • GitLab.comのアカウントが必要です。
  • Git に慣れている必要があります。
  • Node.jsはローカルマシンにインストールする必要があります。例えば、MacOSではbrew install nodenodeをインストールできます。

ドキュサウルスのファイルを格納するプロジェクトを作成します。

パイプライン設定を追加する前に、まずGitLab.comでDocusaurusプロジェクトを設定する必要があります:

  1. ユーザー名(グループではない)で新しいプロジェクトを作成します:
    1. 左のサイドバーで、Search を選択するか、次のページに進んでください。
    2. View all my projects を選択します。
    3. ページの右側で、新規プロジェクトを選択します。
    4. 空白プロジェクトの作成」を選択します。
    5. プロジェクトの詳細を入力します:
      • プロジェクト名フィールドに、プロジェクト名を入力します(例:My Pipeline Tutorial Project)。
      • Initialize repository with a README を選択します。
    6. Create projectを選択します。
  2. プロジェクトのプロジェクト概要ページの右側にあるクローンを選択すると、プロジェクトのクローンパスが表示されます。SSH または HTTP パスをコピーし、そのパスを使用してプロジェクトをローカルにクローンします。

    例えば、SSHを使ってコンピュータのpipeline-tutorial ディレクトリにクローンする場合:

    git clone git@gitlab.com:my-username/my-pipeline-tutorial-project.git pipeline-tutorial
    
  3. プロジェクトのディレクトリに移動し、新しいドキュサウルスサイトを生成します:

    cd pipeline-tutorial
    npm init docusaurus
    

    ドキュソーラス初期化ウィザードは、サイトに関する質問をします。デフォルトのオプションをすべて使用します。

  4. 初期化ウィザードはwebsite/ にサイトを設定しますが、サイトはプロジェクトのルートにあるべきです。ファイルをルートに移動し、古いディレクトリを削除します:

    mv website/* .
    rm -r website
    
  5. Docusaurusの設定ファイルをGitLabプロジェクトの詳細で更新します。docusaurus.config.js にあります:

    • url: に次のフォーマットでパスを設定します:https://<my-username>.gitlab.io/.
    • /my-pipeline-tutorial-project/のように、baseUrl: をプロジェクト名に設定します。
  6. 変更をコミットして GitLab にプッシュします:

    git add .
    git commit -m "Add simple generated Docusaurus site"
    git push origin
    

CI/CDの初期設定ファイルを作成します。

プロジェクトでCI/CDが有効になり、ジョブを実行するためにRunnerが利用できるように、可能な限りシンプルなパイプライン設定ファイルから始めます。

このステップでは

  • ジョブ:コマンドを実行するパイプラインの自己完結した部分です。ジョブはGitLabインスタンスとは別にRunner上で実行されます。
  • script:ジョブの設定のこのセクションでは、ジョブのコマンドを定義します。複数のコマンド(配列)がある場合、それらは順番に実行されます。各コマンドはCLIコマンドとして実行されたかのように実行されます。デフォルトでは、コマンドが失敗したりエラーを返したりした場合、そのジョブは失敗したものとしてフラグが立てられ、それ以上のコマンドは実行されません。

このステップでは、この設定でプロジェクトのルートに.gitlab-ci.yml ファイルを作成します:

test-job:
  script:
    - echo "This is my first job!"
    - date

この変更をコミットして GitLab にプッシュします:

  1. Build (ビルド) > Pipelines (パイプライン)に進み、GitLabでこの単一のジョブでパイプラインが実行されることを確認します。
  2. パイプラインを選択し、ジョブを選択するとジョブのログが表示され、This is my first job! メッセージとその日付が表示されます。

プロジェクトに.gitlab-ci.yml ファイルができたので、今後パイプラインの設定を変更する場合はすべてパイプラインエディターで行うことができます。

サイトを構築するジョブを追加します。

CI/CDパイプラインの一般的なタスクはプロジェクトのコードをビルドしてからデプロイすることです。サイトをビルドするジョブを追加することから始めましょう。

このステップでは

  • image:ジョブの実行に使用するDockerコンテナをRunnerに伝えます。ランナー:
    1. コンテナイメージをダウンロードし、起動します。
    2. GitLab プロジェクトを実行中のコンテナにクローンします。
    3. script コマンドを一つずつ実行します。
  • artifacts:ジョブは自己完結しており、互いにリソースを共有することはありません。あるジョブで生成されたファイルを別のジョブで使用したい場合、最初にアーティファクトとして保存する必要があります。そうすれば、後のジョブがアーティファクトを取得し、生成されたファイルを使用することができます。

このステップでは、test-jobbuild-job に置き換えてください:

  • ジョブを最新のnode イメージで node実行するように設定するにはimage を使用します。node DocusaurusはNode.jsプロジェクトであり、 nodeイメージには必要なnpm コマンドが組み込まれています。
  • npm install を実行して Docusaurus を実行中のnode コンテナにインストールし、npm run build を実行してサイトを構築します。
  • Docusaurus はビルドしたサイトをbuild/ に保存しますので、これらのファイルをartifacts で保存します。
build-job:
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

パイプラインエディタを使用して、このパイプライン設定をデフォルトブランチにコミットし、ジョブログを確認します。できます:

  • npm コマンドの実行とサイトのビルドを確認します。
  • 最後にアーティファクトが保存されていることを確認してください。
  • ジョブが完了した後、ジョブログの右側にある[参照]を選択して、アーティファクトファイルの内容を参照します。

サイトをデプロイするジョブの追加

build-job でドキュサウルスサイトのビルドを確認したら、それをデプロイするジョブを追加できます。

このステップでは

  • stagestages: 最も一般的なパイプライン設定は、ジョブをステージにグループ化します。同じステージのジョブは並行して実行でき、後のステージのジョブは前のステージのジョブの完了を待ちます。ジョブが失敗した場合、ステージ全体が失敗したとみなされ、後のステージのジョブは実行を開始しません。
  • GitLab Pages:静的サイトをホストするには、GitLab Pagesを使います。

このステップでは

  • ビルドしたサイトをフェッチしてデプロイするジョブを追加します。GitLab Pagesを使う場合、ジョブの名前は常にpagesbuild-job からアーティファクトが自動的に取得され、ジョブに抽出されます。Pages はpublic/ ディレクトリにあるサイトを探すので、script コマンドを追加してサイトをそのディレクトリに移動します。
  • stages セクションを追加し、各ジョブのステージを定義します。build-jobbuild ステージで最初に実行され、pagesdeploy ステージで後に実行されます。
stages:          # List of stages for jobs and their order of execution
  - build
  - deploy

build-job:
  stage: build   # Set this job to run in the `build` stage
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

pages:
  stage: deploy  # Set this new job to run in the `deploy` stage
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"

パイプラインエディターを使ってこのパイプライン設定をデフォルトブランチにコミットし、パイプラインリストからパイプラインの詳細を表示します。確認してください:

  • 2つのジョブは異なるステージ、builddeploy で実行されます。
  • pages ジョブが完了すると、pages-deploy ジョブが表示されます。これは GitLab プロセスで、Pages サイトをデプロイします。このジョブが完了すると、新しいドキュソーラスサイトにアクセスできるようになります。PagesのドキュメントにURLのフォーマットが説明されていますが、https://<my-username>.gitlab.io/<my-pipeline-tutorial-project>/ に似ているはずです。

テストジョブの追加

サイトが期待通りにビルドされ、デプロイされるようになったので、 テストと linting を追加することができます。例えば、RubyプロジェクトではRSpecのテストジョブを実行します。DocusaurusはMarkdownと生成されたHTMLを使う静的なサイトなので、このチュートリアルではMarkdownとHTMLをテストするジョブを追加します。

このステップでは

  • allow_failure:断続的に失敗するジョブや失敗が予想されるジョブは、生産性を低下させたり、トラブルシューティングを困難にします。allow_failure を使用して、パイプラインの実行を停止せずにジョブを失敗させます。
  • dependencies:dependencies を使用して、どのジョブからアーティファクトをフェッチするかをリストアップすることで、内部ジョブのアーティファクトダウンロードを制御します。

このステップでは

  • builddeploy の間で実行される、新しいtest ステージ を追加します。これらの3つのステージは、stages が設定で未定義の場合のデフォルトステージです。
  • markdownlintを実行し、プロジェクトのMarkdownをチェックするlint-markdown ジョブを追加します。markdownlintは静的解析ツールで、Markdownファイルがフォーマット標準に従っているかチェックします。
    • Docusaurusが生成するサンプルMarkdownファイルはblog/docs/ にあります。
    • このツールは元のMarkdownファイルのみをスキャンし、build-job のアーティファクトに保存されている生成されたHTMLは必要ありません。dependencies: [] 、アーティファクトを取得しないようにジョブを高速化します。
    • サンプルのMarkdownファイルのいくつかはデフォルトのmarkdownlintルールに違反しているので、ルール違反にもかかわらずパイプラインを継続させるためにallow_failure: true
  • HTMLHintを実行し、生成されたHTMLをチェックするためにtest-html ジョブを追加します。HTMLHintは生成されたHTMLに既知のイシューがないかスキャンする静的解析ツールです。
  • test-htmlpages の両方がbuild-job のアーティファクトで見つかった生成された HTML を必要とします。ジョブはデフォルトでは以前のステージのすべてのジョブからアーティファクトをフェッチしますが、将来のパイプラインの変更後にジョブが誤って他のアーティファクトをダウンロードしないようにするために、dependencies: を追加します。
stages:
  - build
  - test               # Add a `test` stage for the test jobs
  - deploy

build-job:
  stage: build
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

lint-markdown:
  stage: test
  image: node
  dependencies: []     # Don't fetch any artifacts
  script:
    - npm install markdownlint-cli2 --global           # Install markdownlint into the container
    - markdownlint-cli2 -v                             # Verify the version, useful for troubleshooting
    - markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"  # Lint all markdown files in blog/ and docs/
  allow_failure: true  # This job fails right now, but don't let it stop the pipeline.

test-html:
  stage: test
  image: node
  dependencies:
    - build-job        # Only fetch artifacts from `build-job`
  script:
    - npm install --save-dev htmlhint                  # Install HTMLHint into the container
    - npx htmlhint --version                           # Verify the version, useful for troubleshooting
    - npx htmlhint build/                              # Lint all markdown files in blog/ and docs/

pages:
  stage: deploy
  dependencies:
    - build-job        # Only fetch artifacts from `build-job`
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"

このパイプライン設定をデフォルトブランチにコミットし、パイプラインの詳細を表示します。

  • サンプルのMarkdownがデフォルトのmarkdownlintルールに違反しているため、test-markdown のジョブは失敗しますが、失敗は許されます。できます:
    • 今のところ違反を無視してください。チュートリアルの一部として修正する必要はありません。
    • Markdownファイル違反を修正してください。それから、allow_failurefalse に変更するか、allow_failure: false が定義されていない場合のデフォルトの動作なので、allow_failure を完全に削除してください。
    • markdownlint設定ファイルを追加して、警告するルール違反を制限してください。
  • また、Markdownファイルの内容を変更し、次のデプロイ後にサイト上で変更を確認することもできます。

マージリクエストパイプラインの使用開始

上記のパイプライン設定では、パイプラインが正常に完了するたびにサイトがデプロイされますが、これは理想的な開発ワークフローではありません。フィーチャーブランチやマージリクエストから作業を進め、変更がデフォルトブランチにマージされたときにのみサイトをデプロイするほうがよいでしょう。

このステップでは

  • rules:各ジョブにルールを追加して、ジョブを実行するパイプラインを設定します。ジョブをマージリクエストパイプラインスケジュールされたパイプライン、その他の特定の状況で実行するように設定できます。ルールは上から下へ評価され、ルールに一致するジョブはパイプラインに追加されます。
  • CI/CD変数: 設定ファイルやスクリプトコマンドでジョブの動作を設定するには、これらの環境変数を使用します。定義済みのCI/CD変数は、手動で定義する必要のない変数です。これらはパイプラインに自動的に注入されるので、パイプラインの設定に使用できます。変数は通常、$VARIABLE_NAME.のような形式で記述され、定義済みの変数は通常、$CI_.が先頭に付きます。

このステップでは

  • 新しい機能ブランチを作成し、デフォルトブランチの代わりにそのブランチで変更を行います。
  • 各ジョブにrules を追加します:
    • このサイトはデフォルトブランチへの変更のみをデプロイする必要があります。
    • 他のジョブはマージリクエストやデフォルトブランチのすべての変更に対して実行されるべきです。
  • このパイプライン設定により、ジョブを実行せずにフィーチャーブランチで作業することができ、リソースを節約できます。変更を検証する準備ができたら、マージリクエストを作成し、マージリクエストで実行するように設定されたジョブでパイプラインを実行します。
  • マージリクエストが受理され、変更がデフォルトブランチにマージされると、pages デプロイジョブを含む新しいパイプラインが実行されます。ジョブに失敗しなければ、サイトはデプロイされます。
stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'  # Run for all changes to a merge request's source branch
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH       # Run for all changes to the default branch

lint-markdown:
  stage: test
  image: node
  dependencies: []
  script:
    - npm install markdownlint-cli2 --global
    - markdownlint-cli2 -v
    - markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"
  allow_failure: true
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'  # Run for all changes to a merge request's source branch
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH       # Run for all changes to the default branch

test-html:
  stage: test
  image: node
  dependencies:
    - build-job
  script:
    - npm install --save-dev htmlhint
    - npx htmlhint --version
    - npx htmlhint build/
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'  # Run for all changes to a merge request's source branch
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH       # Run for all changes to the default branch

pages:
  stage: deploy
  dependencies:
    - build-job
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH      # Run for all changes to the default branch only

マージリクエストの変更をマージします。このアクションにより、デフォルトブランチが更新されます。新しいパイプラインにサイトをデプロイするpages ジョブが含まれていることを確認します。

今後のパイプライン設定の変更には、必ず機能ブランチとマージリクエストを使用してください。Git タグの作成やパイプラインスケジュールの追加など、その他のプロジェクトの変更は、そのような場合のルールも追加しない限り、パイプラインをトリガーしません。

重複する設定を減らす

パイプラインには、rulesimage の設定が同じ3つのジョブがあります。これらのルールを繰り返す代わりに、extendsdefault を使用して、単一の真実のソースを作成します。

このステップでは

  • 隠しジョブ. で始まるジョブはパイプラインに追加されません。再利用したい設定を保持するために使用します。
  • extends:extends は複数の場所で設定を繰り返すために使います。隠されたジョブの設定を更新した場合、隠されたジョブを拡張するすべてのジョブは更新された設定を使用します。
  • default:定義されていない場合、すべてのジョブに適用されるキーワードのデフォルトを設定します。
  • YAML オーバーライド:extends もしくはdefault の設定を再利用する場合、extends もしくはdefault の設定を上書きするために、ジョブ内でキーワードを明示的に定義することができます。

このステップでは

  • build-job,lint-markdown,test-html で繰り返されるルールを保持するために、.standard-rules 隠しジョブを追加します。
  • extends を使用して、3つのジョブで.standard-rules の設定を再利用します。
  • default セクションを追加して、image デフォルトをnode として定義します。
  • pages デプロイジョブはデフォルトのnode イメージを必要としないので、非常に小さくて高速なイメージであるbusyboxを明示的に使用します。
stages:
  - build
  - test
  - deploy

default:               # Add a default section to define the `image` keyword's default value
  image: node

.standard-rules:       # Make a hidden job to hold the common rules
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

build-job:
  extends:
    - .standard-rules  # Reuse the configuration in `.standard-rules` here
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

lint-markdown:
  stage: test
  extends:
    - .standard-rules  # Reuse the configuration in `.standard-rules` here
  dependencies: []
  script:
    - npm install markdownlint-cli2 --global
    - markdownlint-cli2 -v
    - markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"
  allow_failure: true

test-html:
  stage: test
  extends:
    - .standard-rules  # Reuse the configuration in `.standard-rules` here
  dependencies:
    - build-job
  script:
    - npm install --save-dev htmlhint
    - npx htmlhint --version
    - npx htmlhint build/

pages:
  stage: deploy
  image: busybox       # Override the default `image` value with `busybox`
  dependencies:
    - build-job
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

マージリクエストを使って、このパイプライン設定をデフォルトブランチにコミットします。ファイルはよりシンプルになりますが、前のステップと同じ動作になるはずです。

あなたは今、完全なパイプラインを作り、それをより効率的にするために合理化しました。お見事です!この知識を活かして、.gitlab-ci.yml の残りのキーワードについて学び、独自のパイプラインを構築することができます。