Docker 컨테이너에서 CI/CD job 실행
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
전용 CI/CD 빌드 서버 또는 로컬 머신에서 호스팅되는 Docker 컨테이너에서 CI/CD job을 실행할 수 있습니다. Docker 컨테이너에서 CI/CD job을 실행하려면 다음을 수행해야 합니다. Docker와 함께 GitLab Runner를 사용하려면 Docker executor를 사용하는 러너를 등록 해야 합니다.
전용 CI/CD 빌드 서버 또는 로컬 머신에서 호스팅되는 Docker 컨테이너에서 CI/CD job을 실행할 수 있습니다.
Docker 컨테이너에서 CI/CD job을 실행하려면 다음을 수행해야 합니다.
- 러너를 등록하고 Docker executor를 사용하도록 설정합니다.
.gitlab-ci.yml파일에서 CI/CD job을 실행할 컨테이너 이미지를 지정합니다.- 선택 사항. MySQL과 같은 다른 서비스를 컨테이너에서 실행합니다.
.gitlab-ci.yml파일에 services를 지정하면 됩니다.
Docker executor를 사용하는 러너 등록#
Docker와 함께 GitLab Runner를 사용하려면 Docker executor를 사용하는 러너를 등록 해야 합니다.
다음 예시는 서비스를 제공하기 위한 임시 템플릿을 설정하는 방법을 보여줍니다.
cat > /tmp/test-config.template.toml << EOF
[[runners]]
[runners.docker]
[[runners.docker.services]]
name = "postgres:latest"
[[runners.docker.services]]
name = "mysql:latest"
EOF
그런 다음 이 템플릿을 사용하여 러너를 등록합니다.
sudo gitlab-runner register \
--url "https://gitlab.example.com/" \
--token "$RUNNER_TOKEN" \
--description "docker-ruby:2.6" \
--executor "docker" \
--template-config /tmp/test-config.template.toml \
--docker-image ruby:3.3
등록된 러너는 ruby:2.6 Docker 이미지를 사용하며, postgres:latest와
mysql:latest 두 서비스를 실행합니다. 이 두 서비스는 모두
빌드 프로세스 중에 접근할 수 있습니다.
이미지란#
image 키워드는 Docker executor가 CI/CD job을 실행하는 데
사용하는 Docker 이미지의 이름입니다.
기본적으로 executor는 Docker Hub에서 이미지를 가져옵니다.
하지만 gitlab-runner/config.toml 파일에서 레지스트리 위치를 설정할 수 있습니다.
예를 들어 로컬 이미지를 사용하도록 Docker pull 정책을
설정할 수 있습니다.
이미지와 Docker Hub에 대한 자세한 내용은 Docker 개요를 참조합니다.
이미지 요구 사항#
CI/CD job을 실행하는 데 사용되는 모든 이미지에는 다음 애플리케이션이 설치되어 있어야 합니다.
sh또는bashgrep
.gitlab-ci.yml 파일에서 image 정의#
모든 job에 사용되는 이미지와 런타임 중에 사용할 서비스 목록을 정의할 수 있습니다.
default:
image: ruby:2.6
services:
- postgres:16.10
before_script:
- bundle install
test:
script:
- bundle exec rake spec
이미지 이름은 다음 형식 중 하나여야 합니다.
image: <image-name>(latest태그와 함께<image-name>을 사용하는 것과 동일)image: <image-name>:<tag>image: <image-name>@<digest>
확장된 Docker 설정 옵션#
image 또는 services 항목에는 문자열 또는 맵을 사용할 수 있습니다.
- 문자열에는 전체 이미지 이름을 포함해야 합니다 (Docker Hub가 아닌 다른 레지스트리에서 이미지를 다운로드하려는 경우 레지스트리도 포함해야 합니다).
- 맵에는 최소한
name옵션이 포함되어야 하며, 이는 문자열 설정에 사용한 것과 동일한 이미지 이름입니다.
예를 들어 다음 두 정의는 동일합니다.
-
image와services에 대한 문자열:image: "registry.example.com/my/image:latest" services: - postgresql:16.10 - redis:latest -
image와services에 대한 맵.image:name이 필요합니다.image: name: "registry.example.com/my/image:latest" services: - name: postgresql:16.10 - name: redis:latest
스크립트 실행 위치#
CI job이 Docker 컨테이너에서 실행되면 before_script, script, after_script 명령은 /builds/<project-path>/ 디렉터리에서 실행됩니다. 이미지에는 다른 기본 WORKDIR이 정의되어 있을 수 있습니다. WORKDIR로 이동하려면 job의 런타임 중에 컨테이너에서 참조할 수 있도록 WORKDIR을 환경 변수로 저장합니다.
이미지의 entrypoint 재정의#
사용 가능한 entrypoint 재정의 방법을 설명하기 전에, 러너가 시작되는 방식을 알아보겠습니다. 러너는 CI/CD job에 사용되는 컨테이너에 Docker 이미지를 사용합니다.
- 러너는 정의된 entrypoint를 사용하여 Docker 컨테이너를 시작합니다. 기본값은
Dockerfile의 값이며,.gitlab-ci.yml파일에서 재정의할 수 있습니다. - 러너는 실행 중인 컨테이너에 자신을 연결합니다.
- 러너는 스크립트를 준비합니다(
before_script,script,after_script의 조합). - 러너는 스크립트를 컨테이너 셸의
stdin으로 전송하고 출력을 받습니다.
.gitlab-ci.yml 파일에서 Docker 이미지의
entrypoint를 재정의하려면 다음과 같이 합니다.
- Docker 17.06 이상에서는
entrypoint를 빈 값으로 설정합니다. - Docker 17.03 이하에서는
entrypoint를/bin/sh -c,/bin/bash -c, 또는 이미지에서 사용 가능한 동등한 셸로 설정합니다.
image:entrypoint의 문법은 Dockerfile ENTRYPOINT와 유사합니다.
SQL 데이터베이스가 포함된 super/sql:experimental 이미지가 있다고
가정해 보겠습니다. 이 데이터베이스 바이너리로 일부 테스트를 실행하려고
하므로 이 이미지를 job의 기본 이미지로 사용하려고 합니다. 또한 이
이미지가 entrypoint로 /usr/bin/super-sql run을 사용하도록 설정되어
있다고 가정해 보겠습니다. 추가 옵션 없이 컨테이너가 시작되면
데이터베이스의 프로세스가 실행됩니다. 러너는 이미지에 entrypoint가
없거나, entrypoint가 셸 명령을 시작할 수 있도록 준비되어 있을 것으로
예상합니다.
확장된 Docker 설정 옵션을 사용하면 다음 대신:
super/sql:experimental을 기반으로 자체 이미지를 생성하고,ENTRYPOINT를 셸로 설정하고,- CI job에서 새 이미지를 사용하는
대신, 이제 .gitlab-ci.yml 파일에서 entrypoint를 정의할 수 있습니다.
Docker 17.06 이상의 경우:
image:
name: super/sql:experimental
entrypoint: [""]
Docker 17.03 이하의 경우:
image:
name: super/sql:experimental
entrypoint: ["/bin/sh", "-c"]
config.toml에서 image 및 services 정의#
config.toml 파일에서 다음을 정의할 수 있습니다.
[runners.docker]섹션에서, CI/CD job을 실행하는 데 사용되는 컨테이너 이미지[[runners.docker.services]]섹션에서, services 컨테이너
[runners.docker]
image = "ruby:latest"
services = ["mysql:latest", "postgres:latest"]
이러한 방식으로 정의된 이미지와 서비스는 해당 러너가 실행하는 모든 job에 추가됩니다.
프라이빗 컨테이너 레지스트리에서 이미지 접근#
프라이빗 컨테이너 레지스트리에 접근하기 위해 GitLab Runner 프로세스는 다음을 사용할 수 있습니다.
- 정적으로 정의된 자격 증명. 특정 레지스트리에 대한 사용자 이름과 비밀번호입니다.
- Credentials Store. 자세한 내용은 관련 Docker 문서를 참조합니다.
- Credential Helpers. 자세한 내용은 관련 Docker 문서를 참조합니다.
동일한 GitLab 인스턴스에서 GitLab Container Registry를 사용하는 경우,
GitLab은 이 레지스트리에 대한 기본 자격 증명을 제공합니다. 이 자격 증명을 사용하면 인증에 CI_JOB_TOKEN이 사용됩니다.
job 토큰을 사용하려면 job을 시작하는 사용자가 프라이빗 이미지가 호스팅된 프로젝트에 대해 최소한 Reporter 권한을 가지고 있어야 합니다.
프라이빗 이미지를 호스팅하는 프로젝트는 다른 프로젝트가 job 토큰으로 인증할 수 있도록 허용해야 합니다. 이 접근 권한은 기본적으로 비활성화되어 있습니다.
자세한 내용은 CI/CD job token을 참조합니다.
사용할 옵션을 정의하기 위해 러너 프로세스는 다음 순서로 설정을 읽습니다.
/root/.docker디렉터리의config.json파일.DOCKER_AUTH_CONFIGCI/CD 변수.- 러너의
config.toml파일에 설정된DOCKER_AUTH_CONFIG환경 변수. - 프로세스를 실행하는 사용자의
$HOME/.docker디렉터리에 있는config.json파일. 하위 프로세스를 권한이 없는 사용자로 실행하도록--user플래그가 지정된 경우, 메인 러너 프로세스 사용자의 홈 디렉터리가 사용됩니다.
정적으로 정의된 자격 증명 사용#
두 가지 방법으로 프라이빗 레지스트리에 접근할 수 있습니다. 두 방법 모두 적절한
인증 정보와 함께 DOCKER_AUTH_CONFIG CI/CD 변수를 설정해야 합니다.
- job 별: 하나의 job이 프라이빗 레지스트리에 접근하도록 설정하려면
DOCKER_AUTH_CONFIG를 CI/CD 변수로 추가합니다. - 러너 별: 러너의 모든 job이 프라이빗 레지스트리에 접근할 수 있도록 설정하려면
DOCKER_AUTH_CONFIG를 러너 설정에 환경 변수로 추가합니다.
각각의 예시는 다음 섹션을 참조합니다.
DOCKER_AUTH_CONFIG 데이터 확인#
예를 들어 registry.example.com:5000/private/image:latest 이미지를 사용하려고
한다고 가정해 보겠습니다. 이 이미지는 프라이빗 이미지이며 프라이빗 컨테이너
레지스트리에 로그인해야 합니다.
또한 다음이 로그인 자격 증명이라고 가정해 보겠습니다.
| 키 | 값 |
|---|---|
| registry | registry.example.com:5000 |
| username | my_username |
| password | my_password |
DOCKER_AUTH_CONFIG의 값을 확인하려면 다음 방법 중 하나를 사용합니다.
-
로컬 머신에서
docker login을 실행합니다.docker login registry.example.com:5000 --username my_username --password my_password그런 다음
~/.docker/config.json의 내용을 복사합니다.컴퓨터에서 레지스트리에 접근할 필요가 없다면
docker logout을 실행할 수 있습니다.docker logout registry.example.com:5000 -
일부 설정에서는 Docker 클라이언트가 사용 가능한 시스템 키 저장소를 사용하여
docker login의 결과를 저장할 수 있습니다. 이 경우~/.docker/config.json을 읽을 수 없으므로${username}:${password}의 base64로 인코딩된 버전을 준비하고 Docker 설정 JSON을 직접 생성해야 합니다. 터미널을 열고 다음 명령을 실행합니다.# The use of printf (as opposed to echo) prevents encoding a newline in the password. printf "my_username:my_password" | openssl base64 -A # Example output to copy bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=[!note] 사용자 이름에
@와 같은 특수 문자가 포함된 경우, 인증 문제를 방지하기 위해 백슬래시(\)로 이를 이스케이프해야 합니다.다음과 같이 Docker JSON 설정 내용을 생성합니다.
{ "auths": { "registry.example.com:5000": { "auth": "(Base64 content from above)" } } }
job 설정#
registry.example.com:5000에 대한 접근 권한을 가진 단일 job을 설정하려면
다음 단계를 따릅니다.
-
Docker 설정 파일의 내용을 값으로 하는 CI/CD 변수
DOCKER_AUTH_CONFIG를 생성합니다.{ "auths": { "registry.example.com:5000": { "auth": "bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=" } } } -
이제
.gitlab-ci.yml파일의image또는services에 정의된registry.example.com:5000의 모든 프라이빗 이미지를 사용할 수 있습니다.image: registry.example.com:5000/namespace/image:tag이전 예시에서 GitLab Runner는
namespace/image:tag이미지를 찾기 위해registry.example.com:5000을 확인합니다.
앞서 설명한 대로 "auths" 해시에 레지스트리를 추가하여 원하는 만큼
많은 레지스트리에 대한 설정을 추가할 수 있습니다.
러너가 DOCKER_AUTH_CONFIG와 일치시키려면 어디서나 전체 hostname:port
조합이 필요합니다. 예를 들어 .gitlab-ci.yml 파일에
registry.example.com:5000/namespace/image:tag가 지정된 경우,
DOCKER_AUTH_CONFIG에도 registry.example.com:5000을 지정해야 합니다.
registry.example.com만 지정하면 작동하지 않습니다.
러너 설정#
동일한 레지스트리에 접근하는 파이프라인이 많다면 러너 수준에서 레지스트리 접근을 설정해야 합니다. 이렇게 하면 파이프라인 작성자가 적절한 러너에서 job을 실행하는 것만으로 프라이빗 레지스트리에 접근할 수 있습니다. 또한 레지스트리 변경과 자격 증명 교체를 간소화하는 데 도움이 됩니다.
즉, 해당 러너의 모든 job은 프로젝트 간에도 동일한 권한으로 레지스트리에 접근할 수 있습니다. 레지스트리에 대한 접근을 제어해야 한다면, 러너에 대한 접근을 반드시 제어해야 합니다.
러너에 DOCKER_AUTH_CONFIG를 추가하려면 다음과 같이 합니다.
-
러너의
config.toml파일을 다음과 같이 수정합니다.[[runners]] environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.example.com:5000\":{\"auth\":\"bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=\"}}}"]DOCKER_AUTH_CONFIG데이터에 포함된 큰따옴표는 백슬래시로 이스케이프해야 합니다. 이렇게 하면 TOML로 해석되는 것을 방지할 수 있습니다.environment옵션은 목록입니다. 러너에는 기존 항목이 있을 수 있으므로, 이를 대체하지 말고 목록에 추가해야 합니다.
-
러너 서비스를 재시작합니다.
Credentials Store 사용#
Credentials Store는 인스턴스 러너 또는 러너가 설치된 환경에 접근할 수 없는 다른 러너에서는 사용할 수 없습니다.
사전 요구 사항:
- 특정 키체인 또는 외부 저장소와 상호 작용하는 외부 헬퍼 프로그램으로, GitLab Runner의
$PATH에서 사용 가능해야 합니다.
Credentials Store를 설정하려면 다음과 같이 합니다.
-
GitLab Runner가 헬퍼 프로그램을 사용하도록 설정합니다. 다음 옵션 중 하나를 사용하여 이 작업을 수행할 수 있습니다.
-
Docker 설정 파일의 내용을 값으로 하는 CI/CD 변수
DOCKER_AUTH_CONFIG를 생성합니다.{ "credsStore": "osxkeychain" } -
또는 셀프 매니지드 러너를 실행하는 경우, 해당 JSON을
${GITLAB_RUNNER_HOME}/.docker/config.json에 추가합니다. GitLab Runner는 이 설정 파일을 읽고 이 특정 리포지터리에 필요한 헬퍼를 사용합니다.
-
credsStore는 모든 레지스트리에 접근하는 데 사용됩니다.
프라이빗 레지스트리의 이미지와 Docker Hub의 퍼블릭 이미지를 모두 사용하는 경우,
Docker Hub에서의 pull이 실패합니다. Docker 데몬은 모든 레지스트리에 동일한 자격 증명을 사용하려고 시도합니다.
Credential Helpers 사용#
예를 들어 <aws_account_id>.dkr.ecr.<region>.amazonaws.com/private/image:latest
이미지를 사용하려고 한다고 가정해 보겠습니다. 이 이미지는 프라이빗 이미지이며 프라이빗 컨테이너 레지스트리에 로그인해야 합니다.
Credential Helpers는 인스턴스 러너 또는 러너가 설치된 환경에 접근할 수 없는 다른 러너에서는 사용할 수 없습니다.
사전 요구 사항:
- GitLab Runner의
$PATH에서 사용 가능한docker-credential-ecr-login. - 다음 AWS 자격 증명 설정 중 하나. GitLab Runner Manager가 자격 증명을 획득하여 러너에 전달합니다. GitLab Runner가 자격 증명에 접근할 수 있는지 확인합니다.
<aws_account_id>.dkr.ecr.<region>.amazonaws.com에 대한 접근을 설정하려면 다음과 같이 합니다.
-
GitLab Runner가 credential helper를 사용하도록 설정합니다. 다음 옵션 중 하나를 사용하여 이 작업을 수행할 수 있습니다.
-
Docker 설정 파일의 내용을 값으로 하는 CI/CD 변수
DOCKER_AUTH_CONFIG를 생성합니다.{ "credHelpers": { "<aws_account_id>.dkr.ecr.<region>.amazonaws.com": "ecr-login" } }이렇게 하면 Docker가 특정 레지스트리에 대해 Credential Helper를 사용하도록 설정됩니다.
또는 모든 Amazon Elastic Container Registry(ECR) 레지스트리에 대해 Docker가 Credential Helper를 사용하도록 설정할 수 있습니다.
{ "credsStore": "ecr-login" }[!note]
{"credsStore": "ecr-login"}을 사용하는 경우, AWS 공유 설정 파일(~/.aws/config)에서 리전을 명시적으로 설정합니다. ECR Credential Helper가 인증 토큰을 가져올 때 리전을 지정해야 합니다. -
또는 셀프 매니지드 러너를 실행하는 경우, 이전 JSON을
${GITLAB_RUNNER_HOME}/.docker/config.json에 추가합니다. GitLab Runner는 이 설정 파일을 읽고 이 특정 리포지터리에 필요한 헬퍼를 사용합니다.
-
-
이제
.gitlab-ci.yml파일의image,services, 또는 둘 다에 정의된<aws_account_id>.dkr.ecr.<region>.amazonaws.com의 모든 프라이빗 이미지를 사용할 수 있습니다.image: <aws_account_id>.dkr.ecr.<region>.amazonaws.com/private/image:latest이 예시에서 GitLab Runner는
private/image:latest이미지를 찾기 위해<aws_account_id>.dkr.ecr.<region>.amazonaws.com을 확인합니다.
"credHelpers" 해시에 레지스트리를 추가하여 원하는 만큼 많은 레지스트리에 대한 설정을 추가할 수 있습니다.
체크섬을 사용하여 이미지 보안 유지#
이미지의 무결성을 검증하려면 .gitlab-ci.yml 파일의 job 정의에서 이미지 체크섬을 사용합니다. 이미지 무결성 검증에 실패하면 수정된 컨테이너를 사용할 수 없습니다.
이미지 체크섬을 사용하려면 마지막에 체크섬을 추가해야 합니다.
image: ruby:2.6.8@sha256:d1dbaf9665fe8b2175198e49438092fdbcf4d8934200942b94425301b17853c7
이미지 체크섬을 확인하려면 이미지의 TAG 탭에서 DIGEST 열을 확인합니다.
예를 들어 Ruby 이미지를 확인합니다.
체크섬은 6155f0235e95와 같은 임의의 문자열입니다.
시스템에 있는 모든 이미지의 체크섬은 docker images --digests 명령으로도 확인할 수 있습니다.
❯ docker images --digests
REPOSITORY TAG DIGEST (...)
gitlab/gitlab-ee latest sha256:723aa6edd8f122d50cae490b1743a616d54d4a910db892314d68470cc39dfb24 (...)
gitlab/gitlab-runner latest sha256:4a18a80f5be5df44cb7575f6b89d1fdda343297c6fd666c015c0e778b276e726 (...)
커스텀 GitLab Runner Docker 이미지 생성#
AWS CLI와 Amazon ECR Credential Helper를 패키징하기 위해 커스텀 GitLab Runner Docker 이미지를 생성할 수 있습니다. 이 설정을 사용하면 특히 컨테이너화된 애플리케이션에서 AWS 서비스와 안전하고 간소화된 상호 작용이 가능합니다. 예를 들어 이 설정을 사용하여 Amazon ECR에서 Docker 이미지를 관리, 배포, 업데이트할 수 있습니다. 이 설정은 시간이 많이 걸리고 오류가 발생하기 쉬운 설정과 수동 자격 증명 관리를 피하는 데 도움이 됩니다.
-
다음 내용으로
Dockerfile을 생성합니다.# Control package versions ARG GITLAB_RUNNER_VERSION=v17.3.0 ARG AWS_CLI_VERSION=2.17.36 # AWS CLI and Amazon ECR Credential Helper FROM amazonlinux as aws-tools RUN set -e \ && yum update -y \ && yum install -y --allowerasing git make gcc curl unzip \ && curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" --output "awscliv2.zip" \ && unzip awscliv2.zip && ./aws/install -i /usr/local/bin \ && yum clean all # Download and install ECR Credential Helper RUN curl --location --output /usr/local/bin/docker-credential-ecr-login "https://github.com/awslabs/amazon-ecr-credential-helper/releases/latest/download/docker-credential-ecr-login-linux-amd64" RUN chmod +x /usr/local/bin/docker-credential-ecr-login # Configure the ECR Credential Helper RUN mkdir -p /root/.docker RUN echo '{ "credsStore": "ecr-login" }' > /root/.docker/config.json # Final image based on GitLab Runner FROM gitlab/gitlab-runner:${GITLAB_RUNNER_VERSION} # Install necessary packages RUN apt-get update \ && apt-get install -y --no-install-recommends jq procps curl unzip groff libgcrypt20 tar gzip less openssh-client \ && apt-get clean && rm -rf /var/lib/apt/lists/* # Copy AWS CLI and Amazon ECR Credential Helper binaries COPY --from=aws-tools /usr/local/bin/ /usr/local/bin/ # Copy ECR Credential Helper Configuration COPY --from=aws-tools /root/.docker/config.json /root/.docker/config.json -
.gitlab-ci.yml에서 커스텀 GitLab Runner Docker 이미지를 빌드하려면 다음 예시를 포함합니다.variables: DOCKER_DRIVER: overlay2 IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME GITLAB_RUNNER_VERSION: v17.3.0 AWS_CLI_VERSION: 2.17.36 stages: - build build-image: stage: build script: - echo "Logging into GitLab container registry..." - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - echo "Building Docker image..." - docker build --build-arg GITLAB_RUNNER_VERSION=${GITLAB_RUNNER_VERSION} --build-arg AWS_CLI_VERSION=${AWS_CLI_VERSION} -t ${IMAGE_NAME} . - echo "Pushing Docker image to GitLab container registry..." - docker push ${IMAGE_NAME} rules: - changes: - Dockerfile