GitLab CI/CD에서 Git 서브모듈 사용
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
Git 서브모듈을 사용하여 다른 Git 리포지터리의 서브디렉토리로 Git 리포지터리를 유지할 수 있습니다. Git 서브모듈을 사용할 때 프로젝트에는 .gitmodules라는 파일이 있어야 합니다. 예를 들어, 다음과 같은 경우에 생성된 .gitmodules 설정은 다음과 같을 수 있습니다:
Git 서브모듈을 사용하여 다른 Git 리포지터리의 서브디렉토리로 Git 리포지터리를 유지할 수 있습니다. 다른 리포지터리를 프로젝트에 클론하고 커밋을 분리하여 유지할 수 있습니다.
.gitmodules 파일 구성#
Git 서브모듈을 사용할 때 프로젝트에는 .gitmodules라는 파일이 있어야 합니다. GitLab CI/CD 작업에서 작동하도록 구성하는 여러 옵션이 있습니다.
절대 URL 사용#
히스토리
- GitLab Runner 15.11에서 도입.
예를 들어, 다음과 같은 경우에 생성된 .gitmodules 설정은 다음과 같을 수 있습니다:
- 프로젝트가
https://gitlab.com/secret-group/my-project에 위치한 경우. - 프로젝트가 서브모듈로 포함하려는
https://gitlab.com/group/project에 의존하는 경우. git@gitlab.com:secret-group/my-project.git과 같은 SSH 주소로 소스를 체크아웃하는 경우.
[submodule "project"]
path = project
url = git@gitlab.com:group/project.git
이 경우 GIT_SUBMODULE_FORCE_HTTPS 변수를 사용하여 GitLab Runner가 서브모듈을 클론하기 전에 URL을 HTTPS로 변환하도록 지시하세요.
또는 로컬에서도 HTTPS를 사용하는 경우 HTTPS URL을 구성할 수 있습니다:
[submodule "project"]
path = project
url = https://gitlab.com/group/project.git
이 경우 추가 변수를 구성할 필요가 없지만, 로컬에서 클론하려면 개인 접근 토큰을 사용해야 합니다.
상대 URL 사용#
상대 URL을 사용하는 경우, 포크 워크플로우에서 서브모듈이 잘못 해석될 수 있습니다. 프로젝트에 포크가 있을 것으로 예상되는 경우 절대 URL을 대신 사용하세요.
서브모듈이 동일한 GitLab 서버에 있는 경우 .gitmodules 파일에서 상대 URL을 사용할 수도 있습니다:
[submodule "project"]
path = project
url = ../../project.git
위의 설정은 소스를 클론할 때 사용할 URL을 자동으로 추론하도록 Git에 지시합니다. 모든 CI/CD 작업에서 HTTPS로 클론하고, 로컬에서는 계속 SSH를 사용하여 클론할 수 있습니다.
동일한 GitLab 서버에 없는 서브모듈의 경우 항상 전체 URL을 사용하세요:
[submodule "project-x"]
path = project-x
url = https://gitserver.com/group/project-x.git
CI/CD 작업에서 Git 서브모듈 사용#
사전 요구 사항:
- 파이프라인 작업에서
CI_JOB_TOKEN을 사용하여 서브모듈을 클론하는 경우 코드를 가져오려면 서브모듈 리포지터리에 대한 Reporter, Developer, Maintainer 또는 Owner 권한이 있어야 합니다. - CI/CD 작업 토큰 접근이 업스트림 서브모듈 프로젝트에서 올바르게 구성되어야 합니다.
CI/CD 작업에서 서브모듈이 올바르게 작동하도록 하려면:
-
GIT_SUBMODULE_STRATEGY변수를normal또는recursive로 설정하여 러너에게 작업 전에 서브모듈을 가져오도록 지시할 수 있습니다:variables: GIT_SUBMODULE_STRATEGY: recursive -
동일한 GitLab 서버에 있고 Git 또는 SSH URL로 구성된 서브모듈의 경우
GIT_SUBMODULE_FORCE_HTTPS변수를 설정해야 합니다. -
GIT_DEPTH변수와 독립적으로 서브모듈의 클론 깊이를 구성하려면GIT_SUBMODULE_DEPTH를 사용하세요:variables: GIT_SUBMODULE_DEPTH: 1 -
GIT_SUBMODULE_PATHS를 사용하여 동기화되는 서브모듈을 제어하기 위해 특정 서브모듈을 필터링하거나 제외할 수 있습니다.variables: GIT_SUBMODULE_PATHS: submoduleA submoduleB -
GIT_SUBMODULE_UPDATE_FLAGS를 사용하여 고급 체크아웃 동작을 제어하는 추가 플래그를 제공할 수 있습니다.variables: GIT_SUBMODULE_STRATEGY: recursive GIT_SUBMODULE_UPDATE_FLAGS: --jobs 4
중첩 서브모듈 체크아웃#
히스토리
- GitLab Runner 18.6에서 도입.
중첩 서브모듈은 자체 서브모듈을 포함하는 서브모듈입니다. 리포지터리의 모든 서브모듈이 아닌 특정 중첩 서브모듈만 체크아웃해야 할 수 있습니다.
GitLab Runner 18.6 이상은 Git 구성(자격 증명 포함)을 별도 파일로 외부화하여 빌드 디렉토리가 오염되는 것을 방지합니다. 서브모듈 디렉토리로 이동하여 Git 명령을 실행하면 기본 리포지터리의 구성이 GIT_SUBMODULE_STRATEGY에 따라 모든 서브모듈에 자동으로 상속됩니다:
GIT_SUBMODULE_STRATEGY: normal을 사용하면 최상위 서브모듈이 초기화됩니다.GIT_SUBMODULE_STRATEGY: recursive를 사용하면 모든 중첩 서브모듈이 초기화됩니다.
중첩 서브모듈의 서브셋을 체크아웃하려면:
-
GIT_SUBMODULE_STRATEGY를normal로 설정하세요:variables: GIT_SUBMODULE_STRATEGY: normal -
작업에서 외부화된 구성을 명시적으로 전달하세요:
my-job: script: - git submodule sync - git submodule update --init - cd path/to/submodule-with-nested-submodule - git -c "include.path=$(git -C $CI_PROJECT_DIR config include.path)" submodule update --init nested-submodule
git -C $CI_PROJECT_DIR config include.path 명령은 기본 리포지터리에서 외부화된 구성 파일의 경로를 가져옵니다. 이렇게 하면 중첩 서브모듈을 체크아웃할 때 자격 증명 및 기타 설정을 사용할 수 있습니다.
다른 GitLab 인스턴스의 서브모듈 사용#
서브모듈이 메인 프로젝트와 다른 GitLab 인스턴스에 호스팅된 경우 현재 인스턴스의 CI_JOB_TOKEN은 외부 인스턴스에 인증할 수 없습니다. 외부 인스턴스에서 생성된 토큰을 사용하여 인증해야 합니다.
외부 GitLab 인스턴스로 인증하는 두 가지 주요 방법이 있습니다:
- URL 재작성: Git URL을 수정하여 인증 자격 증명을 포함합니다.
- Git 자격 증명 헬퍼: Git이 필요할 때 자동으로 사용하는 자격 증명을 저장합니다.
선택하는 인증 방법은 GitLab Runner 실행기 유형에 따라 다릅니다:
-
컨테이너화된 실행기(Docker 또는 Kubernetes): 각 작업이 격리된 컨테이너에서 실행되므로 전역 Git 구성 변경은 현재 작업에만 영향을 미치고 컨테이너가 삭제될 때 자동으로 정리됩니다.
-
셸 실행기: 작업이 러너 호스트 시스템에서 직접 실행되므로 전역 Git 구성 변경이 작업 간에 지속됩니다. 이로 인해 다른 작업이 다른 자격 증명을 사용하는 경우 인증 충돌이 발생할 수 있습니다.
셸 실행기를 사용할 때 인증 자격 증명을 지속적으로 저장하는 git config --global 명령을 피하세요. 이러한 설정은 작업 간에 활성 상태로 유지되며 다른 작업이 다른 자격 증명을 사용하는 경우 인증 실패 또는 보안 문제를 일으킬 수 있습니다.
다음 토큰 유형 중 하나를 사용할 수 있습니다:
URL 재작성으로 인증 구성#
URL 재작성으로 인증을 구성하려면:
-
.gitmodules파일에서 서브모듈에 절대 HTTPS URL을 사용하세요:[submodule "external-project"] path = external-project url = https://other-gitlab.example.com/group/project.git -
외부 GitLab 인스턴스에서
read_repository스코프를 가진 토큰을 생성하세요. -
메인 프로젝트에서 토큰을 마스크된 CI/CD 변수로 추가하세요. 예를 들어 이름을
EXTERNAL_GITLAB_TOKEN으로 지정하세요. -
.gitlab-ci.yml파일에서 실행기 유형에 따라 인증을 구성하세요:컨테이너화된 실행기(Docker 또는 Kubernetes)의 경우:
variables: GIT_SUBMODULE_STRATEGY: recursive my-job: before_script: - git config --global url."https://<username>:${EXTERNAL_GITLAB_TOKEN}@other-gitlab.example.com/".insteadOf "https://other-gitlab.example.com/" script: - echo "Submodules are fetched with authentication" - ls -la external-project/셸 실행기의 경우:
variables: GIT_SUBMODULE_STRATEGY: none my-job: before_script: - parent_include_path=$(git -C $CI_PROJECT_DIR config include.path) - git -c "include.path=${parent_include_path}" -c "url.https://<username>:${EXTERNAL_GITLAB_TOKEN}@other-gitlab.example.com/.insteadOf=https://other-gitlab.example.com/" submodule update --init --recursive --force script: - echo "Submodules are fetched with authentication" - ls -la external-project/<username>을 토큰과 연관된 GitLab 사용자 이름으로 바꾸세요.컨테이너화된 실행기에서만 모든 작업에 대해 인증을 전역적으로 구성하려면:
hooks: pre_get_sources_script: - git config --global url."https://<username>:${EXTERNAL_GITLAB_TOKEN}@other-gitlab.example.com/".insteadOf "https://other-gitlab.example.com/"
Git 자격 증명 헬퍼로 인증 구성#
Git 자격 증명 헬퍼로 인증을 구성하려면:
-
외부 GitLab 인스턴스에서
read_repository스코프를 가진 토큰을 생성하세요. -
메인 프로젝트에서 토큰을 마스크된 CI/CD 변수로 추가하세요. 예를 들어 이름을
EXTERNAL_GITLAB_TOKEN으로 지정하세요. -
.gitlab-ci.yml파일에서 실행기 유형에 따라 자격 증명 헬퍼를 구성하세요:컨테이너화된 실행기(Docker 또는 Kubernetes)의 경우:
my-job: before_script: - git config --global credential.helper store - echo "https://<username>:${EXTERNAL_GITLAB_TOKEN}@other-gitlab.example.com" >> ~/.git-credentials script: - echo "Submodules are fetched with authentication" - ls -la external-project/셸 실행기의 경우:
my-job: before_script: - TEMP_CREDS=$(mktemp) - echo "https://<username>:${EXTERNAL_GITLAB_TOKEN}@other-gitlab.example.com" > "$TEMP_CREDS" - git config credential.helper "store --file=$TEMP_CREDS" - trap "rm -f $TEMP_CREDS" EXIT script: - echo "Submodules are fetched with authentication" - ls -la external-project/<username>을 토큰과 연관된 GitLab 사용자 이름으로 바꾸세요.
트러블슈팅#
.gitmodules 파일을 찾을 수 없음#
.gitmodules 파일은 일반적으로 숨겨진 파일이므로 찾기 어려울 수 있습니다. 숨겨진 파일을 찾고 표시하는 방법을 알아보려면 특정 OS 설명서를 확인하세요.
.gitmodules 파일이 없는 경우 서브모듈 설정이 git config 파일에 있을 수 있습니다.
오류: fatal: run_command returned non-zero status#
이 오류는 서브모듈과 함께 작업하고 GIT_STRATEGY가 fetch로 설정된 경우 작업에서 발생할 수 있습니다.
GIT_STRATEGY를 clone으로 설정하면 문제가 해결될 것입니다.
오류: fatal: could not read Username for 'https://gitlab.com': No such device or address#
CI/CD 작업이 서브모듈과 함께 클론, 가져오기 또는 기타 Git 작업을 시도할 때 이 오류가 발생할 수 있습니다. 이 문제는 다음과 같은 경우에 발생합니다:
- 서브모듈 디렉토리 내에서 Git 명령(예:
git fetch)을 실행할 때, 외부화된 Git 구성이 모든 Git 작업에 자동으로 상속되지 않을 수 있습니다. - 중첩 서브모듈을 사용할 때, GitLab Runner 18.6 이상이 Git 구성을 외부화하므로 서브모듈에 자동으로 상속되지 않을 수 있습니다.
https://gitlab.com을 참조하는 서브모듈이 있는 GitLab 호스팅 러너를 사용할 때,CI_SERVER_FQDN이gitlab.com과 다르기 때문입니다. GitLab Runner는 초기 체크아웃 중에 Git URL 대체를 자동으로 수행하지만, 이는 서브모듈 디렉토리 내의 후속 Git 작업에는 적용되지 않을 수 있습니다.
이 문제를 해결하려면:
-
중첩 서브모듈의 경우 중첩 서브모듈 체크아웃을 참조하세요.
-
서브모듈 디렉토리 내의 Git 작업의 경우 외부화된 구성을 명시적으로 전달하세요:
my-job: script: - cd path/to/submodule - git -c "include.path=$(git -C $CI_PROJECT_DIR config include.path)" fetch origin -
GitLab 호스팅 러너 또는 서브모듈 내에서 여러 Git 작업이 있는 작업의 경우
CI_JOB_TOKEN을 사용하여 URL 대체를 구성하세요:my-job: script: - cd path/to/submodule - git -c "include.path=$(git -C $CI_PROJECT_DIR config include.path)" -c "url.https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_FQDN}/.insteadOf=https://gitlab.com/" fetch origin실행기별 구성 옵션에 대해서는 다른 GitLab 인스턴스의 서브모듈 사용을 참조하세요.
