ランナーのオートスケール設定

オートスケール機能は GitLab Runner 1.1.0 で導入されました。

オートスケールは、より弾力的でダイナミックな方法でリソースを利用する能力を提供します。

オートスケールが可能なRunnerのおかげで、インフラストラクチャにはいつでも必要なだけのビルドインスタンスしか含まれません。 オートスケールのみを使用するようにRunnerを設定すると、Runnerがインストールされているシステムは、Runnerが作成するすべてのマシンの拠点として機能します。

概要

この機能が有効で適切に設定されている場合、ジョブは_オンデマンドで_作成されたマシンで実行されます。 これらのマシンはジョブ終了後、次のジョブの実行を待つか、設定されたIdleTimeの後に削除することができます。多くのクラウドプロバイダーの場合、これは既に使用されているインスタンスのコストを利用するのに役立ちます。

以下は、GitLab.comのGitLab Community Editionプロジェクトでテストされたrunner autoscale機能の実例です:

Real life example of autoscaling

Chart上の各マシンは独立したクラウドインスタンスであり、Dockerコンテナ内でジョブを実行しています。

システム要件

オートスケールを設定する前に、以下を行う必要があります:

  • 環境を整えましょう
  • オプションで、GitLabが提供するDocker machineのフォークバージョンを使用すると、いくつかの修正が追加されます。

対応クラウドプロバイダー

オートスケールの仕組みはDockerMachineに基づいています。 サポートされている仮想化/クラウドプロバイダのパラメータはすべて、Docker Machineドライバのドキュメントで入手できます。

ランナーの構成

このセクションでは、オートスケール機能の観点から重要なパラメータのみを説明します。 より詳細な設定については、詳細設定をお読みください。

Runner グローバルオプション

パラメータ 説明
concurrent 整数 グローバルに同時に実行できるジョブの数を制限します。 これは、定義された_すべての_ランナー、ローカルおよびオートスケールを使用するジョブの数の上限です。limit ([[runners]] セクションより) およびIdleCount ([runners.machine] セクションより) とともに、作成されるマシンの上限に影響します。

[[runners]] オプション

パラメータ 説明
executor オートスケール機能を使用するには、executordocker+machine またはdocker-ssh+machineに設定する必要があります。
limit 整数 この特定のトークンが同時に処理できるジョブの数を制限します。0は単に制限しないことを意味します。 オートスケールの場合、このプロバイダが作成するマシンの上限です(concurrentIdleCountと併用)。

[runners.machine] オプション

設定パラメータの詳細はGitLab Runner - Advanced Configuration - The[runners.machine] sectionにあります。

[runners.cache] オプション

設定パラメータの詳細はGitLab Runner - Advanced Configuration - The[runners.cache] セクションにあります。

追加設定情報

また、IdleCount = 0を設定すると、特別なモードもあります。 このモードでは、各ジョブの前に、マシンは常に オンデマンドで作成されます(_アイドル_状態のマシンがない場合)。 ジョブが終了すると、オートスケーリング・アルゴリズムは、以下に説明するのと同じように動作します。 マシンは次のジョブを待ち、IdleTime の期間が経過しても、1つも実行されない場合、マシンは削除されます。 ジョブがない場合、_アイドル_状態のマシンはありません。

オートスケーリング・アルゴリズムとパラメータ

オートスケーリング・アルゴリズムは、IdleCountIdleTimelimitの3つの主要パラメータに基づいています。

GitLab Runnerがオートスケールモードの場合、全てのマシンを監視し、常に_Idle_状態のマシンがIdleCount

同時に、GitLab Runnerは各マシンの_Idle_状態の時間をチェックしています。 時間がIdleTime の値を超えた場合、マシンは自動的に削除されます。


例:GitLab Runnerに以下のオートスケールパラメータを設定したとします:

[[runners]]
  limit = 10
  # (...)
  executor = "docker+machine"
  [runners.machine]
    IdleCount = 2
    IdleTime = 1800
    # (...)

ジョブがキューに入っていない最初の段階で、GitLab Runnerは2台のマシン(IdleCount = 2)を起動し、_Idle_状態にします。IdleTime も30分に設定していることに注目してください(IdleTime = 1800)。

ここで、GitLab CIに5つのジョブがキューに入っているとします。最初の2つのジョブは、2台ある_Idle_マシンに送られます。GitLab Runnerは、_Idle_マシンの数がIdleCount (0 < 2)より少ないことに気づき、2台の新しいマシンを起動します。次に、キューから次の2つのジョブが新しく作成されたマシンに送られます。ここでも、_Idle_マシンの数はIdleCountより少ないので、GitLab Runnerは2台の新しいマシンを起動し、最後のキューに入ったジョブは_Idle_マシンの1台に送られます。

1台の_Idle_マシンができたので、GitLab RunnerはIdleCount。キューに新しいジョブがないので、これら2台のマシンは_Idleの_ままとなり、GitLab Runnerは満足します。


5つのジョブがキューに入った後、新しいマシンが作成され、合計で7台のマシンが稼働しました。 そのうち5台がジョブを実行中で、2台が次のジョブを待つ_アイドル_状態でした

GitLab Runnerは、IdleCountが満たされるまで、ジョブの実行に使われたマシンごとに新しい_Idle_マシンを作成します。これらのマシンは、limit パラメータで limit定義された数まで作成されますlimitlimitGitLablimit Runnerが limit作成されたマシンの総数が多いlimit ことに気づいたら limit、自動スケーリングを停止し、新しいジョブはマシンが_Idle_状態に戻り始めるまでジョブキューで待つ必要があります。

上記の例では、常にアイドル状態のマシンが2台あることになります。IdleTimeが適用されるのは、IdleCountマシンの台数が. IdleCountを超えた場合のみです。


スケールダウン:ジョブが終了した後、マシンは_Idle_状態に設定され、次のジョブが実行されるのを待ちます。 キューに新しいジョブがないとします。IdleTime で指定された時間が経過すると、_Idle_マシンは削除されます。この例では、30分後に全てのマシンが削除され(最後のジョブ実行が終了してから30分後に各マシンが削除されます)、GitLab Runnerは例の最初と同じように、IdleCount の_Idle_マシンを稼働させ続けます。


というわけで、まとめます:

  1. ランナースタート
  2. Runnerは2台のアイドルマシンを作成します。
  3. ランナーは1つのジョブを選択
  4. Runnerは、常に2台のアイドル状態のマシンを持つという強い要求を満たすために、もう1台マシンを作成します。
  5. ジョブ終了後、3台のアイドリングマシンがあります。
  6. 3台のアイドリングマシンのうち1台が、前回ジョブを選んだ時間からIdleTime を超えると、そのマシンは削除されます。
  7. Runnerは、ジョブの高速ピッキングのために、少なくとも2台のアイドルマシンを常に待機させています。

下記はジョブステータスとマシンステータスの比較表です:

Autoscale state chart

concurrentlimitIdleCount はどのようにしてランニングマシンの上限を生成するのでしょうか?

limitconcurrent を何に設定すればいいかを教えてくれる魔法の方程式は存在しません。ニーズに合わせて行動してください。_アイドル_マシンのIdleCount を持つことはスピードアップ機能です。 インスタンスが作成されるまで10s/20s/30sも待つ必要はありません。 しかし、ユーザーとしては、(お金を払う必要のある)すべてのマシンを_アイドル_状態ではなく、ジョブを実行するようにしたいはずです。 そのため、concurrentlimit は、お金を払ってもいいマシンの最大数を実行する値に設定すべきです。IdleCountについては、ジョブキューが空のときに、_使用されていない_マシンが最小量生成される値に設定すべきです。

次のような例を考えてみましょう:

concurrent=20

[[runners]]
  limit = 40
  [runners.machine]
    IdleCount = 10

上記のシナリオでは、マシンの総量は30台です。limit (ビルドとアイドル)マシンの総量は40台です。アイドルマシンは10台ですが、concurrent ジョブは20台です。つまり、ジョブを実行しているマシンの同時実行台数は20台、アイドルマシンは10台で、合計は30台です。

しかし、limit 、作成可能なマシンの総量よりも少ない場合はどうなるのでしょうか?以下の例でそのケースを説明します:

concurrent=20

[[runners]]
  limit = 25
  [runners.machine]
    IdleCount = 10

この例では、同時実行ジョブは最大20ジョブ、作成されるマシンは最大25台です。アイドル状態のマシンに関する最悪のシナリオでは、limit が25であるため、アイドル状態のマシンを10台用意することはできず、5台しか用意できません。

オートスケーリング期間の設定

GitLab Runner 13.0で導入されました。

オートスケーリングは、時間帯によって異なる値に設定できます。 組織には、ジョブの実行が急増する時間帯が定期的にある場合と、ジョブがほとんどない時間帯がある場合があります。 たとえば、ほとんどの営利企業は、月曜日から金曜日まで、午前10時から午後6時までといった決まった時間帯に働きます。 それ以外の週の夜間と週末は、パイプラインが開始されません。

これらの期間は、[[runners.machine.autoscaling]] セクションの助けを借りて設定することができます。各セクションは、Periodsのセットに基づいて、IdleCountIdleTime を設定することができます。

オートスケーリング期間の仕組み

[runners.machine] の設定では、複数の[[runners.machine.autoscaling]] セクションを追加することができ、それぞれにIdleCountIdleTimePeriodsTimezone プロパティを設定することができます。最も一般的なシナリオから最も具体的なシナリオの順に、各構成ごとにセクションを定義する必要があります。

すべてのセクションが解析され、現在の時刻に最後にマッチしたものがアクティブになります。 マッチするものがない場合は、[runners.machine] のルートの値が使われます。

使用例:

[runners.machine]
  MachineName = "auto-scale-%s"
  MachineDriver = "digitalocean"
  IdleCount = 10
  IdleTime = 1800
  [[runners.machine.autoscaling]]
    Periods = ["* * 9-17 * * mon-fri *"]
    IdleCount = 50
    IdleTime = 3600
    Timezone = "UTC"
  [[runners.machine.autoscaling]]
    Periods = ["* * * * * sat,sun *"]
    IdleCount = 5
    IdleTime = 60
    Timezone = "UTC"

この設定では、平日の9時から17時(UTC)までの間、オペレーション時間中の大量のトラフィックを処理するために、マシンがオーバープロビジョニングされます。 週末には、トラフィックの減少を考慮して、IdleCount が 5 に下がります。それ以外の時間帯は、ルート内のデフォルト値 -IdleCount = 10IdleTime = 1800- が使用されます。

注意:指定した期間の最後の59秒は、その期間の一部とはみなされません。 詳細については、イシュー#2170を参照してください。

"Australia/Sydney"のように、ピリオドのTimezone を指定することができます。指定しない場合、すべてのランナーのホストマシンのシステム設定が使用されます。このデフォルトは、Timezone = "Local" と明示的に指定することができます。

[[runner.machine.autoscaling]] セクションの構文についての詳細はGitLab Runner - Advanced Configuration - The[runners.machine] sectionを参照してください。

オフピーク時間モードの設定(非推奨)

この設定は非推奨であり、14.0で削除される予定です。 代わりにオートスケーリング期間を使用してください。 両方の設定が使用されている場合、オフピーク設定は無視されます。

オートスケールは、_オフピーク_時間モード期間をサポートして設定することができます。

_オフピークとは_何ですか?

組織によっては、定期的に仕事がない時間帯を設定することができます。 この時間帯は_オフピークと_呼ばれます。

_オフピークの_時間帯が発生する内部では、この時間帯にジョブが実行されないことが確実な場合、_アイドル_マシンの料金を支払いたくはないでしょう。特に、IdleCount が大きな数字に設定されている場合はなおさらです。

どのように機能しているのですか?

_オフピークの_設定は、OffPeakPeriodsOffPeakTimezoneOffPeakIdleCountOffPeakIdleTimeの4つのパラメータで行います。OffPeakPeriods の設定には、_オフピークタイムモードを_いつオンにするかを定義する cron スタイルのパターンの配列が含まれています。 例えば、以下のようになります:

[runners.machine]
  OffPeakPeriods = [
    "* * 0-8,18-23 * * mon-fri *",
    "* * * * * sat,sun *"
  ]

Machinesスケジューラはアレイからすべてのパターンをチェックし、そのうちの少なくとも1つが現在の時刻を表していれば、_オフピークモードが_有効になります。

_オフピークモードが_有効になっている場合、マシンスケジューラは、IdleCount の代わりにOffPeakIdleCount を、IdleTime の代わりにOffPeakIdleTimeを使用します。 オートスケーリングアルゴリズムは変更されず、パラメータのみが変更されます。マシンスケジューラは、OffPeakPeriods パターンのどれもが満たされていないことを発見すると、IdleCountIdleTime の設定に切り替えます。

ディストリビューション・ランナー・キャッシング

注:独自のキャッシュサーバーをインストールする方法をお読みください。

ジョブを高速化するために、GitLab Runnerは選択したディレクトリやファイルを保存し、後続のジョブ間で共有するキャッシュメカニズムを提供します。

ジョブが同じホストで実行されている場合は問題ありませんが、Runnerのオートスケール機能を使い始めると、ほとんどのジョブが新しい(またはほとんど新しい)ホストで実行されるようになり、新しいDockerコンテナで各ジョブが実行されるようになります。 その場合、キャッシュ機能を利用することができなくなります。

このイシューを克服するために、オートスケール機能とともに、ディストリビューション・ランナー・キャッシュ機能が導入されました。

使用するDockerホスト間でキャッシュを共有するために、設定されたオブジェクトストレージサーバを使用します。 キャッシュのリストアやアーカイブを行う際、GitLab Runnerはサーバにクエリを発行し、それぞれアーカイブをダウンロードまたはアップロードします。

分散キャッシュを有効にするには、[runners.cache] ディレクティブを使って、config.toml で定義する必要があります:

[[runners]]
  limit = 10
  executor = "docker+machine"
  [runners.cache]
    Type = "s3"
    Path = "path/to/prefix"
    Shared = false
    [runners.cache.s3]
      ServerAddress = "s3.example.com"
      AccessKey = "access-key"
      SecretKey = "secret-key"
      BucketName = "runner"
      Insecure = false

上記の例では、S3のURLはhttp(s)://<ServerAddress>/<BucketName>/<Path>/runner/<runner-id>/project/<id>/<cache-key>の構造に従っています。

2つ以上のRunner間でキャッシュを共有するには、Shared フラグをtrueに設定します。これにより、URL (runner/<runner-id>)からRunnerトークンが削除され、設定されたすべてのRunnerが同じキャッシュを共有します。キャッシュ共有が有効な場合、Path を設定してRunner間でキャッシュを分離することもできます。

分散コンテナレジストリミラーリング

注:コンテナレジストリのインストール方法をお読みください。

Dockerコンテナ内で実行されるジョブを高速化するために、Dockerレジストリミラーリングサービスを使用することができます。 これはDockerマシンと使用されている全てのレジストリの間にプロキシを提供します。 イメージはレジストリミラーによって一度ダウンロードされます。 新しいホスト、またはイメージが利用できない既存のホストでは、設定されたレジストリミラーからダウンロードされます。

ミラーがDockerマシンのLANに存在するのであれば、イメージのダウンロードステップは各ホスト上でより速くなるはずです。

Dockerレジストリのミラーリングを設定するには、config.tomlの設定にMachineOptions を追加する必要があります:

[[runners]]
  limit = 10
  executor = "docker+machine"
  [runners.machine]
    (...)
    MachineOptions = [
      (...)
      "engine-registry-mirror=http://10.11.12.13:12345"
    ]

10.11.12.13:12345 はレジストリミラーがDockerサービスからの接続をリッスンしているIPアドレスとポートです。 Docker Machineによって作成された各ホストからアクセスできる必要があります。

完全な例config.toml

以下のconfig.tomldigitalocean Docker Machine ドライバを使っています:

concurrent = 50   # All registered Runners can run up to 50 concurrent jobs

[[runners]]
  url = "https://gitlab.com"
  token = "RUNNER_TOKEN"             # Note this is different from the registration token used by `gitlab-runner register`
  name = "autoscale-runner"
  executor = "docker+machine"        # This Runner is using the 'docker+machine' executor
  limit = 10                         # This Runner can execute up to 10 jobs (created machines)
  [runners.docker]
    image = "ruby:2.6"               # The default image used for jobs is 'ruby:2.6'
  [runners.machine]
    IdleCount = 5                    # There must be 5 machines in Idle state - when Off Peak time mode is off
    IdleTime = 600                   # Each machine can be in Idle state up to 600 seconds (after this it will be removed) - when Off Peak time mode is off
    MaxBuilds = 100                  # Each machine can handle up to 100 jobs in a row (after this it will be removed)
    MachineName = "auto-scale-%s"    # Each machine will have a unique name ('%s' is required)
    MachineDriver = "digitalocean"   # Docker Machine is using the 'digitalocean' driver
    MachineOptions = [
        "digitalocean-image=coreos-stable",
        "digitalocean-ssh-user=core",
        "digitalocean-access-token=DO_ACCESS_TOKEN",
        "digitalocean-region=nyc2",
        "digitalocean-size=4gb",
        "digitalocean-private-networking",
        "engine-registry-mirror=http://10.11.12.13:12345"   # Docker Machine is using registry mirroring
    ]
    [[runners.machine.autoscaling]]  # Define periods with different settings
      Periods = ["* * 9-17 * * mon-fri *"] # Every workday between 9 and 17 UTC
      IdleCount = 50
      IdleTime = 3600
      Timezone = "UTC"
    [[runners.machine.autoscaling]]
      Periods = ["* * * * * sat,sun *"] # During the weekends
      IdleCount = 5
      IdleTime = 60
      Timezone = "UTC"
  [runners.cache]
    Type = "s3"
    [runners.cache.s3]
      ServerAddress = "s3-eu-west-1.amazonaws.com"
      AccessKey = "AMAZON_S3_ACCESS_KEY"
      SecretKey = "AMAZON_S3_SECRET_KEY"
      BucketName = "runner"
      Insecure = false

MachineOptions パラメータには、Digital Ocean上でホストされているマシンを起動するためにDocker Machineが使用するdigitaloceanドライバのオプションと、Docker Machine自体のオプション (engine-registry-mirror) が含まれていることに注意してください。