CI/CD 작업을 Docker 컨테이너에서 실행하기

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

CI/CD 작업을 전용 CI/CD 빌드 서버 또는 로컬 머신에서 호스팅되는 Docker 컨테이너에서 실행할 수 있습니다.

Docker 컨테이너에서 CI/CD 작업을 실행하려면 다음이 필요합니다:

  1. 러너를 등록하고 Docker executor를 사용하도록 설정합니다.
  2. .gitlab-ci.yml 파일에서 CI/CD 작업을 실행할 Docker 이미지에서 지정합니다.
  3. 선택 사항. 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:latestmysql:latest, 두 서비스 모두 빌드 프로세스 중에 접근할 수 있습니다.

이미지는 무엇인가

image 키워드는 Docker executor가 CI/CD 작업을 실행하는 데 사용하는 Docker 이미지의 이름입니다.

기본적으로 executor는 Docker Hub에서 이미지를 가져옵니다.

그러나 gitlab-runner/config.toml 파일에서 레지스트리 위치를 구성할 수 있습니다. 예를 들어, Docker pull policy를 설정하여 로컬 이미지를 사용할 수 있습니다.

이미지와 Docker Hub에 대한 자세한 내용은 Docker 개요를 참조하세요.

이미지 요구 사항

CI/CD 작업을 실행하는 데 사용되는 모든 이미지는 다음 애플리케이션이 설치되어 있어야 합니다:

  • sh 또는 bash
  • grep

.gitlab-ci.yml 파일에서 image 정의하기

모든 작업에 사용되는 이미지를 정의하고, 런타임 중에 사용하려는 서비스 목록을 정의할 수 있습니다:

default:
  image: ruby:2.6
  services:
    - postgres:11.7
  before_script:
    - bundle install

test:
  script:
    - bundle exec rake spec

이미지 이름은 다음 형식 중 하나여야 합니다:

  • image: <image-name> (최신 태그와 함께 <image-name>을 사용하는 것과 동일)
  • image: <image-name>:<tag>
  • image: <image-name>@<digest>

확장된 Docker 구성 옵션

  • GitLab 및 GitLab Runner 9.4에서 도입됨.

image 또는 services 항목에 문자열 또는 맵을 사용할 수 있습니다:

  • 문자열은 전체 이미지 이름을 포함해야 하며
    (레지스트리 이외의 레지스트리에서 이미지를 다운로드하려는 경우 레지스트리를 포함합니다).
  • 맵은 최소한 name 옵션을 포함해야 하며,
    이는 문자열 설정에 사용된 동일한 이미지 이름입니다.

예를 들어, 다음 두 정의는 동일합니다:

  • imageservices에 대한 문자열:

    image: "registry.example.com/my/image:latest"
    
    services:
      - postgresql:14.3
      - redis:latest
    
  • imageservices에 대한 맵입니다. image:name이 필수입니다:

    image:
      name: "registry.example.com/my/image:latest"
    
    services:
      - name: postgresql:14.3
      - name: redis:latest
    

스크립트가 실행되는 위치

CI 작업이 Docker 컨테이너에서 실행될 때, before_script, script, 및 after_script 명령은 /builds/<project-path>/ 디렉토리에서 실행됩니다. 여러분의 이미지에는 다른 기본 WORKDIR가 정의되어 있을 수 있습니다. WORKDIR로 이동하려면, WORKDIR를 환경 변수로 저장하여 작업 실행 중에 컨테이너에서 참조할 수 있도록 하세요.

이미지의 엔트리포인트 재정의

  • GitLab 및 GitLab Runner 9.4에서 도입되었습니다. 확장 구성 옵션에 대해 자세히 알아보세요.

사용 가능한 엔트리포인트 재정의 방법을 설명하기 전에, 러너가 시작하는 방법을 설명하겠습니다. CI/CD 작업에 사용되는 컨테이너를 위해 Docker 이미지를 사용합니다:

  1. 러너는 정의된 엔트리포인트를 사용하여 Docker 컨테이너를 시작합니다. 이는 .gitlab-ci.yml 파일에서 재정의할 수 있는 Dockerfile의 기본값입니다.

  2. 러너는 실행 중인 컨테이너에 연결합니다.

  3. 러너는 스크립트를 준비합니다 ( before_script, script, 및 after_script의 조합).

  4. 러너는 스크립트를 컨테이너의 셸 stdin에 전송하고 출력을 받습니다.

Docker 이미지의 엔트리포인트를 재정의하려면, .gitlab-ci.yml 파일에서:

  • Docker 17.06 이상에서는 entrypoint를 빈 값으로 설정합니다.
  • Docker 17.03 이하 버전에서는 entrypoint/bin/sh -c, /bin/bash -c 또는 이미지에서 사용할 수 있는 동등한 셸로 설정합니다.

image:entrypoint의 구문은 Dockerfile의 ENTRYPOINT와 유사합니다.

가정해 보겠습니다, 여러분이 SQL 데이터베이스가 포함된 super/sql:experimental 이미지를 가지고 있습니다. 이 데이터베이스 바이너리로 일부 테스트를 실행하고 싶기 때문에 이 이미지를 작업의 기본 이미지로 사용하고 싶습니다. 또한, 이 이미지가 엔트리포인트로 /usr/bin/super-sql run을 구성하고 있다고 가정해 보겠습니다. 추가 옵션 없이 컨테이너가 시작되면 데이터베이스의 프로세스가 실행됩니다. 러너는 이미지에 엔트리포인트가 없거나 엔트리포인트가 셸 명령을 시작할 준비가 되어 있다고 기대합니다.

확장된 Docker 구성 옵션 덕분에 이제 다음을 할 필요가 없습니다:

  • super/sql:experimental을 기반으로 자신의 이미지를 만드는 것.
  • 엔트리포인트를 셸로 설정하는 것.
  • CI 작업에서 새 이미지를 사용하는 것.

이제 .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에서 이미지 및 서비스 정의

config.toml 파일에서 다음을 정의할 수 있습니다:

[runners.docker]
  image = "ruby:latest"
  services = ["mysql:latest", "postgres:latest"]

이렇게 정의된 이미지 및 서비스는 해당 러너가 실행하는 모든 작업에 추가됩니다.

개인 컨테이너 레지스트리에서 이미지 접근하기

개인 컨테이너 레지스트리에 접근하기 위해 GitLab Runner 프로세스는 다음을 사용할 수 있습니다:

어떤 옵션을 사용할지 정의하기 위해, 러너 프로세스는 이 순서로 구성을 읽습니다:

  • DOCKER_AUTH_CONFIG CI/CD 변수.
  • 러너의 config.toml 파일에 설정된 DOCKER_AUTH_CONFIG 환경 변수.
  • 프로세스를 실행하는 사용자의 $HOME/.docker 디렉토리에 있는 config.json 파일.

    자식 프로세스를 비특권 사용자로 실행하기 위해 --user 플래그가 제공된 경우,

    주요 러너 프로세스 사용자의 홈 디렉토리가 사용됩니다.

요구 사항 및 제한 사항

  • GitLab Runner 13.1 이상에서 Kubernetes executor에서 사용할 수 있습니다.
  • 자격증명 저장소자격증명 도우미는 GitLab Runner의 $PATH에 바이너리를 추가해야 하며, 이를 위한 접근 권한이 필요합니다. 따라서 이러한 기능은 인스턴스 러너 또는 사용자가 러너가 설치된 환경에 대한 접근 권한이 없는 다른 러너에서는 사용할 수 없습니다.

정적으로 정의된 자격증명 사용하기

개인 레지스트리에 접근하기 위해 취할 수 있는 두 가지 접근 방식이 있습니다.

두 방법 모두 적절한 인증 정보를 가진 CI/CD 변수 DOCKER_AUTH_CONFIG를 설정해야 합니다.

  1. 작업별: 특정 작업이 개인 레지스트리에 접근할 수 있도록 하려면, DOCKER_AUTH_CONFIGCI/CD 변수로 추가하세요.

  2. 러너별: 모든 작업이 개인 레지스트리에 접근할 수 있도록 러너를 구성하려면, 러너의 구성에서 환경 변수로 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 구성을 수동으로 작성해야 합니다. 터미널을 열고 다음 명령을 실행하세요:

    # printf의 사용(반드시 echo가 아님)은 비밀번호에 줄 바꿈을 인코딩하지 않도록 합니다.
    printf "my_username:my_password" | openssl base64 -A
    
    # 복사할 예제 출력
    bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=
    

참고: 사용자 이름에 @와 같은 특수 문자가 포함되어 있는 경우, 인증 문제를 방지하기 위해 해당 문자를 백슬래시(\)로 이스케이프해야 합니다.

Docker JSON 구성 콘텐츠를 다음과 같이 작성합니다:

  {
      "auths": {
          "registry.example.com:5000": {
              "auth": "(상기에서 가져온 Base64 콘텐츠)"
          }
      }
  }

작업 구성

registry.example.com:5000에 대한 접근 권한을 가진 단일 작업을 구성하려면 다음 단계를 따르세요:

  1. Docker 구성 파일의 내용을 값으로 하는 CI/CD 변수 DOCKER_AUTH_CONFIG를 만듭니다:

    {
        "auths": {
            "registry.example.com:5000": {
                "auth": "bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ="
            }
        }
    }
    
  2. 이제 .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_CONFIGregistry.example.com:5000을 지정해야 합니다.
registry.example.com만 지정해서는 작동하지 않습니다.

러너 구성

많은 파이프라인이 동일한 레지스트리에 접근하는 경우, 러너 수준에서 레지스트리 접근 권한을 설정해야 합니다. 이는 파이프라인 작성자가 적절한 러너에서 작업을 실행함으로써 개인 레지스트리에 접근할 수 있게 합니다. 또한 레지스트리 변경 사항 및 자격 증명 회전을 단순화하는 데 도움이 됩니다.

즉, 해당 러너에서 모든 작업이 동일한 권한으로 레지스트리에 접근할 수 있습니다. 여러 프로젝트에 걸쳐서도 가능합니다. 레지스트리에 대한 접근 권한을 제어해야 하는 경우, 러너에 대한 접근을 제어하는 것도 확실히 해야 합니다.

러너에 DOCKER_AUTH_CONFIG를 추가하려면:

  1. 러너의 config.toml 파일을 다음과 같이 수정합니다:

    [[runners]]
      environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.example.com:5000\":{\"auth\":\"bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=\"}}}"]
    
    • DOCKER_AUTH_CONFIG 데이터에 포함된 이중 인용부호는 백슬래시로 이스케이프해야 합니다. 이는 TOML로 해석되는 것을 방지합니다.
    • environment 옵션은 목록입니다. 러너에 기존 항목이 있을 수 있으며 이를 목록에 추가해야 하며 교체하면 안 됩니다.
  2. 러너 서비스를 재시작합니다.

자격 증명 저장소 사용

자격 증명 저장소를 구성하려면:

  1. 자격 증명 저장소를 사용하려면 특정 키체인이나 외부 저장소와 상호작용하는 외부 도우미 프로그램이 필요합니다.
    도우미 프로그램이 GitLab Runner의 $PATH에 있는지 확인하세요.

  2. GitLab Runner가 이를 사용하도록 설정합니다. 이를 달성하는 방법에는 두 가지가 있습니다. 다음 중 하나를 수행하세요:

    • Docker 구성 파일의 내용을 값으로 하는 CI/CD 변수 DOCKER_AUTH_CONFIG를 생성합니다:

        {
          "credsStore": "osxkeychain"
        }
      
    • 또는, 자가 관리 러너를 실행 중인 경우 위의 JSON을 ${GITLAB_RUNNER_HOME}/.docker/config.json에 추가하세요. GitLab Runner는 이 구성 파일을 읽고 이 특정 저장소를 위해 필요한 도우미를 사용합니다.

credsStore모든 레지스트리에 접근하는 데 사용됩니다.
개인 레지스트리의 이미지를 사용하고 Docker Hub의 공개 이미지를 사용하면 Docker Hub에서 가져오기가 실패합니다.
Docker 데몬은 모든 레지스트리에 대해 동일한 자격 증명을 사용하려고 합니다.

자격 증명 도우미 사용하기

  • GitLab Runner 12.0에서 도입되었습니다.

예를 들어, <aws_account_id>.dkr.ecr.<region>.amazonaws.com/private/image:latest 이미지를 사용하고 싶다고 가정해 봅시다. 이 이미지는 비공식이며, 개인 컨테이너 레지스트리에 로그인해야 합니다.

<aws_account_id>.dkr.ecr.<region>.amazonaws.com에 대한 접근을 구성하려면 다음 단계를 따르세요:

  1. docker-credential-ecr-login가 GitLab Runner의 $PATH에 있는지 확인하세요.

  2. 다음 AWS 자격 증명 중 하나가 설정되어 있는지 확인하세요.
    GitLab Runner가 자격 증명에 접근할 수 있도록 하세요.

  3. GitLab Runner가 이를 사용하도록 설정하세요. 이를 달성하는 방법은 두 가지가 있습니다. 다음 중 하나를 선택하세요:

    • CI/CD 변수
      DOCKER_AUTH_CONFIG를 Docker 구성 파일의 내용으로 설정하세요:

      {
        "credHelpers": {
          "<aws_account_id>.dkr.ecr.<region>.amazonaws.com": "ecr-login"
        }
      }
      

      이는 Docker가 특정 레지스트리에 대한 Credential Helper를 사용하도록 구성합니다.

      대신, Amazon Elastic Container Registry (ECR) 레지스트리에 대한 Credential Helper를 사용하도록 Docker를 구성할 수 있습니다:

      {
        "credsStore": "ecr-login"
      }
      

      참고:
      {"credsStore": "ecr-login"}을 사용하는 경우, ECR Credential Helper가 인증 토큰을 가져올 때 지역이 지정되어야 하므로, AWS 공유 구성 파일(~/.aws/config)에서 지역을 명시적으로 설정해야 합니다.

    • 또는, 자체 관리하는 러너를 실행 중인 경우,
      이전 JSON을 ${GITLAB_RUNNER_HOME}/.docker/config.json에 추가하세요.
      GitLab Runner는 이 구성 파일을 읽고 이 특정 리포지토리에 필요한 도우미를 사용합니다.

  4. 이제 .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는 <aws_account_id>.dkr.ecr.<region>.amazonaws.com에서
    이미지 private/image:latest를 찾습니다.

원하는 만큼 레지스트리에 대한 구성을 추가할 수 있으며, "credHelpers" 해시에 더 많은 레지스트리를 추가할 수 있습니다.

이미지 보안을 위한 체크섬 사용하기

우리는 .gitlab-ci.yml 파일의 작업 정의에서 이미지의 체크섬을 사용하는 것을 권장하여
이미지의 무결성을 확인합니다. 이미지 무결성 검증이 실패하면 수정된 컨테이너를 사용할 수 없습니다.

이미지 체크섬을 사용하려면 체크섬을 끝에 추가해야 합니다:

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 러너 Docker 이미지 생성

AWS CLI 및 Amazon ECR Credential Helper를 패키지하기 위해 커스텀 GitLab 러너 Docker 이미지를 생성할 수 있습니다. 이 설정은 AWS 서비스와의 안전하고 효율적인 상호작용을 촉진하며, 특히 컨테이너화된 애플리케이션에 유용합니다. 예를 들어, 수동 구성의 시간 및 오류를 줄이기 위해 AWS에서 마이크로서비스를 배포하는 팀은 이 설정을 사용하여 수동 자격 증명 관리 없이 Amazon ECR에서 Docker 이미지를 관리, 배포 및 업데이트할 수 있습니다.

  1. GitLab을 AWS에 인증하기.
  2. 다음 내용을 포함하는 Dockerfile을 생성합니다:

    # 패키지 버전 제어
    ARG GITLAB_RUNNER_VERSION=v17.3.0
    ARG AWS_CLI_VERSION=2.17.36
    
    # AWS CLI 및 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
    
    # 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
    
    # ECR Credential Helper 구성
    RUN mkdir -p /root/.docker
    RUN echo '{ "credsStore": "ecr-login" }' > /root/.docker/config.json
    
    # GitLab 러너를 기반으로 한 최종 이미지
    FROM gitlab/gitlab-runner:${GITLAB_RUNNER_VERSION}
    
    # 필요한 패키지 설치
    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/*
    
    # AWS CLI 및 Amazon ECR Credential Helper 바이너리 복사
    COPY --from=aws-tools /usr/local/bin/ /usr/local/bin/
    
    # ECR Credential Helper 구성 복사
    COPY --from=aws-tools /root/.docker/config.json /root/.docker/config.json
    
  3. .gitlab-ci.yml 내에서 커스텀 GitLab 러너 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 "GitLab 컨테이너 레지스트리에 로그인 중..."
        - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
        - echo "Docker 이미지 빌드 중..."
        - docker build --build-arg GITLAB_RUNNER_VERSION=${GITLAB_RUNNER_VERSION} --build-arg AWS_CLI_VERSION=${AWS_CLI_VERSION} -t ${IMAGE_NAME} .
        - echo "Docker 이미지를 GitLab 컨테이너 레지스트리에 푸시 중..."
        - docker push ${IMAGE_NAME}
      rules:
        - changes:
            - Dockerfile
    
  4. 러너 등록하기.