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

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

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

로컬 머신에서 Docker를 실행하는 경우 테스트를 전용 CI/CD 서버에서 하는 대신 컨테이너에서 테스트를 실행할 수 있습니다.

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

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

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 Docker 이미지를 사용하고 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로 이동할 수 있습니다.

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

제공되는 엔트리포인트 재정의 방법을 설명하기 전에 러너가 실행되는 방식에 대해 설명하겠습니다. CI/CD 작업에 사용되는 컨테이너에 대한 Docker 이미지를 사용하여 러너가 시작됩니다.

  1. 러너는 정의된 엔트리포인트를 사용하여 Docker 컨테이너를 시작합니다. .gitlab-ci.yml 파일에서 이를 재정의할 수 있습니다.
  2. 러너는 실행 중인 컨테이너에 자신을 부착합니다.
  3. 러너는 스크립트를 준비합니다. (여기에는 before_script, script, after_script의 조합이 포함됩니다)
  4. 러너는 스크립트를 컨테이너의 셸 stdin에 전송하고 출력을 받습니다.

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

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

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

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

확장된 Docker 구성 옵션을 사용하면 다음과 같이 .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"]

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

프라이빗 컨테이너 레지스트리에서 이미지에 액세스하기

프라이빗 컨테이너 레지스트리에 액세스하려면 GitLab 러너 프로세스가 다음을 사용할 수 있습니다:

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

  • DOCKER_AUTH_CONFIG CI/CD 변수.
  • 러너의 config.toml 파일에서 설정된 DOCKER_AUTH_CONFIG 환경 변수.
  • 사용자가 프로세스를 실행하는 사용자의 $HOME/.docker 디렉터리에 있는 config.json 파일. 자식 프로세스를 비권한 사용자로 실행할 수 있도록 --user 플래그가 제공되면 주 러너 프로세스 사용자의 홈 디렉터리를 사용합니다.

요구 사항 및 제한 사항

  • GitLab 러너 13.1 이상의 Kubernetes executor에서 사용 가능합니다.
  • 자격 증명 스토어자격 증명 도우미는 이진 파일을 GitLab 러너 $PATH에 추가하고 이를 수행할 수 있는 권한이 있어야 합니다. 따라서 이러한 기능은 인스턴스 러너나 러너가 설치된 환경에 액세스 권한이 없는 경우에는 사용할 수 없습니다.

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

프라이빗 레지스트리에 액세스하려면 두 가지 방법을 사용할 수 있습니다. 양쪽 모두 적절한 인증 정보로 DOCKER_AUTH_CONFIG를 설정해야 합니다.

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

아래에 각각의 예제를 참조하세요.

DOCKER_AUTH_CONFIG 데이터 확인하기

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

다음은 로그인 자격 증명입니다:

Key Value
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을 매뉴얼으로 생성해야 합니다. 터미널을 열고 다음 명령을 실행합니다:

    # 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 러너는 registry.example.com:5000에 있는 namespace/image:tag 이미지를 참조합니다.

원하는 만큼의 레지스트리에 대해 구성을 추가하여 이를 도와드립니다.

러너가 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만 지정하는 것은 작동하지 않습니다.

러너 구성하기

동일한 레지스트리에 액세스하는 다수의 파이프라인이 있는 경우, 러너 수준에서 레지스트리 액세스 구성해야 합니다. 이렇게 하면 파이프라인 작성자가 해당 러너에서 작업을 실행하기만 하면 프라이빗 레지스트리에 액세스할 수 있으며, 레지스트리 변경 및 자격 증명 회전을 단순화하는 데 도움이 됩니다.

즉, 해당 러너에 있는 모든 작업이 동일한 권한으로 레지스트리에 액세스할 수 있습니다. 프로젝트 간에도 권한을 제어해야 하는 경우 러너 액세스를 제어해야 합니다.

러너에 DOCKER_AUTH_CONFIG를 추가하려면 다음 단계를 따르세요:

  1. 러너의 config.toml 파일을 다음과 같이 수정하세요:

    [[runners]]
      environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.example.com:5000\":{\"auth\":\"bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=\"}}}"]
    
    • DOCKER_AUTH_CONFIG 데이터에 포함된 이중 따옴표는 escape를 사용하여 처리해야 합니다. 이렇게 하면 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 데몬은 모든 레지스트리에 대해 동일한 자격 증명을 사용하려고 시도합니다.

자격 증명 도우미 사용

  • 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를 특정 레지스트리에 대해 자격 증명 도우미를 구성합니다.

      대신, 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는 private/image:latest 이미지를 위해 <aws_account_id>.dkr.ecr.<region>.amazonaws.com를 참조합니다.

필요한 만큼 많은 레지스트리에 대한 구성을 추가하여 "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 자격 증명 도우미를 패키지로 만드는 사용자 정의 GitLab 러너 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 자격 증명 도우미
       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 자격 증명 도우미 다운로드 및 설치
       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 자격 증명 도우미 구성
       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 자격 증명 도우미 이진 파일 복사
       COPY --from=aws-tools /usr/local/bin/ /usr/local/bin/
          
       # ECR 자격 증명 도우미 구성 파일 복사
       COPY --from=aws-tools /root/.docker/config.json /root/.docker/config.json
    
  3. 사용자 정의 GitLab 러너 Docker 이미지를 .gitlab-ci.yml에서 만들기 위해 다음 예제를 포함하세요:

     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