LoginSignup
9
3

More than 5 years have passed since last update.

GitLab での 並列 CI パターン

Last updated at Posted at 2018-12-28

GitLabで並列にCIを行う方法について調査しました。

GitLab 11.5 でテストしていますが、現時点(2018年12月)の最新版 11.6 でも同じはずです。
もし差分が見つかれば随時反映します。(ので、詳しい方からのコメントもお待ちしています)

同一stageに複数jobを定義

一番基本的な戦略として、並列にビルド・デプロイする処理を、それぞれ「同じstageに属するjob」として定義する方法があります。

.gitlab-ci.yml の例

stages:
  - a
  - b

.job_a_common:
  script: mkdir build && touch build/${CI_JOB_NAME}.txt
  artifacts:
    paths:
      - build

job_a1:
  stage: a
  extends: .job_a_common

job_a2:
  stage: a
  extends: .job_a_common

job_a3:
  stage: a
  extends: .job_a_common

job_b:
  stage: b
  script: ls -l build/

実行結果

下の様にjobが並列に動作します。

image.png

artifacts をまとめることができて、後のstageでそれらを扱うこともできます。

: job_b の出力
$ ls -l build/
total 0
-rw-r--r--    1 root     root             0 Dec 28 04:38 job_a1.txt
-rw-r--r--    1 root     root             0 Dec 28 04:38 job_a2.txt
-rw-r--r--    1 root     root             0 Dec 28 04:38 job_a3.txt
Job succeeded

parallelによる多重度指定

2018年11月にリリースされた GitLab 11.5 から、 parallel というキーワードが導入されました。
https://docs.gitlab.com/ee/ci/yaml/#parallel

指定した数値を多重度として、jobを並列実行することができます。
それぞれのjobの処理内容は、環境変数 CI_NODE_INDEX CI_NODE_TOTAL を使って変化させることができます。

.gitlab-ci.yml の例

stages:
  - a
  - b

job_a:
  stage: a
  parallel: 3
  script: mkdir build && touch build/${CI_NODE_INDEX}_of_${CI_NODE_TOTAL}.txt
  artifacts:
    paths:
      - build

job_b:
  stage: b
  script: ls -l build/

実行結果

Pipelineの表示では、ぱっと見では並列に見えませんが、よく見ると多重度3が見えています。

image.png

Jobsの表示では、確かに並列にJobが動いていることがわかります。

image.png

artifactsについても、複数Jobを定義した場合と同様に扱うことができます。

: job_b の出力
$ ls -l build/
total 0
-rw-r--r--    1 root     root             0 Dec 28 04:45 1_of_3.txt
-rw-r--r--    1 root     root             0 Dec 28 04:45 2_of_3.txt
-rw-r--r--    1 root     root             0 Dec 28 04:46 3_of_3.txt
Job succeeded

ファイル単位で並列にビルド (parallelの応用)

parallelでは並列多重度を静的に指定することしかできません。
例えば「ファイル毎の並列ビルド」など、多重度を動的に決定したいことはあると思います。

ですが、現時点(2018年末、GitLab 11.6リリース時点)でそれを行う方法はありません。

機能の提案はされているので、将来的には可能になる可能性はあります。
https://gitlab.com/gitlab-org/gitlab-ce/issues/23455

少し妥協して、適当な多重度で立ち上げたJobで対象ソースを切り替えることで、ビルドを平準化することができます。
以降はその例です。

repository構造

$ tree
.
├── 1.txt
├── 2.txt
├── 3.txt
├── 4.txt
└── 5.txt

0 directories, 5 files
$ head *.txt
==> 1.txt <==
11111

==> 2.txt <==
22222

==> 3.txt <==
33333

==> 4.txt <==
44444

==> 5.txt <==
55555

.gitlab-ci.yml

stages:
  - a
  - b

job_a:
  stage: a
  parallel: 3
  script:
    - mkdir build
    - NF=$(ls -1 *.txt | wc -l)
    - ls -1 *.txt
      | awk "(NR-1)%${CI_NODE_TOTAL}==${CI_NODE_INDEX}-1"
      | xargs -P$((NF/CI_NODE_TOTAL+1)) -I_ sh -c "cat _ | tee build/_"
  artifacts:
    paths:
      - build

job_b:
  stage: b
  script: head build/*.txt

途中で少々複雑な awk の式がありますが、行数の剰余を取って、順にJobに割り振っているだけです。
また、Job内でもプロセスを並列化するため、対象ソースの数から必要なプロセス数を計算して xargs-P オプションで渡しています。

実行結果

Pipelineの見た目は、前のものと同じなので割愛します。

それぞれのJobの出力を見ると、ちゃんと処理が平準化されていることがわかります。

: job_a 1/3 の出力
$ mkdir build
$ NF=$(ls -1 *.txt | wc -l)
$ ls -1 *.txt | awk "(NR-1)%${CI_NODE_TOTAL}==${CI_NODE_INDEX}-1" | xargs -P$((NF/CI_NODE_TOTAL+1)) -I_ sh -c "cat _ | tee build/_"
44444
11111
: job_a 2/3 の出力
$ mkdir build
$ NF=$(ls -1 *.txt | wc -l)
$ ls -1 *.txt | awk "(NR-1)%${CI_NODE_TOTAL}==${CI_NODE_INDEX}-1" | xargs -P$((NF/CI_NODE_TOTAL+1)) -I_ sh -c "cat _ | tee build/_"
22222
55555
:job_a 3/3 の出力
$ mkdir build
$ NF=$(ls -1 *.txt | wc -l)
$ ls -1 *.txt | awk "(NR-1)%${CI_NODE_TOTAL}==${CI_NODE_INDEX}-1" | xargs -P$((NF/CI_NODE_TOTAL+1)) -I_ sh -c "cat _ | tee build/_"
33333

job_b でも build 以下にファイルが残っているため、意図したとおりに動作したことがわかります。

: job_b の出力
$ head build/*.txt
==> build/1.txt <==
11111

==> build/2.txt <==
22222

==> build/3.txt <==
33333

==> build/4.txt <==
44444

==> build/5.txt <==
55555
Job succeeded

以上です。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3