GitLab CI/CD 구성 파일 최적화

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

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 구성을 상속하는 test1test2 두 개의 작업을 각각 자신만의 사용자 정의 script로 만듭니다:

.job_template: &job_configuration  # 'job_configuration'이라는 이름의 앵커를 정의하는 숨겨진 yaml 구성
  image: ruby:2.6
  services:
    - postgres
    - redis

test1:
  <<: *job_configuration           # 'job_configuration' 별칭의 내용을 추가
  script:
    - test1 project

test2:
  <<: *job_configuration           # 'job_configuration' 별칭의 내용을 추가
  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

두 세트의 서비스를 정의하는 데 앵커를 사용할 수 있습니다. 예를 들어, 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 앵커

여러 작업에서 미리 정의된 명령을 사용하려면 스크립트, before_script, 및 after_script와 함께 YAML 앵커를 사용할 수 있습니다:

.some-script-before: &some-script-before
  - echo "이 스크립트를 먼저 실행하세요"

.some-script: &some-script
  - echo "이 스크립트를 두 번째로 실행하세요"
  - echo "이 스크립트도 실행하세요"

.some-script-after: &some-script-after
  - echo "이 스크립트를 마지막에 실행하세요"

job1:
  before_script:
    - *some-script-before
  script:
    - *some-script
    - echo "이 작업에 대해서만 무언가를 실행하세요"
  after_script:
    - *some-script-after

job2:
  script:
    - *some-script-before
    - *some-script
    - echo "다른 작업에 대해서 무언가를 실행하세요"
    - *some-script-after

구성을 재사용하기 위해 extends 사용

여러 작업에서 구성을 재사용하려면 extends 키워드를 사용할 수 있습니다. 이는 YAML 앵커와 유사하지만 더 간단하며, 포함과 함께 extends를 사용할 수 있습니다.

extends는 다단계 상속을 지원합니다. 추가 복잡성으로 인해 세 개 이상의 수준을 사용하는 것을 피해야 하지만, 최대 11개까지 사용할 수 있습니다. 다음 예에는 두 수준의 상속이 있습니다:

.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를 결합하십시오.

다음 예에서 included.yml 파일에 script가 정의되어 있습니다. 그런 다음 .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 태그를 사용하여 다른 작업 섹션에서 키워드 구성을 선택하고 현재 섹션에서 재사용할 수 있습니다. YAML 앵커와는 달리, !reference 태그를 사용하여 포함된 구성 파일에서 구성을 재사용할 수 있습니다.

다음 예제에서는 두 개의 다른 위치에서 scriptafter_scripttest 작업에서 재사용됩니다:

  • configs.yml:

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

    include:
      - local: configs.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

!reference 태그를 parallel:matrix 키워드와 함께 사용할 때는 알려진 문제가 있습니다.

script, before_script, 및 after_script에서 !reference 태그 중첩하기

  • !reference에 대한 지원은 GitLab 16.9에서 stages 키워드와 함께 도입되었습니다.

scripts, before_scriptafter_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 작업은 세 개의 echo 명령을 모두 실행합니다.

!reference 태그를 지원하도록 IDE 구성하기

파이프라인 편집기!reference 태그를 지원합니다. 그러나 기본적으로 사용 중인 편집기에서 !reference와 같은 사용자 정의 YAML 태그에 대한 스키마 규칙이 유효하지 않다고 간주될 수 있습니다.

일부 편집기를 구성하여 !reference 태그를 허용할 수 있습니다. 예를 들어:

  • VS Code에서는 settings.json 파일에서 vscode-yamlcustomTags를 구문 분석하도록 설정할 수 있습니다:

    "yaml.customTags": [
       "!reference sequence"
    ]
    
  • Sublime Text에서 LSP-yaml 패키지를 사용하는 경우 LSP-yaml 사용자 설정에서 customTags를 설정할 수 있습니다:

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