カスタムエグゼキューター

GitLab Runner 12.1 で導入されました

GitLab Runnerはネイティブでサポートしていない環境のためにCustom Executorを提供します。例えば、LXD や Libvirt などです。

これは、GitLab Runnerがあなたの環境のプロビジョニング、実行、クリーンアップを行うための実行ファイルを使用するように設定することで、独自のエクゼキュータを作成するためのコントロールを提供します。

カスタム Executor 用に設定したスクリプトはDrivers と呼ばれます。例えば、LXDドライバや Libvirtドライバを作成することができます。

制限事項

Custom Executorを使用する際の現在の制限事項を以下に示します:

設定

いくつかの設定キーがあります。いくつかはオプションです。

以下はCustom Executorの設定例です:

[[runners]]
  name = "custom"
  url = "https://gitlab.com"
  token = "TOKEN"
  executor = "custom"
  builds_dir = "/builds"
  cache_dir = "/cache"
  [runners.custom]
    config_exec = "/path/to/config.sh"
    config_args = [ "SomeArg" ]
    config_exec_timeout = 200

    prepare_exec = "/path/to/script.sh"
    prepare_args = [ "SomeArg" ]
    prepare_exec_timeout = 200

    run_exec = "/path/to/binary"
    run_args = [ "SomeArg" ]

    cleanup_exec = "/path/to/executable"
    cleanup_args = [ "SomeArg" ]
    cleanup_exec_timeout = 200

    graceful_kill_timeout = 200
    force_kill_timeout = 200

フィールドの定義とどのフィールドが必要かは[runners.custom] の設定を参照してください。

また、[[runners]] の内部にはbuilds_dircache_dir の両方が必須フィールドです。

ジョブを実行するために必要なソフトウェア

ユーザーはPATH に存在しなければならない以下を含む環境をセットアップしなければなりません:

ステージ

Custom Executorはジョブの詳細を設定し、環境を準備し、クリーンアップし、その中でジョブスクリプトを実行するためのステージを提供します。各ステージは特定のことを担当し、注意すべきことが異なります。

Custom executorによって実行される各ステージは、組み込みのGitLab Runner executorが実行する時間に実行されます。

実行される各ステージに対して、実行ファイルに特定の環境変数が公開され、実行中の特定のジョブに関する情報を得るために使うことができます。すべてのステージは以下の環境変数を利用できます:

CI/CD環境変数と定義済み変数の両方は、システム環境変数との競合を防ぐために、CUSTOM_ENV_ が先頭に付きます。例えば、CI_BUILDS_DIRCUSTOM_ENV_CI_BUILDS_DIRとして利用できます。

ステージは以下の順序で実行されます:

  1. config_exec
  2. prepare_exec
  3. run_exec
  4. cleanup_exec

サービス

GitLab Runner 13.6 で導入されました

サービスはJSON 配列CUSTOM_ENV_CI_JOB_SERVICES として公開されます。

使用例:

custom:
  script:
    - echo $CUSTOM_ENV_CI_JOB_SERVICES
  services:
    - redis:latest
    - name: my-postgres:9.4
      alias: pg
      entrypoint: ["path", "to", "entrypoint"]
      command: ["path", "to", "cmd"]

上記の例では、CUSTOM_ENV_CI_JOB_SERVICES 環境変数に以下の値を設定します:

[{"name":"redis:latest","alias":"","entrypoint":null,"command":null},{"name":"my-postgres:9.4","alias":"pg","entrypoint":["path","to","entrypoint"],"command":["path","to","cmd"]}]

設定

コンフィグステージはconfig_exec によって実行されます。

実行時にいくつかの設定を行いたい場合があります。例えば、プロジェクトIDに応じたビルドディレクトリの設定などです。config_exec はSTDOUTから読み込み、特定のキーを持つ有効なJSON文字列を期待します。

使用例:

#!/usr/bin/env bash

cat << EOS
{
  "builds_dir": "/builds/${CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID}/${CUSTOM_ENV_CI_PROJECT_PATH_SLUG}",
  "cache_dir": "/cache/${CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID}/${CUSTOM_ENV_CI_PROJECT_PATH_SLUG}",
  "builds_dir_is_shared": true,
  "hostname": "custom-hostname",
  "driver": {
    "name": "test driver",
    "version": "v0.0.1"
  },
  "job_env" : {
    "CUSTOM_ENVIRONMENT": "example"
  }
}
EOS

JSON文字列の中に追加のキーがあっても無視されます。有効なJSON文字列でない場合、ステージは失敗し、さらに2回再試行されます。

パラメータ種類必須説明
builds_dir文字列です。ジョブの作業ディレクトリが作成されるベースディレクトリ。
cache_dir文字列です。ローカルキャッシュが保存されるベースディレクトリ。
builds_dir_is_sharedブールn/a同時実行ジョブ間で環境を共有するかどうかを定義します。
hostname文字列です。ランナーによって保存されたジョブの “メタデータ “に関連付けるホスト名。未定義の場合、ホスト名は設定されません。
driver.name文字列です。ドライバーのユーザー定義名。Using custom executor... 行で表示されます。未定義の場合、ドライバに関する情報は表示されません。
driver.version文字列です。ドライブのユーザー定義バージョン。Using custom executor... 行で印刷されます。未定義の場合は、名前情報のみが表示されます。
job_envオブジェクトを返します。ジョブの実行に続くすべてのステージで、環境変数を通して利用可能な名前と値のペア。これらはジョブではなくドライバで利用可能です。詳細については、job_env usage を参照してください。

実行ファイルのSTDERR は、ジョブログに出力されます。

ユーザは、GitLab Runnerが処理を終了する前にJSON文字列を返すまでの期限を設定したい場合、config_exec_timeout

config_exec_args のいずれかが定義されている場合は、config_exec で定義された実行ファイルに順番に追加されます。例えば、config.toml の内容を以下に示します:

...
[runners.custom]
  ...
  config_exec = "/path/to/config"
  config_args = [ "Arg1", "Arg2" ]
  ...

GitLab Runner はこれを/path/to/config Arg1 Arg2 として実行します。

job_env 使い方

job_env 設定の主な目的は、ジョブ実行の後続ステージのカスタムExecutorドライバ呼び出しのコンテキストに変数を渡すことです。

ジョブ実行環境との接続にいくつかの認証情報を準備する必要があり、このオペレーションが非常に高価であるドライバの例を考えてみましょう。ジョブ実行環境と接続するために、カスタムエグゼキュータが次に使用できる一時的なSSHユーザ名とパスワードを取得するために、ローカルの認証情報プロバイダに接続する必要があるとします。

Custom Executor の実行フローでは、各ジョブ実行ステージprepare 、複数のrun コール、cleanup )がドライバの別個の実行であり、コンテキストはそれぞれ別個です。資格情報を解決する例では、資格情報プロバイダへの接続は毎回行う必要があります。

このオペレーションが高価な場合、ジョブ実行全体に対して一度だけ行い、その後すべてのジョブ実行ステージでクレデンシャルを再利用したいと思うかもしれません。ここでjob_env が役立ちます。これによって、config_exec 呼び出し中にプロバイダと一度だけ接続し、job_env で受信した資格情報を渡すことができます。次に、prepare_execrun_execcleanup_exec のカスタムエグゼキュータ呼び出しが受信する変数のリストに追加されます。これにより、ドライバは、毎回資格情報プロバイダに接続する代わりに、変数を読み込んで、存在する資格情報を使用することができます。

理解すべき重要な点は、変数はジョブ自体で自動的に利用できるわけではないということです。これは、Custom Executor Driver がどのように実装されているかに完全に依存し、多くの場合、そこには存在しません。

job_env 、特定のRunnerによって実行されるすべてのジョブに変数のセットを渡せるようにしたいと考えているのであれば、[[runners]]](../configuration/advanced-configuration.md#the-runners-section) の[environment 設定を見てください。

変数が動的で、異なるジョブ間で値が変更されることが予想される場合は、job_env によって渡された変数がジョブ実行呼び出しに追加されるようにドライバが実装されていることを確認する必要があります。

準備

Prepareステージはprepare_exec によって実行されます。

この時点で、GitLab Runnerはジョブに関するすべてのことを知っています(どこで、どのように実行されるのか)。あとは、ジョブが実行できるように環境をセットアップするだけです。GitLab Runnerはprepare_exec で指定された実行ファイルを実行します。

これは、環境のセットアップ(たとえば、仮想マシンやコンテナ、サービスなどの作成)を行います。これが終わると、ジョブを実行する環境が整います。

このステージはジョブ実行の中で一度だけ実行されます。

ユーザは、GitLab Runnerがプロセスを終了する前に環境を準備するために待つ時間の期限を設定したい場合、prepare_exec_timeout

この実行ファイルから返されるSTDOUTSTDERR はジョブログに出力されます。

prepare_exec_args のいずれかが定義されている場合は、prepare_exec で定義された実行ファイルに順番に追加されます。例えば、config.toml の内容を以下に示します:

...
[runners.custom]
  ...
  prepare_exec = "/path/to/bin"
  prepare_args = [ "Arg1", "Arg2" ]
  ...

GitLab Runner はこれを/path/to/bin Arg1 Arg2 として実行します。

実行

Run ステージはrun_exec によって実行されます。

この実行ファイルから返されるSTDOUTSTDERR はジョブログに出力されます。

他のステージとは異なり、run_exec ステージは複数回実行されます。これは、以下のサブステージに順次分割されるためです:

  1. prepare_script
  2. get_sources
  3. restore_cache
  4. download_artifacts
  5. step_*
  6. build_script
  7. step_*
  8. after_script
  9. archive_cache ORarchive_cache_on_failure
  10. upload_artifacts_on_success ORupload_artifacts_on_failure
  11. cleanup_file_variables
note
GitLab Runner 14.0 以降では、build_scriptstep_script に置き換えられます。詳しくはこのイシューをご覧ください。

上記の各ステージで、run_exec の実行ファイルが実行されます:

  • 通常の環境変数。
  • 2つの引数:
    • GitLab RunnerがCustom Executorを実行するために作成するスクリプトへのパス。
    • ステージの名前。

使用例:

/path/to/run_exec.sh /path/to/tmp/script1 prepare_executor
/path/to/run_exec.sh /path/to/tmp/script1 prepare_script
/path/to/run_exec.sh /path/to/tmp/script1 get_sources

run_args が定義されている場合、それらはrun_exec 実行ファイルに渡される最初の引数のセットとなり、その後 GitLab Runner は他の引数を追加します。例えば、config.toml

...
[runners.custom]
  ...
  run_exec = "/path/to/run_exec.sh"
  run_args = [ "Arg1", "Arg2" ]
  ...

GitLab Runnerは実行ファイルに以下の引数を渡して実行します:

/path/to/run_exec.sh Arg1 Arg2 /path/to/tmp/script1 prepare_executor
/path/to/run_exec.sh Arg1 Arg2 /path/to/tmp/script1 prepare_script
/path/to/run_exec.sh Arg1 Arg2 /path/to/tmp/script1 get_sources

この実行ファイルは、最初の引数で指定されたスクリプトを実行します。このスクリプトには、GitLab Runner Executor が通常実行するクローン、アーティファクトのダウンロード、ユーザースクリプトの実行、その他後述するすべてのステップを実行するためのすべてのスクリプトが含まれています。スクリプトには以下のシェルを使うことができます:

  • Bash
  • PowerShellデスクトップ
  • PowerShellコア
  • バッチ(非推奨)

[[runners]]の内部でshell によって設定されたシェルを使用してスクリプトを生成します。 何も指定されていない場合は、OS プラットフォームのデフォルトが使用されます。

以下の表は、各スクリプトが何を行い、そのスクリプトの主な目的が何であるかを詳細に説明したものです。

スクリプト名スクリプトの内容
prepare_scriptジョブが実行されているマシンの簡単なデバッグ情報。
get_sourcesGit の設定を準備し、リポジトリをクローン/フェッチします。GitLab が提供する Git 戦略のすべての利点を得ることができるので、このままにしておくことをお勧めします。
restore_cacheキャッシュが定義されていれば、それを取り出します。これは、gitlab-runner のバイナリが$PATH にあることを期待します。
download_artifactsアーティファクトが定義されている場合は、ダウンロードします。これは、gitlab-runner のバイナリが$PATH で利用可能であることを想定しています。
step_*GitLabによって生成されます。実行するスクリプトのセット。カスタムエグゼキューターに送られることはありません。step_releasestep_accessibility のように複数のステップを持つこともあります。これは.gitlab-ci.yml ファイルの機能です。
build_script before_scriptscriptの組み合わせ。 GitLab Runner 14.0 以降では、build_scriptstep_scriptに置き換えられます。詳しくはイシューをご覧ください。
after_scriptこれはジョブから定義されたafter_script です。前のステップのどれかが失敗しても、これは常に呼び出されます。
archive_cacheキャッシュが定義されている場合、すべてのキャッシュのアーカイブを作成します。build_script が成功した場合のみ実行されます。
archive_cache_on_failureキャッシュが定義されていれば、すべてのキャッシュのアーカイブを作成します。build_script が失敗したときのみ実行されます。
upload_artifacts_on_success定義されているアーティファクトをアップロードします。build_script が成功した場合にのみ実行されます。
upload_artifacts_on_failure定義されているアーティファクトをアップロードします。build_script が失敗した場合にのみ実行されます。
cleanup_file_variables ファイルベースの変数をすべてディスクから削除します。

クリーンアップ

クリーンアップステージはcleanup_exec によって実行されます。

この最終ステージは、前のステージのいずれかが失敗した場合でも実行されます。このステージの主な目的は、セットアップされた可能性のある環境をすべてクリーンアップすることです。例えば、VMをオフにしたり、コンテナを削除したりします。

cleanup_exec の結果はジョブのステータスには影響しません。例えば、以下のような場合でもジョブは成功としてマークされます:

  • prepare_execrun_exec の両方が成功。
  • cleanup_exec は失敗します。

ユーザーが、GitLab Runnerがプロセスを終了する前に環境をクリーンアップするまでの期限を設定したい場合は、cleanup_exec_timeout

この実行ファイルのSTDOUT は GitLab Runner のログに DEBUG レベルで出力されます。STDERR は WARN レベルでログに出力されます。

cleanup_exec_args のいずれかが定義されている場合は、cleanup_exec で定義された実行ファイルに順番に追加されます。例えば、config.toml の内容を以下に示します:

...
[runners.custom]
  ...
  cleanup_exec = "/path/to/bin"
  cleanup_args = [ "Arg1", "Arg2" ]
  ...

GitLab Runner はこれを/path/to/bin Arg1 Arg2 として実行します。

実行可能ファイルの終了と終了

GitLab Runnerは、以下のいずれかの条件下で実行可能ファイルを優雅に終了させようとします:

  • config_exec_timeout prepare_exec_timeout またはcleanup_exec_timeout が満たされた場合。
  • ジョブがタイムアウトしました。
  • ジョブがキャンセルされました。

タイムアウトに達すると、SIGTERM が実行ファイルに送られ、exec_terminate_timeout のカウントダウンが始まります。実行ファイルはこのシグナルをリッスンして、リソースをクリーンアップする必要があります。exec_terminate_timeout が過ぎてプロセスがまだ実行中であれば、SIGKILL が送られてプロセスが終了し、exec_force_kill_timeout が開始します。exec_force_kill_timeout が終了した後もプロセスが実行されている場合、GitLab Runner はプロセスを放棄し、それ以上停止/終了を試みません。config_execprepare_execrun_exec の間にこれらのタイムアウトに達した場合、ビルドは失敗とみなされます。

GitLab 13.1では、ドライバによって生成された子プロセスも、UNIXベースのシステムで上で説明したグレースフル・ターミネーション処理を受けます。これは、すべての子プロセスが属するプロセスグループとしてメインプロセスを設定することで実現されます。

エラーハンドリング

GitLab Runnerが処理できるエラーには2種類あります。これらのエラーは、config_exec,prepare_exec,run_exec,cleanup_exec の内部の実行ファイルがこれらのコードで終了した場合にのみ処理されます。ユーザーがゼロ以外の終了コードで終了した場合は、以下のエラーコードの一つとして伝搬されるはずです。

ユーザースクリプトがこれらのコードで終了した場合、実行可能ファイルの終了コードに反映される必要があります。

ビルドの失敗

GitLab RunnerはBUILD_FAILURE_EXIT_CODE 環境変数を BUILD_FAILURE_EXIT_CODE提供しBUILD_FAILURE_EXIT_CODE 、実行変数がユーザージョブの失敗をGitLab Runnerに通知するための終了コードとして使用 BUILD_FAILURE_EXIT_CODEします。BUILD_FAILURE_EXIT_CODE もし実行ファイルがこのコードで終了した BUILD_FAILURE_EXIT_CODE場合、GitLab CIではビルドは失敗とみなされます。

ユーザーが.gitlab-ci.yml ファイル内部で定義したスクリプトがゼロ以外のコードで終了した場合、run_execBUILD_FAILURE_EXIT_CODE の値で終了する必要があります。

BUILD_FAILURE_EXIT_CODE ハードコードされた値の代わりにBUILD_FAILURE_EXIT_CODE を使用して終了することを強くお勧めします。

システム障害

SYSTEM_FAILURE_EXIT_CODE で指定されたエラーコードでプロセスを終了することで、GitLab Runner にシステム障害を送信することができます。 このエラーコードが返された場合、特定のステージで GitLab Runner はステージを再試行し、再試行がどれも成功しなかった場合、ジョブは失敗としてマークされます。

以下は、どのステージが何回再試行されるかの表です。

ステージ名試行回数各再試行間の待機時間
prepare_exec33秒
get_sources GET_SOURCES_ATTEMPTS 変数の値。(デフォルト 1)0秒
restore_cache RESTORE_CACHE_ATTEMPTS 変数の値。(デフォルト 1)0秒
download_artifacts ARTIFACT_DOWNLOAD_ATTEMPTS 変数の値。(デフォルト 1)0秒
note
ハードコードされた値ではなく、SYSTEM_FAILURE_EXIT_CODE を使用して終了することを強くお勧めします。なぜなら、この値はどのリリースでも変更される可能性があり、バイナリやスクリプトを将来的にも使えるようにするためです。

ジョブ応答

文書化されたCI/CD 変数の優先順位に従って、ジョブレベルのCUSTOM_ENV_ 変数を変更することができます。この機能は望ましいものですが、信頼されたジョブコンテキストが必要な場合、完全なJSONジョブレスポンスが自動的に提供されます。ランナーはJOB_RESPONSE_FILE 環境変数で参照される一時ファイルを生成します。このファイルはすべてのステージに存在し、クリーンアップの間に自動的に削除されます。

$ cat ${JOB_RESPONSE_FILE}
{"id": 123456, "token": "jobT0ken",...}