도커 컨테이너에서 CI/CD 작업 실행

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

CI/CD 작업을 독립적이고 격리된 도커 컨테이너에서 실행할 수 있습니다.

로컬 머신에서 도커를 실행하면 테스트를 전용 CI/CD 서버에서가 아닌 컨테이너에서 실행할 수 있습니다.

CI/CD 작업을 도커 컨테이너에서 실행하려면 다음을 수행해야 합니다:

  1. 모든 작업이 도커 컨테이너에서 실행되도록 러너를 등록합니다. 이를 위해 등록하는 동안 Docker executor를 선택합니다.
  2. 작업을 실행할 컨테이너를 지정합니다. 이를 위해 .gitlab-ci.yml 파일에서 이미지를 지정합니다.
  3. 선택 사항. MySQL과 같은 다른 서비스를 컨테이너에서 실행합니다. 이를 위해 .gitlab-ci.yml 파일에서 services를 지정합니다.

Docker executor를 사용하는 러너 등록

Docker를 사용하여 GitLab 러너를 사용하려면 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/" \
  --registration-token "PROJECT_REGISTRATION_TOKEN" \
  --description "docker-ruby:2.6" \
  --executor "docker" \
  --template-config /tmp/test-config.template.toml \
  --docker-image ruby:2.6

등록된 러너는 ruby:2.6 도커 이미지를 사용하고 postgres:latestmysql:latest라는 두 개의 서비스를 실행합니다. 이 서비스들은 모두 빌드 프로세스 중에 접근할 수 있습니다.

이미지란

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

기본적으로 executor는 이미지를 Docker Hub에서 가져옵니다. 그러나 gitlab-runner/config.toml 파일에서 레지스트리 위치를 구성할 수 있습니다. 예를 들어 Docker pull 정책를 사용하여 로컬 이미지를 설정할 수 있습니다.

이미지와 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: <이미지-이름> (<이미지-이름>latest 태그를 사용하는 것과 동일)
  • image: <이미지-이름>:<태그>
  • image: <이미지-이름>@<다이제스트>

확장된 Docker 구성 옵션

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

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

  • 문자열은 레지스트리가 Docker Hub가 아닌 레지스트리에서 이미지를 다운로드하려는 경우와 같이 전체 이미지 이름을 포함해야 합니다.
  • 맵은 적어도 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/<프로젝트-경로>/ 디렉터리에서 실행됩니다. 이미지에는 다른 기본 WORKDIR가 정의될 수 있습니다. WORKDIR를 저장하여 작업의 런타임 중에 컨테이너에서 참조할 수 있도록 하려면 WORKDIR를 환경 변수로 저장하세요.

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

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

사용 가능한 엔트리포인트 재정의 방법을 설명하기 전에 먼저 Runner가 어떻게 시작되는지 설명하겠습니다. CI/CD 작업에서 사용되는 컨테이너에는 Docker 이미지를 사용합니다.

  1. Runner는 정의된 엔트리포인트를 사용하여 Docker 컨테이너를 시작합니다. 이는 .gitlab-ci.yml 파일에서 재정의할 수 있는 Dockerfile의 기본 설정입니다.
  2. Runner는 실행 중인 컨테이너에 자체를 연결합니다.
  3. Runner는 스크립트( before_script, script, after_script의 조합)를 준비합니다.
  4. Runner는 스크립트를 컨테이너 쉘의 stdin으로 보내고 출력을 받습니다.

Docker 이미지의 엔트리포인트를 재정의하려면, .gitlab-ci.yml 파일에서 빈 entrypoint를 정의하여 Runner가 쓸모없는 쉘 레이어를 시작하지 않도록 합니다. 그러나 모든 Docker 버전에 대해 해당 방법이 작동하지는 않습니다.

  • Docker 17.06 이상의 경우, entrypoint를 빈 값으로 설정할 수 있습니다.
  • Docker 17.03 이하의 경우, entrypoint/bin/sh -c, /bin/bash -c, 또는 이미지에서 사용 가능한 동등한 쉘로 설정할 수 있습니다.

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

예를 들어 super/sql:experimental 이미지에 SQL 데이터베이스가 있다고 가정해봅시다. 이 데이터베이스 바이너리로 몇 가지 테스트를 실행하려고 하기 때문에 작업에서 기본 이미지로 사용하려고 합니다. 또한 이 이미지가 엔트리포인트로 /usr/bin/super-sql run을 구성했다고 가정해봅시다. 추가 옵션이 없이 컨테이너를 시작하면 데이터베이스 프로세스가 실행됩니다. Runner는 이미지에 엔트리포인트가 없거나 엔트리포인트가 쉘 명령을 시작할 수 있도록 준비되어 있다고 예상합니다.

확장된 Docker 구성 옵션을 사용하면 다음과 같습니다:

  • super/sql:experimental를 기반으로 자체 이미지를 생성합니다.
  • ENTRYPOINT를 셸로 설정합니다.
  • 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에서 이미지 및 서비스 정의하기

[runners.docker] 섹션을 찾아보세요:

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

이 방법으로 정의된 이미지와 서비스는 해당 Runner에서 실행되는 모든 작업에 추가됩니다.

개인 컨테이너 레지스트리에서 이미지 액세스

개인 컨테이너 레지스트리에 액세스하려면 GitLab Runner 프로세스에서 다음을 사용할 수 있습니다:

사용할 옵션을 정의하려면 Runner 프로세스는 다음의 순서로 구성을 읽습니다:

  • DOCKER_AUTH_CONFIG CI/CD 변수.
  • Runner의 config.toml 파일에서 설정된 DOCKER_AUTH_CONFIG 환경 변수.
  • 사용자가 실행 중인 프로세스의 $HOME/.docker 디렉토리에 있는 config.json 파일. 자식 프로세스를 언프리빌리지드 사용자로 실행하도록 --user 플래그가 제공된 경우, 주 러너 프로세스 사용자의 홈 디렉토리가 사용됩니다.

요구 사항 및 제한 사항

  • GitLab Runner 13.1 이상의 Kubernetes executor에서 사용할 수 있습니다.
  • 자격 증명 저장소자격 증명 도우미는 GitLab Runner $PATH에 바이너리를 추가하고 그러한 작업을 수행할 수 있는 권한이 필요합니다. 따라서 이러한 기능을 인스턴스 러너나 사용자가 환경에 액세스할 수 없는 다른 러너에는 사용할 수 없습니다.

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

개인 레지스트리에 액세스하는 데 취할 수 있는 두 가지 접근 방식이 있습니다. 모두 적절한 인증 정보를 가지고 DOCKER_AUTH_CONFIG CI/CD 변수를 설정해야 합니다.

  1. 작업당: 개인 레지스트리에 액세스하도록 하나의 작업을 구성하려면 DOCKER_AUTH_CONFIGCI/CD 변수로 추가하세요.
  2. 러너당: 러너를 구성하여 모든 작업이 개인 레지스트리에 액세스할 수 있도록 하려면 DOCKER_AUTH_CONFIG를 러너 구성의 환경 변수로 추가하세요.

각각의 예시는 아래에서 확인할 수 있습니다.

도커 DOCKER_AUTH_CONFIG 데이터 결정

예를 들어, registry.example.com:5000/private/image:latest 이미지를 사용하려고 한다고 가정해 봅시다. 이 이미지는 비공개이며 개인 컨테이너 레지스트리에 로그인해야 합니다.

또한 다음이 로그인 자격 증명이라고 가정해 봅시다:

레지스트리 registry.example.com:5000
사용자 이름 my_username
비밀번호 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을 수동으로 작성해야 합니다. 터미널을 열고 다음 명령을 실행하세요:

    # 새 줄을 인코딩하지 않기 위해 echo가 아닌 printf를 사용합니다.
    printf "my_username:my_password" | openssl base64 -A
    
    # 복사할 예시 출력
    bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=
    

    다음과 같이 Docker JSON 구성 내용을 작성하세요:

    {
        "auths": {
            "registry.example.com:5000": {
                "auth": "(위의 base64 내용)"
            }
        }
    }
    

작업 구성

registry.example.com:5000에 액세스 권한을 갖는 단일 작업을 구성하려면 다음 단계를 따르세요:

  1. CI/CD 변수 DOCKER_AUTH_CONFIG를 다음과 같이 생성하세요. 해당 Docker 구성 파일의 내용을 값으로 사용하세요:

    {
        "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가 사용하도록 설정하세요. 다음 중 한 가지 방법으로 수행합니다:

    • CI/CD 변수 DOCKER_AUTH_CONFIG를 생성하세요. 해당 Docker 구성 파일의 내용을 값으로 사용하세요:

        {
          "credsStore": "osxkeychain"
        }
      
    • 또는, self-managed 러너를 실행 중이라면 위의 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. GitLab Runner의 $PATHdocker-credential-ecr-login이 있는지 확인하십시오.
  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가 특정 레지스트리에 대해 자격 증명 도우미를 사용하도록 구성됩니다.

      대신, Docker를 모든 Amazon Elastic Container Registry (ECR) 레지스트리에 대해 자격 증명 도우미를 사용하도록 구성할 수 있습니다.

      {
        "credsStore": "ecr-login"
      }
      
    • 또는, self-managed 러너를 실행 중이라면, 이전 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 Runner Docker 이미지 만들기

AWS CLI와 Amazon ECR Credential Helper를 패키지화하기 위해 커스텀 GitLab Runner Docker 이미지를 만들 수 있습니다. 이 설정은 특히 컨테이너화된 응용 프로그램을 위해 AWS 서비스와의 안전하고 효율적인 상호 작용을 용이하게 합니다. 예를 들어, AWS에 마이크로서비스를 배포하는 팀들은 수동 자격 증명 관리를 사용하지 않고 Amazon ECR에 Docker 이미지를 관리, 배포 및 업데이트하는 데에 이 설정을 사용할 수 있습니다.

  1. AWS와 GitLab을 인증하십시오.
  2. 다음 내용으로 Dockerfile를 만드십시오.

       # 패키지 버전 관리
       ARG GITLAB_RUNNER_VERSION=v16.4.0
       ARG AWS_CLI_VERSION=2.2.30
    
       # 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 RUNNER 기반의 최종 이미지
       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 Runner Docker 이미지를 빌드하도록 다음 예제를 포함하십시오.

     variables:
       DOCKER_DRIVER: overlay2
       IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
       GITLAB_RUNNER_VERSION: v16.4.0
       AWS_CLI_VERSION: 2.13.21
    
     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. 런너를 등록하십시오.