GitLab CI/CD設定ファイルの最適化

GitLab CI/CD設定ファイルの複雑さや重複した設定を減らすには、次のような方法があります:

  • アンカー (&) 、エイリアス (*) 、マップマージ (<<) のような YAML 固有の機能。YAMLの様々な機能についてもっと読む
  • extends キーワード はより柔軟で読みやすくなっています。可能であればextends を使うべきです。

アンカー

YAML には ‘アンカー’ と呼ばれる機能があります。

プロパティを複製もしくは継承するためにアンカーを使います。ジョブのテンプレートを提供するために隠しジョブでアンカーを使います。キーが重複している場合、最新のキーが優先され、他のキーより優先されます。

特定の場合 (スクリプトのための YAML アンカー を参照)、YAML アンカーを使用して、別の場所で定義された複数のコンポーネントを持つ配列を作ることができます。たとえば

.default_scripts: &default_scripts
  - ./default-script1.sh
  - ./default-script2.sh

job1:
  script:
    - *default_scripts
    - ./job-script.sh

include キーワードを使う場合、複数のファイルにまたがって YAML アンカーを使うことはできません。アンカーは定義されたファイルでのみ有効です。異なる YAML ファイルの設定を再利用するには、!reference タグ またはextends キーワード を使います。

次の例はアンカーとマップのマージを使っています。この例では、.job_template の設定を継承する2つのジョブ、test1test2 が作成され、それぞれ独自のカスタムscript が定義されています:

.job_template: &job_configuration  # Hidden yaml configuration that defines an anchor named 'job_configuration'
  image: ruby:2.6
  services:
    - postgres
    - redis

test1:
  <<: *job_configuration           # Add the contents of the 'job_configuration' alias
  script:
    - test1 project

test2:
  <<: *job_configuration           # Add the contents of the 'job_configuration' alias
  script:
    - test2 project

& はアンカーの名前を設定し (job_configuration)、<< は「指定されたハッシュを現在のハッシュにマージする」ことを意味し、* は指定されたアンカーを含みます (job_configuration 再び)。この例の拡張版は

.job_template:
  image: ruby:2.6
  services:
    - postgres
    - redis

test1:
  image: ruby:2.6
  services:
    - postgres
    - redis
  script:
    - test1 project

test2:
  image: ruby:2.6
  services:
    - postgres
    - redis
  script:
    - test2 project

アンカーを使って2つのサービスセットを定義することができます。例えば、test:postgrestest:mysql は、.job_template で定義されたscript を共有しますが、.postgres_services.mysql_servicesで定義されたservices は、異なるものを使用します:

.job_template: &job_configuration
  script:
    - test project
  tags:
    - dev

.postgres_services:
  services: &postgres_configuration
    - postgres
    - ruby

.mysql_services:
  services: &mysql_configuration
    - mysql
    - ruby

test:postgres:
  <<: *job_configuration
  services: *postgres_configuration
  tags:
    - postgres

test:mysql:
  <<: *job_configuration
  services: *mysql_configuration

拡張バージョンは次のとおりです:

.job_template:
  script:
    - test project
  tags:
    - dev

.postgres_services:
  services:
    - postgres
    - ruby

.mysql_services:
  services:
    - mysql
    - ruby

test:postgres:
  script:
    - test project
  services:
    - postgres
    - ruby
  tags:
    - postgres

test:mysql:
  script:
    - test project
  services:
    - mysql
    - ruby
  tags:
    - dev

隠されたジョブがテンプレートとして便利に使われていることがわかります。tags: [postgres]tags: [dev] を上書きします。

スクリプトのためのYAMLアンカー

GitLab 12.5で導入されました

YAMLアンカーを script,before_script,after_script で使うことで、複数のジョブで定義済みのコマンドを使うことができます:

.some-script-before: &some-script-before
  - echo "Execute this script first"

.some-script: &some-script
  - echo "Execute this script second"
  - echo "Execute this script too"

.some-script-after: &some-script-after
  - echo "Execute this script last"

job1:
  before_script:
    - *some-script-before
  script:
    - *some-script
    - echo "Execute something, for this job only"
  after_script:
    - *some-script-after

job2:
  script:
    - *some-script-before
    - *some-script
    - echo "Execute something else, for this job only"
    - *some-script-after

設定セクションを再利用するにはextends を使います。

複数のジョブで設定を再利用するためにextends キーワード を使うことができます。これはYAML アンカーに似ていますが、よりシンプルで、 extendsincludesと一緒に使うことができます。

extends は複数レベルの継承をサポートします。複雑さが増すので3つ以上のレベルを使うことは避けるべきですが、11個まで使うことができます。以下の例では、2つのレベルの継承を行っています:

.tests:
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"

.rspec:
  extends: .tests
  script: rake rspec

rspec 1:
  variables:
    RSPEC_SUITE: '1'
  extends: .rspec

rspec 2:
  variables:
    RSPEC_SUITE: '2'
  extends: .rspec

spinach:
  extends: .tests
  script: rake spinach

からキーを除外します。extends

拡張コンテンツからキーを除外するには、そのキーをnull に割り当てる必要があります:

.base:
  script: test
  variables:
    VAR1: base var 1

test1:
  extends: .base
  variables:
    VAR1: test1 var 1
    VAR2: test2 var 2

test2:
  extends: .base
  variables:
    VAR2: test2 var 2

test3:
  extends: .base
  variables: {}

test4:
  extends: .base
  variables: null

マージ設定:

test1:
  script: test
  variables:
    VAR1: test1 var 1
    VAR2: test2 var 2

test2:
  script: test
  variables:
    VAR1: base var 1
    VAR2: test2 var 2

test3:
  script: test
  variables:
    VAR1: base var 1

test4:
  script: test
  variables: null

extendsinclude

異なる設定ファイルの設定を再利用するには、extendsinclude を組み合わせてください。

次の例では、scriptincluded.yml ファイルで定義されています。次に、.gitlab-ci.yml ファイルで、extendsscript の内容を参照します:

  • included.yml:

     .template:
       script:
         - echo Hello!
    
  • .gitlab-ci.yml:

     include: included.yml
       
     useTemplate:
       image: alpine
       extends: .template
    

マージの詳細

extends を使ってハッシュをマージすることはできますが、配列をマージすることはできません。マージに使われるアルゴリズムは “最も近いスコープが勝つ “です。キーが重複している場合、GitLabはキーを元に逆ディープマージを行います。最後のメンバーからのキーは、常に他のレベルで定義されたものを上書きします。例えば

.only-important:
  variables:
    URL: "http://my-url.internal"
    IMPORTANT_VAR: "the details"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "stable"
  tags:
    - production
  script:
    - echo "Hello world!"

.in-docker:
  variables:
    URL: "http://docker-url.internal"
  tags:
    - docker
  image: alpine

rspec:
  variables:
    GITLAB: "is-awesome"
  extends:
    - .only-important
    - .in-docker
  script:
    - rake rspec

結果はこのようになりますrspec ジョブ:

rspec:
  variables:
    URL: "http://docker-url.internal"
    IMPORTANT_VAR: "the details"
    GITLAB: "is-awesome"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "stable"
  tags:
    - docker
  image: alpine
  script:
    - rake rspec

この例では:

  • variables のセクションはマージされますが、URL: "http://docker-url.internal"URL: "http://my-url.internal" を上書きします。
  • tags: ['docker']tags: ['production'] を上書きします。
  • script はマージしませんが、script: ['rake rspec']script: ['echo "Hello world!"'] を上書きします。配列をマージするためにYAML アンカーを使うことができます。

!reference タグ

!reference カスタムYAMLタグを使って他のジョブセクションからキーワード設定を選択し、現在のセクションで再利用 !referenceします。!reference YAMLアンカーとは異なり、 !referenceタグを使ってインクルードされた設定ファイルから設定を再利用することもできます。

次の例では、2つの異なる場所からscriptafter_scripttest ジョブで再利用されています:

  • setup.yml:

     .setup:
       script:
         - echo creating environment
    
  • .gitlab-ci.yml:

     include:
       - local: setup.yml
       
     .teardown:
       after_script:
         - echo deleting environment
       
     test:
       script:
         - !reference [.setup, script]
         - echo running my own command
       after_script:
         - !reference [.teardown, after_script]
    

次の例では、test-vars-1.vars のすべての変数を再利用し、test-vars-2 は特定の変数を選択し、新しいMY_VAR 変数として再利用します。

.vars:
  variables:
    URL: "http://my-url.internal"
    IMPORTANT_VAR: "the details"

test-vars-1:
  variables: !reference [.vars, variables]
  script:
    - printenv

test-vars-2:
  variables:
    MY_VAR: !reference [.vars, variables, IMPORTANT_VAR]
  script:
    - printenv

scriptbefore_script!reference のタグを入れ子にします。after_script

GitLab 14.8で導入されました

script,before_script,after_script セクションでは、!reference タグを 10 レベルまでネストできます。より複雑なスクリプトを作るときに、ネストしたタグを使って再利用可能なセクションを定義します。例えば

.snippets:
  one:
    - echo "ONE!"
  two:
    - !reference [.snippets, one]
    - echo "TWO!"
  three:
    - !reference [.snippets, two]
    - echo "THREE!"

nested-references:
  script:
    - !reference [.snippets, three]

この例では、nested-references ジョブは 3 つのecho コマンドをすべて実行します。

!reference タグをサポートするように IDE を設定します。

パイプラインエディターは !reference タグをサポートします。しかし、カスタムYAMLタグのスキーマルールは!reference デフォルトではエディターによって無効なものとして扱われるかもしれません !reference。タグを受け入れる!reference ようにエディタを設定 !referenceできます。たとえば

  • VS Code では、settings.json ファイルのcustomTags を解析するようにvscode-yaml を設定できます:

     "yaml.customTags": [
        "!reference sequence"
     ]
    
  • Sublime Text では、LSP-yaml パッケージを使用している場合、LSP-yaml ユーザー設定でcustomTags を設定できます:

     {
       "settings": {
         "yaml.customTags": ["!reference sequence"]
       }
     }