사용자 정의 실행기

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

GitLab Runner은 기본적으로 지원하지 않는 환경을 위해 사용자 정의 실행기를 제공합니다. 예를 들어, LXD 또는 Libvirt와 같은 환경입니다.

이를 통해 GitLab Runner를 구성하여 환경을 프로비저닝, 실행 및 정리하기 위해 특정 실행 파일을 사용할 수 있는 제어권을 얻을 수 있습니다.

사용자 정의 실행기에 구성하는 스크립트는 드라이버(Drivers)라고 합니다. 예를 들어, LXD 드라이버Libvirt 드라이버를 만들 수 있습니다.

제한 사항

사용자 정의 실행기를 사용할 때 현재 존재하는 일부 제한 사항은 다음과 같습니다:

구성

사용 가능한 몇 가지 구성 키가 있습니다. 일부는 선택적입니다.

다음은 모든 가능한 구성 키를 사용하여 사용자 정의 실행기를 구성하는 예시입니다:

[[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에 있어야 합니다:

단계

사용자 정의 실행기는 작업의 세부 정보를 구성하고, 환경을 준비하고 정리하며 작업 스크립트를 실행하는 데 필요한 단계를 제공합니다. 각 단계는 특정한 작업을 담당하며 고려해야 할 사항이 다릅니다.

사용자 정의 실행기에 의해 실행되는 각 단계는 기본 GitLab Runner 실행기가 해당 단계를 실행할 때 실행됩니다.

실행될 각 단계마다 특정 환경 변수가 실행 파일에 노출되는데, 해당 변수는 실행 중인 특정 작업에 대한 정보를 얻기 위해 사용될 수 있습니다. 모든 단계에서 다음 환경 변수가 사용 가능합니다:

CI/CD 환경 변수 및 미리 정의된 변수는 시스템 환경 변수와의 충돌을 방지하기 위해 CUSTOM_ENV_로 접두사가 붙습니다. 예를 들어, CI_BUILDS_DIRCUSTOM_ENV_CI_BUILDS_DIR로 사용할 수 있습니다.

아래는 각 단계가 실행되는 순서입니다:

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

서비스

서비스CUSTOM_ENV_CI_JOB_SERVICES로 JSON 배열로 노출됩니다.

예시:

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 단계는 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 문자열이 아닌 경우, 해당 단계는 실패하고 두 번 더 다시 시도합니다.

매개변수 유형 필수 허용 여부 설명
builds_dir string 작업 디렉토리가 생성될 기본 디렉토리입니다.
cache_dir string 로컬 캐시가 저장될 기본 디렉토리입니다.
builds_dir_is_shared bool n/a 환경이 동시 작업 간에 공유되는지 여부를 정의합니다.
hostname string 러너가 저장한 작업 “메타데이터”에 연결할 호스트명입니다. 정의되지 않으면 호스트명이 설정되지 않습니다.
driver.name string 드라이버의 사용자 정의 이름입니다. Using custom executor... 라인과 함께 출력됩니다. 정의되지 않으면 드라이버에 대한 정보가 출력되지 않습니다.
driver.version string 드라이버의 사용자 정의 버전입니다. Using custom executor... 라인과 함께 출력됩니다. 정의되지 않으면 이름 정보만이 출력됩니다.
job_env object 작업 실행의 모든 후속 단계에서 환경 변수로 사용 가능한 이름-값 쌍입니다. 작업에 대한 것이 아닌 드라이버에서 사용 가능합니다. 자세한 내용은 job_env 사용법을 참조하십시오.

실행 가능 파일의 STDERR가 작업 로그에 출력됩니다.

사용자는 GitLab 러너가 JSON 문자열을 반환하기 전에 얼마나 오랫동안 기다릴지 지정하려면 config_exec_timeout를 설정할 수 있습니다.

만약 config_exec_args 중 하나라도 정의되어 있다면, 이들은 config_exec에서 정의된 실행 파일에 순서대로 추가됩니다. 예를 들어, 아래와 같이 config.toml 내용이 있다면:

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

GitLab 러너는 /path/to/config Arg1 Arg2로 실행됩니다.

job_env 사용법

job_env 설정의 주요 목적은 작업 실행의 후속 단계로 변수를 전달하는 것입니다.

예를 들어, 암호 준비 등이 매우 비용이 많이 들고 작업 실행 환경과의 연결을 위해 일부 자격 증명을 준비해야 하는 예제 드라이버를 고려해 봅시다. 각 작업 실행 단계prepare, 여러 번의 run 호출 및 cleanup은 별도의 드라이버 실행입니다. 우리의 자격 증명 해결 예제에서 자격증명 제공자에 연결은 매번 수행되어야 합니다.

이 작업이 비용이 많이 든다면, 전체 작업 실행을 위해 한 번만 수행하고, 그 다음에 자격 증명을 모든 작업 실행 단계에 재사용하고 싶을 수 있습니다. 이것이 job_env가 도움이 될 수 있는 곳입니다. 여기서 config_exec 호출 중에 연결하고, 그 후에 job_env로 받은 자격 증명을 전달할 수 있습니다. 이것들은 이후에 prepare_exec, run_execcleanup_exec에 대해 실행되는 사용자 정의 실행기 호출에 추가됩니다. 이를 통해 드라이버는 매번 자격 증명 제공자에 연결하는 대신 변수를 읽고 있는 자격 증명을 사용할 수 있습니다.

이 변수들이 작업 자체에 자동으로 사용 가능한 것은 아님을 이해하는 것이 중요합니다. 이것은 완전히 사용자 정의된 Custom Executor 드라이버의 구현에 따라 완전히 달라집니다.

특정 러너로 실행되는 각 작업에 일련의 변수를 전달하여 작업이 실행될 때마다 동일한 변수를 사용하려는 경우, [[runners]]environment 설정을 살펴보세요.

변수가 동적이고 그 값이 다른 작업 간에 변경될 것으로 예상되는 경우, job_env를 통해 전달하려는 변수가 작업 실행 호출에 추가되도록 드라이버가 구현되어 있는지 확인해야 합니다.

준비

준비 단계는 prepare_exec에 의해 실행됩니다.

이 시점에서 GitLab Runner는 작업에 대해 모든 것을 알고 있습니다(어디에서 실행될지, 어떻게 실행될지). 지금 남은 것은 작업이 실행될 수 있도록 환경이 설정되는 것뿐입니다. GitLab Runner는 prepare_exec에서 지정된 실행 파일을 실행할 것입니다.

이는 환경을 설정하는 데 책임이 있습니다(예: 가상 머신 또는 컨테이너 생성, 서비스 또는 기타 것들). 이 작업이 완료된 후에는 환경이 작업을 실행할 준비가 되었다고 기대합니다.

이 단계는 작업 실행 중에 한 번만 실행됩니다.

사용자는 prepare_exec_timeout를 설정하여 GitLab Runner가 프로세스를 종료하기 전에 환경을 준비하는 데 기다릴 시간 제한을 설정할 수 있습니다.

이 실행 파일에서 반환된 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_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 또는 archive_cache_on_failure
  10. upload_artifacts_on_success 또는 upload_artifacts_on_failure
  11. cleanup_file_variables

참고: GitLab Runner 14.0 이후로 build_scriptstep_script로 대체됩니다. 자세한 정보는 이 이슈를 참조하세요.

위에서 언급된 각 단계마다, run_exec 실행 파일은 다음과 같이 실행될 것입니다:

  • 일반 환경 변수.
  • 두 개의 인수:
    • 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 실행기가 일반적으로 클론하고 다운로드, 사용자 스크립트 실행 및 아래 설명된 모든 다른 단계를 수행하는 모든 스크립트가 포함될 수 있습니다. 스크립트는 다음과 같은 셸일 수 있습니다:

  • Bash
  • PowerShell 데스크톱
  • PowerShell 코어
  • Batch (비권장)

우리는 .gitlab-ci.yml 파일의 기능으로 생긴, step_releasestep_accessibility와 같은 여러 단계를 갖는 step_*를 포함한다. 이 내용을 포함할 수 있습니다.

shell로 구성된 셸을 사용하여 스크립트를 생성합니다. 이 셸은 기본적으로 OS 플랫폼에 대한 기본값을 사용합니다.

아래 표는 각 스크립트가 무엇을 수행하고 해당 스크립트의 주요 목표가 무엇인지에 대한 자세한 설명입니다.

스크립트 이름 스크립트 내용
prepare_script Job이 실행 중인 머신에 대한 간단한 디버그 정보입니다.
get_sources Git 구성을 준비하고 리포지토리를 복제/페치합니다. GitLab이 제공하는 Git 전략의 모든 이점을 얻으므로 이를 그대로 유지하는 것이 좋습니다.
restore_cache 정의된 경우 캐시를 추출합니다. 이는 $PATH에서 gitlab-runner 바이너리를 사용할 수 있다고 기대합니다.
download_artifacts 정의된 경우 아티팩트를 다운로드합니다. 이는 $PATH에서 gitlab-runner 바이너리를 사용할 수 있다고 기대합니다.
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

클린업 단계는 cleanup_exec에 의해 실행됩니다.

이 최종 단계는 이전 단계 중 하나가 실패하더라도 실행됩니다.
이 단계의 주요 목표는 설정된 환경을 정리하는 것입니다.
예를 들어 VM을 끄거나 컨테이너를 삭제하는 것 등이 있을 수 있습니다.

cleanup_exec의 결과는 작업 상태에 영향을 미치지 않습니다.
예를 들어, 작업은 다음과 같은 경우에도 성공으로 표시됩니다.

  • prepare_execrun_exec 모두 성공.
  • cleanup_exec 실패.

사용자는 cleanup_exec_timeout을 설정하여 GitLab Runner가 환경을 정리하기 전에 얼마나 오랫동안 기다려야 하는지에 대한 기한을 설정할 수 있습니다.

이 실행 파일의 STDOUT는 GitLab Runner 로그에 DEBUG 수준으로 출력됩니다.
STDERRWARN 수준의 로그에 출력됩니다.

만약 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_exec, prepare_exec 또는 run_exec 중에 모두 도달하는 경우 빌드는 실패로 표시됩니다.

GitLab 13.1부터, 드라이버에 의해 생성된 모든 자식 프로세스는 UNIX 기반 시스템에서도 위에서 설명된 우아한 종료 프로세스를 받게 됩니다. 이것은 모든 자식 프로세스가 속한 프로세스 그룹으로 주 프로세스를 설정함으로써 구현됩니다.

오류 처리

GitLab Runner는 실행 파일이 다음 코드 중 하나로 종료될 때만 다르게 처리할 수 있는 두 가지 유형의 오류가 있습니다.
사용자 스크립트가 config_exec, prepare_exec, run_execcleanup_exec 내부에서 이 코드로 종료되면 이 오류들이 처리됩니다.
사용자가 0이 아닌 종료 코드로 종료하는 경우 아래의 오류 코드 중 하나로 전파되어야 합니다.

빌드 실패

GitLab Runner는 BUILD_FAILURE_EXIT_CODE 환경 변수를 제공하여 사용자의 작업에 실패가 있는지 GitLab Runner에게 알리는 종료 코드로 사용해야 합니다.
BUILD_FAILURE_EXIT_CODE로 종료 시 빌드는 GitLab CI에서 적절하게 실패로 표시됩니다.
.gitlab-ci.yml 파일 내에서 사용자가 정의한 스크립트가 0이 아닌 코드로 종료되면, run_execBUILD_FAILURE_EXIT_CODE 값을 가지도록 종료해야 합니다.

참고: 우리는 BUILD_FAILURE_EXIT_CODE를 하드코딩된 값 대신 사용하는 것을 강력히 권장합니다.
왜냐하면 이 값은 어떤 릴리스에서든 변경될 수 있기 때문에 당신의 이진 파일/스크립트를 미래에 대비하게 만들 수 있습니다.

시스템 실패

SYSTEM_FAILURE_EXIT_CODE에서 지정된 오류 코드로 프로세스를 종료하여 시스템 실패를 GitLab Runner에 보낼 수 있습니다.
이 오류 코드가 반환되면, 일부 단계에서 GitLab Runner는 해당 단계를 다시 시도하고, 모든 재시도가 성공하지 않으면 작업은 실패로 표시됩니다.

아래는 재시도되는 각 단계 및 각 재시도 사이에 대기하는 기간의 표입니다.

단계 이름 시도 횟수 각 재시도 사이의 대기 시간
prepare_exec 3 3초
get_sources GET_SOURCES_ATTEMPTS 변수의 값. (기본값 1) 0초
restore_cache RESTORE_CACHE_ATTEMPTS 변수의 값. (기본값 1) 0초
download_artifacts ARTIFACT_DOWNLOAD_ATTEMPTS 변수의 값. (기본값 1) 0초

참고: 우리는 SYSTEM_FAILURE_EXIT_CODE를 하드코딩된 값 대신 사용하는 것을 강력히 권장합니다.
왜냐하면 이 값은 어떤 릴리스에서든 변경될 수 있기 때문에 당신의 이진 파일/스크립트를 미래에 대비하게 만들 수 있습니다.

작업 응답

문서화된 CI/CD 변수 우선 순위를 준수하는 대로 작업 수준의 CUSTOM_ENV_ 변수를 변경할 수 있습니다. 이 기능은 유용할 수 있지만, 신뢰할 수 있는 작업 컨텍스트가 필요할 때 전체 JSON 작업 응답이 자동으로 제공됩니다. 러너는 JOB_RESPONSE_FILE 환경 변수에서 참조되는 임시 파일을 생성합니다. 이 파일은 모든 단계에 존재하며, 정리 중에 자동으로 제거됩니다.

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