InfoGrab Docs

Docker를 사용하여 Docker 이미지 빌드

요약

GitLab CI/CD와 Docker를 함께 사용하여 Docker 이미지를 생성할 수 있습니다. CI/CD job에서 Docker 명령을 실행하려면 docker 명령을 지원하도록 GitLab Runner를 구성해야 합니다.

GitLab CI/CD와 Docker를 함께 사용하여 Docker 이미지를 생성할 수 있습니다. 예를 들어 애플리케이션의 Docker 이미지를 생성하고, 테스트하고, 컨테이너 레지스트리에 푸시할 수 있습니다.

CI/CD job에서 Docker 명령을 실행하려면 docker 명령을 지원하도록 GitLab Runner를 구성해야 합니다. 이 방법은 privileged 모드가 필요합니다.

러너에서 privileged 모드를 활성화하지 않고 Docker 이미지를 빌드하려면 Docker 대안을 사용할 수 있습니다.

CI/CD job에서 Docker 명령 활성화#

CI/CD job에 Docker 명령을 활성화하려면 다음을 사용할 수 있습니다:

shell executor 사용#

CI/CD job에 Docker 명령을 포함하려면, shell executor를 사용하도록 러너를 구성할 수 있습니다. 이 구성에서 gitlab-runner 사용자가 Docker 명령을 실행하지만, 그러기 위한 권한이 필요합니다.

  1. GitLab Runner를 설치합니다.

  2. 러너를 등록합니다. shell executor를 선택합니다. 예:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor shell \
      --description "My Runner"
    
  3. GitLab Runner가 설치된 서버에 Docker Engine을 설치합니다. 지원 플랫폼 목록을 확인하세요.

  4. gitlab-runner 사용자를 docker 그룹에 추가합니다:

    sudo usermod -aG docker gitlab-runner
    
  5. gitlab-runner가 Docker에 접근할 수 있는지 확인합니다:

    sudo -u gitlab-runner -H docker info
    
  6. GitLab에서 Docker가 작동하는지 확인하기 위해 .gitlab-ci.ymldocker info를 추가합니다:

    default:
      before_script:
        - docker info
    
    build_image:
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

이제 docker 명령을 사용할 수 있습니다(필요한 경우 Docker Compose도 설치 가능).

gitlab-runnerdocker 그룹에 추가하면 gitlab-runner에게 실질적으로 전체 root 권한을 부여하게 됩니다. 자세한 내용은 docker 그룹의 보안을 참조하세요.

Docker-in-Docker 사용#

"Docker-in-Docker" (dind)의 의미:

Docker 이미지에는 모든 docker 도구가 포함되어 있으며 privileged 모드에서 이미지 컨텍스트로 job 스크립트를 실행할 수 있습니다.

TLS가 활성화된 Docker-in-Docker를 사용해야 하며, GitLab.com 인스턴스 러너에서 지원됩니다.

항상 docker:24.0.5와 같이 이미지의 특정 버전을 지정해야 합니다. docker:latest와 같은 태그를 사용하면 어떤 버전이 사용되는지 제어할 수 없습니다. 이는 새 버전이 릴리스될 때 호환성 문제를 일으킬 수 있습니다.

Docker executor와 Docker-in-Docker 사용#

Docker executor를 사용하여 Docker 컨테이너에서 job을 실행할 수 있습니다.

Docker executor에서 TLS 활성화된 Docker-in-Docker#

Docker 데몬은 TLS를 통한 연결을 지원합니다. TLS는 Docker 19.03.12 이상에서 기본값입니다.

Warning

이 작업은 --docker-privileged를 활성화하여 컨테이너의 보안 메커니즘을 실질적으로 비활성화하고 호스트를 권한 상승에 노출시킵니다. 이 작업은 컨테이너 탈출을 유발할 수 있습니다. 자세한 내용은 런타임 권한 및 Linux 기능을 참조하세요.

TLS가 활성화된 Docker-in-Docker를 사용하려면:

  1. GitLab Runner를 설치합니다.

  2. 커맨드 라인에서 GitLab Runner를 등록합니다. dockerprivileged 모드를 사용합니다:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --tag-list "tls-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-privileged \
      --docker-volumes "/certs/client"
    
    • 이 명령은 docker:24.0.5-cli 이미지를 사용하는 새 러너를 등록합니다(job 레벨에서 지정하지 않은 경우). 빌드 및 서비스 컨테이너를 시작하기 위해 privileged 모드를 사용합니다. Docker-in-Docker를 사용하려면 Docker 컨테이너에서 항상 privileged = true를 사용해야 합니다.
    • 이 명령은 서비스 및 빌드 컨테이너에 대해 /certs/client를 마운트합니다. 이는 Docker 클라이언트가 해당 디렉터리의 인증서를 사용하는 데 필요합니다. 자세한 내용은 Docker 이미지 문서를 참조하세요.

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = true
        disable_cache = false
        volumes = ["/certs/client", "/cache"]
    
  3. 이제 job 스크립트에서 docker를 사용할 수 있습니다. docker:24.0.5-dind 서비스를 포함해야 합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다. Docker 19.03은
      # https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03/docker-entrypoint.sh#L23-L29에서
      # DOCKER_HOST를 설정하여 이를 자동으로 수행합니다
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services에서 설명합니다.
      #
      # Docker에 인증서를 생성할 위치를 지정합니다. Docker는
      # 부팅 시 자동으로 생성하고 config.toml의 볼륨 마운트 덕분에
      # 서비스와 job 컨테이너 간에 공유할 `/certs/client`를 생성합니다
      DOCKER_TLS_CERTDIR: "/certs"
    
    build:
      stage: build
      tags:
        - tls-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
Docker-in-Docker와 빌드 컨테이너 간 공유 볼륨의 Unix 소켓 사용#

Docker executor에서 TLS 활성화된 Docker-in-Docker 방식의 volumes = ["/certs/client", "/cache"]에 정의된 디렉터리는 빌드 간에 지속됩니다. Docker executor 러너를 사용하는 여러 CI/CD job에서 Docker-in-Docker 서비스가 활성화된 경우, 각 job은 디렉터리 경로에 씁니다. 이 방식은 충돌을 일으킬 수 있습니다.

이 충돌을 해결하려면 Docker-in-Docker 서비스와 빌드 컨테이너 간에 공유된 볼륨의 Unix 소켓을 사용합니다. 이 방식은 성능을 개선하고 서비스와 클라이언트 간의 보안 연결을 설정합니다.

다음은 빌드와 서비스 컨테이너 간에 공유된 임시 볼륨이 있는 config.toml 샘플입니다:

[[runners]]
  url = "https://gitlab.com/"
  token = TOKEN
  executor = "docker"
  [runners.docker]
    image = "docker:24.0.5-cli"
    privileged = true
    volumes = ["/runner/services/docker"] # 빌드와 서비스 컨테이너 간에 공유된 임시 볼륨.

Docker-in-Docker 서비스가 docker.sock을 생성합니다. Docker 클라이언트는 Docker Unix 소켓 볼륨을 통해 docker.sock에 연결됩니다.

job:
  variables:
    # 이 변수는 DinD 서비스와 Docker 클라이언트 모두 공유합니다.
    # 서비스의 경우, DinD가 여기에 `docker.sock`을 생성하도록 지시합니다.
    # 클라이언트의 경우, Docker 클라이언트가 연결할 Docker Unix 소켓을 알려줍니다.
    DOCKER_HOST: "unix:///runner/services/docker/docker.sock"
  services:
    - docker:24.0.5-dind
  image: docker:24.0.5-cli
  script:
    - docker version
Docker executor에서 TLS 비활성화된 Docker-in-Docker#

때로는 TLS를 비활성화할 타당한 이유가 있습니다. 예를 들어, 사용 중인 GitLab Runner 구성을 제어할 수 없는 경우입니다.

  1. 커맨드 라인에서 GitLab Runner를 등록합니다. dockerprivileged 모드를 사용합니다:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --tag-list "no-tls-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-privileged
    

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = true
        disable_cache = false
        volumes = ["/cache"]
    
  2. job 스크립트에 docker:24.0.5-dind 서비스를 포함합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다.
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services 참조
      #
      DOCKER_HOST: tcp://docker:2375
      #
      # Docker가 TLS 없이 시작하도록 지시합니다.
      DOCKER_TLS_CERTDIR: ""
    
    build:
      stage: build
      tags:
        - no-tls-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
Docker executor에서 프록시 활성화된 Docker-in-Docker#

docker push 명령을 사용하려면 프록시 설정을 구성해야 할 수 있습니다.

자세한 내용은 dind 서비스 사용 시 프록시 설정을 참조하세요.

Kubernetes executor와 Docker-in-Docker 사용#

Kubernetes executor를 사용하여 Docker 컨테이너에서 job을 실행할 수 있습니다.

Kubernetes에서 TLS 활성화된 Docker-in-Docker#

Kubernetes에서 TLS 활성화된 Docker-in-Docker를 사용하려면:

  1. Helm 차트를 사용하여 values.yml 파일을 업데이트하여 볼륨 마운트를 지정합니다.

    runners:
      tags: "tls-dind-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = true
          [[runners.kubernetes.volumes.empty_dir]]
            name = "docker-certs"
            mount_path = "/certs/client"
            medium = "Memory"
    
  2. job에 docker:24.0.5-dind 서비스를 포함합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - name: docker:24.0.5-dind
          variables:
            HEALTHCHECK_TCP_PORT: "2376"
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다.
      DOCKER_HOST: tcp://docker:2376
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services 참조
      #
      # Docker에 인증서를 생성할 위치를 지정합니다. Docker는
      # 부팅 시 자동으로 생성하고 config.toml의 볼륨 마운트 덕분에
      # 서비스와 job 컨테이너 간에 공유할 `/certs/client`를 생성합니다
      DOCKER_TLS_CERTDIR: "/certs"
      # 이것들은 보통 entrypoint에서 지정되지만, Kubernetes executor는
      # entrypoint를 실행하지 않습니다
      # https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4125
      DOCKER_TLS_VERIFY: 1
      DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
    
    build:
      stage: build
      tags:
        - tls-dind-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
Kubernetes에서 TLS 비활성화된 Docker-in-Docker#

Kubernetes에서 TLS 비활성화된 Docker-in-Docker를 사용하려면, 이전 예시를 다음과 같이 수정해야 합니다:

  • values.yml 파일에서 [[runners.kubernetes.volumes.empty_dir]] 섹션을 제거합니다.
  • DOCKER_HOST: tcp://docker:2375로 포트를 2376에서 2375로 변경합니다.
  • DOCKER_TLS_CERTDIR: ""로 TLS 비활성화하여 Docker를 시작하도록 지시합니다.

예:

  1. Helm 차트를 사용하여 values.yml 파일을 업데이트합니다:

    runners:
      tags: "no-tls-dind-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = true
    
  2. 이제 job 스크립트에서 docker를 사용할 수 있습니다. docker:24.0.5-dind 서비스를 포함해야 합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - name: docker:24.0.5-dind
          variables:
            HEALTHCHECK_TCP_PORT: "2375"
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다.
      DOCKER_HOST: tcp://docker:2375
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services 참조
      #
      # Docker가 TLS 없이 시작하도록 지시합니다.
      DOCKER_TLS_CERTDIR: ""
    build:
      stage: build
      tags:
        - no-tls-dind-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Docker-in-Docker의 알려진 문제#

Docker-in-Docker는 권장 구성이지만 다음 문제에 유의해야 합니다:

  • docker-compose 명령: 이 구성에서는 기본적으로 이 명령을 사용할 수 없습니다. job 스크립트에서 docker-compose를 사용하려면 Docker Compose 설치 지침을 따르세요.

  • 캐시: 각 job은 새로운 환경에서 실행됩니다. 모든 빌드가 자체 Docker 엔진 인스턴스를 갖기 때문에 동시 job은 충돌을 일으키지 않습니다. 그러나 레이어 캐싱이 없기 때문에 job이 더 느릴 수 있습니다. Docker 레이어 캐싱을 참조하세요.

  • 스토리지 드라이버: 기본적으로 이전 버전의 Docker는 각 job에 대해 파일 시스템을 복사하는 vfs 스토리지 드라이버를 사용합니다. Docker 17.09 이상은 권장 스토리지 드라이버인 --storage-driver overlay2를 사용합니다. 자세한 내용은 OverlayFS 드라이버 사용을 참조하세요.

  • 루트 파일 시스템: docker:24.0.5-dind 컨테이너와 러너 컨테이너가 루트 파일 시스템을 공유하지 않으므로, job의 작업 디렉터리를 자식 컨테이너의 마운트 포인트로 사용할 수 있습니다. 예를 들어, 자식 컨테이너와 공유하려는 파일이 있는 경우 /builds/$CI_PROJECT_PATH 아래에 하위 디렉터리를 생성하여 마운트 포인트로 사용할 수 있습니다. 자세한 내용은 이슈 #41227을 참조하세요.

    variables:
      MOUNT_POINT: /builds/$CI_PROJECT_PATH/mnt
    script:
      - mkdir -p "$MOUNT_POINT"
      - docker run -v "$MOUNT_POINT:/mnt" my-docker-image
    

Docker 소켓 바인딩 사용#

CI/CD job에서 Docker 명령을 사용하려면 /var/run/docker.sock을 빌드 컨테이너에 바인드 마운트할 수 있습니다. 그러면 Docker를 이미지 컨텍스트에서 사용할 수 있습니다.

Docker 소켓을 바인드하면 docker:24.0.5-dind를 서비스로 사용할 수 없습니다. 볼륨 바인딩도 서비스에 영향을 미쳐 호환되지 않습니다.

Docker executor와 Docker 소켓 바인딩 사용#

Docker executor로 Docker 소켓을 마운트하려면 "/var/run/docker.sock:/var/run/docker.sock"[runners.docker] 섹션의 볼륨에 추가합니다.

  1. 러너 등록 시 /var/run/docker.sock을 마운트하려면 다음 옵션을 포함합니다:

    sudo gitlab-runner register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor "docker" \
      --description "docker-runner" \
      --tag-list "socket-binding-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-volumes "/var/run/docker.sock:/var/run/docker.sock"
    

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = RUNNER_TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = false
        disable_cache = false
        volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
      [runners.cache]
        Insecure = false
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:24.0.5-cli
      before_script:
        - docker info
    
    build:
      stage: build
      tags:
        - socket-binding-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Kubernetes executor와 Docker 소켓 바인딩 사용#

Kubernetes executor로 Docker 소켓을 마운트하려면 "/var/run/docker.sock"[[runners.kubernetes.volumes.host_path]] 섹션의 볼륨에 추가합니다.

  1. 볼륨 마운트를 지정하려면 Helm 차트를 사용하여 values.yml 파일을 업데이트합니다.

    runners:
      tags: "socket-binding-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = false
          [runners.kubernetes]
            [[runners.kubernetes.volumes.host_path]]
              host_path = '/var/run/docker.sock'
              mount_path = '/var/run/docker.sock'
              name = 'docker-sock'
              read_only = true
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:24.0.5-cli
      before_script:
        - docker info
    build:
      stage: build
      tags:
        - socket-binding-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Docker 소켓 바인딩의 알려진 문제#

Docker 소켓 바인딩을 사용하면 Docker를 privileged 모드로 실행하는 것을 방지할 수 있습니다. 그러나 이 방법의 영향은 다음과 같습니다:

  • Docker 데몬을 공유하면 실질적으로 컨테이너의 보안 메커니즘을 비활성화하고 호스트를 권한 상승에 노출시킵니다. 이는 컨테이너 탈출을 일으킬 수 있습니다. 예를 들어, 프로젝트에서 docker rm -f $(docker ps -a -q)를 실행하면 GitLab Runner 컨테이너가 제거됩니다.

  • 동시 job이 작동하지 않을 수 있습니다. 테스트에서 특정 이름의 컨테이너를 생성하면 서로 충돌할 수 있습니다.

  • Docker 명령으로 생성된 컨테이너는 러너의 자식이 아닌 형제입니다. 이는 워크플로에 복잡성을 더할 수 있습니다.

  • 소스 리포지터리에서 컨테이너로 파일 및 디렉터리를 공유하는 것이 예상대로 작동하지 않을 수 있습니다. 볼륨 마운팅은 빌드 컨테이너가 아닌 호스트 머신의 컨텍스트에서 수행됩니다. 예:

    docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_app_tests
    

Docker-in-Docker executor를 사용할 때처럼 docker:24.0.5-dind 서비스를 포함할 필요가 없습니다:

default:
  image: docker:24.0.5-cli
  before_script:
    - docker info

build:
  stage: build
  script:
    - docker build -t my-docker-image .
    - docker run my-docker-image /script/to/run/tests

CodeClimate를 사용한 코드 품질 스캐닝과 같은 복잡한 Docker-in-Docker 설정의 경우, 적절한 실행을 위해 호스트와 컨테이너 경로를 일치시켜야 합니다. 자세한 내용은 CodeClimate 기반 스캐닝에 개인 러너 사용을 참조하세요.

Docker 파이프 바인딩 사용#

Windows 컨테이너는 Docker-in-Docker 방식을 지원하지 않으므로, 컨테이너 내에서 중첩된 Docker Engine을 실행할 수 없습니다. Windows 컨테이너 내에서 Docker 이미지를 빌드하거나 관리하려면 Docker 파이프 바인딩(Docker-outside-of-Docker 또는 DooD라고도 함)을 사용합니다.

Warning

Docker 파이프 바인딩은 보안적 영향이 있습니다. \\\\.\\pipe\\docker_engine을 바인드 마운트하면 컨테이너가 호스트의 Docker 데몬에 대한 전체 관리자 액세스 권한을 갖게 됩니다. 컨테이너 내의 프로세스는 다른 컨테이너를 시작하거나 중지하고, 이미지를 관리하며, 호스트 시스템에서 권한을 상승시킬 수 있습니다.

Docker 파이프 바인딩을 사용하려면 호스트 Windows Server 운영 체제에 Docker Engine을 설치하고 실행해야 합니다. 자세한 내용은 Windows Server에 Docker Community Edition (CE) 설치를 참조하세요.

Windows 기반 컨테이너 CI/CD job에서 Docker 명령을 사용하려면 \\\\.\\pipe\\docker_engine을 실행된 executor 컨테이너에 바인드 마운트할 수 있습니다. 그러면 Docker를 이미지 컨텍스트에서 사용할 수 있습니다.

Windows에서의 Docker 파이프 바인딩Linux에서의 Docker 소켓 바인딩과 유사하며 알려진 문제Docker 소켓 바인딩의 알려진 문제와 유사합니다.

Docker 파이프 바인딩 사용의 필수 전제 조건은 호스트 Windows Server 운영 체제에 Docker Engine이 설치되어 실행 중인 것입니다.

Docker executor와 Docker 파이프 바인딩 사용#

Docker executor를 사용하여 Windows 기반 컨테이너에서 job을 실행할 수 있습니다.

Docker executor로 Docker 파이프를 마운트하려면 "\\\\.\\pipe\\docker_engine:\\\\.\\pipe\\docker_engine"[runners.docker] 섹션의 볼륨에 추가합니다.

  1. 러너 등록 시 \\\\.\\pipe\\docker_engine을 마운트하려면 다음 옵션을 포함합니다:

    .\gitlab-runner.exe register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor "docker-windows" \
      --description "docker-windows-runner"
      --tag-list "docker-windows-runner" \
      --docker-image "docker:25-windowsservercore-ltsc2022" \
      --docker-volumes "\\\\.\\pipe\\docker_engine:\\\\.\\pipe\\docker_engine"
    

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = RUNNER_TOKEN
      executor = "docker-windows"
      [runners.docker]
        tls_verify = false
        image = "docker:25-windowsservercore-ltsc2022"
        privileged = false
        disable_cache = false
        volumes = ["\\\\.\\pipe\\docker_engine:\\\\.\\pipe\\docker_engine"]
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:25-windowsservercore-ltsc2022
      before_script:
        - docker version
        - docker info
    
    build:
      stage: build
      tags:
        - docker-windows-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Kubernetes executor와 Docker 파이프 바인딩 사용#

Kubernetes executor를 사용하여 Windows 기반 컨테이너에서 job을 실행할 수 있습니다.

Windows 기반 컨테이너에 Kubernetes executor를 사용하려면 Kubernetes 클러스터에 Windows 노드를 포함해야 합니다. 자세한 내용은 Kubernetes의 Windows 컨테이너를 참조하세요.

Linux 환경에서 실행 중이지만 Windows 노드를 대상으로 하는 러너를 사용할 수 있습니다.

Kubernetes executor로 Docker 파이프를 마운트하려면 "\\\\.\\pipe\\docker_engine"[[runners.kubernetes.volumes.host_path]] 섹션의 볼륨에 추가합니다.

  1. 볼륨 마운트를 지정하려면 Helm 차트를 사용하여 values.yml 파일을 업데이트합니다.

    runners:
      tags: "kubernetes-windows-runner"
      config: |
        [[runners]]
          executor = "kubernetes"
    
          # FF_USE_POWERSHELL_PATH_RESOLVER 기능 플래그는 러너가 Linux 환경에서
          # 실행 중이지만 Windows 노드를 대상으로 할 때
          # PowerShell이 Windows 경로를 올바르게 확인하도록 활성화해야 합니다.
          [runners.feature_flags]
            FF_USE_POWERSHELL_PATH_RESOLVER = true
    
          [runners.kubernetes]
            [[runners.kubernetes.volumes.host_path]]
              host_path = '\\\\.\\pipe\\docker_engine'
              mount_path = '\\\\.\\pipe\\docker_engine'
              name = 'docker-pipe'
              read_only = true
    
            [runners.kubernetes.node_selector]
              "kubernetes.io/arch" = "amd64"
              "kubernetes.io/os" = "windows"
              "node.kubernetes.io/windows-build" = "10.0.20348"
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:25-windowsservercore-ltsc2022
      before_script:
        - docker version
        - docker info
    
    build:
      stage: build
      tags:
        - kubernetes-windows-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
AWS EKS Kubernetes 클러스터의 알려진 문제#

dockerd에서 containerd로 마이그레이션할 때, AWS EKS 부트스트래핑 스크립트 Start-EKSBootstrap.ps1이 Docker 서비스를 중지하고 비활성화합니다. 이 문제를 해결하려면 Windows Server에 Docker Community Edition (CE) 설치 후 이 스크립트로 Docker 서비스 이름을 바꿉니다:

Write-Output "Rename the just installed Docker Engine Service from docker to dockerd"
Write-Output "because the Start-EKSBootstrap.ps1 stops and disables the docker Service as part of migration from dockerd to containerd"
Stop-Service -Name docker
dockerd --register-service --service-name dockerd
Start-Service -Name dockerd
Write-Output "Ready to do Docker pipe binding on Windows EKS Node! :-)"

Docker 파이프 바인딩의 알려진 문제#

Docker 파이프 바인딩은 Docker 소켓 바인딩의 알려진 문제와 동일한 보안 및 격리 문제를 가지고 있습니다.

docker:dind 서비스의 레지스트리 미러 활성화#

Docker 데몬이 서비스 컨테이너 내에서 시작될 때 기본 구성을 사용합니다. 성능 향상 및 Docker Hub 속도 제한 초과를 방지하기 위해 레지스트리 미러를 구성할 수 있습니다.

.gitlab-ci.yml 파일의 서비스#

dind 서비스에 추가 CLI 플래그를 추가하여 레지스트리 미러를 설정할 수 있습니다:

services:
  - name: docker:24.0.5-dind
    command: ["--registry-mirror", "https://registry-mirror.example.com"]  # 사용할 레지스트리 미러를 지정합니다

GitLab Runner 구성 파일의 서비스#

GitLab Runner 관리자라면 command를 지정하여 Docker 데몬의 레지스트리 미러를 구성할 수 있습니다. dind 서비스는 Docker 또는 Kubernetes executor에 대해 정의되어야 합니다.

Docker:

[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    ...
    privileged = true
    [[runners.docker.services]]
      name = "docker:24.0.5-dind"
      command = ["--registry-mirror", "https://registry-mirror.example.com"]

Kubernetes:

[[runners]]
  ...
  name = "kubernetes"
  [runners.kubernetes]
    ...
    privileged = true
    [[runners.kubernetes.services]]
      name = "docker:24.0.5-dind"
      command = ["--registry-mirror", "https://registry-mirror.example.com"]

GitLab Runner 구성 파일의 Docker executor#

GitLab Runner 관리자라면 모든 dind 서비스에 미러를 사용할 수 있습니다. 볼륨 마운트를 지정하도록 구성을 업데이트합니다.

예를 들어, 다음 내용이 포함된 /opt/docker/daemon.json 파일이 있는 경우:

{
  "registry-mirrors": [
    "https://registry-mirror.example.com"
  ]
}

config.toml 파일을 업데이트하여 파일을 /etc/docker/daemon.json에 마운트합니다. 이렇게 하면 GitLab Runner가 생성하는 모든 컨테이너에 파일이 마운트됩니다. dind 서비스가 구성을 감지합니다.

[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    image = "alpine:3.12"
    privileged = true
    volumes = ["/opt/docker/daemon.json:/etc/docker/daemon.json:ro"]

GitLab Runner 구성 파일의 Kubernetes executor#

GitLab Runner 관리자라면 모든 dind 서비스에 미러를 사용할 수 있습니다. ConfigMap 볼륨 마운트를 지정하도록 구성을 업데이트합니다.

예를 들어, 다음 내용이 포함된 /tmp/daemon.json 파일이 있는 경우:

{
  "registry-mirrors": [
    "https://registry-mirror.example.com"
  ]
}

이 파일의 내용으로 ConfigMap을 생성합니다. 다음과 같은 명령으로 할 수 있습니다:

kubectl create configmap docker-daemon --namespace gitlab-runner --from-file /tmp/daemon.json
Note

GitLab Runner의 Kubernetes executor가 job 파드를 생성하는 데 사용하는 네임스페이스를 사용해야 합니다.

ConfigMap이 생성된 후 config.toml 파일을 업데이트하여 파일을 /etc/docker/daemon.json에 마운트할 수 있습니다. 이 업데이트는 GitLab Runner가 생성하는 모든 컨테이너에 파일을 마운트합니다. dind 서비스가 이 구성을 감지합니다.

[[runners]]
  ...
  executor = "kubernetes"
  [runners.kubernetes]
    image = "alpine:3.12"
    privileged = true
    [[runners.kubernetes.volumes.config_map]]
      name = "docker-daemon"
      mount_path = "/etc/docker/daemon.json"
      sub_path = "daemon.json"

Docker-in-Docker에서 레지스트리 인증#

Docker-in-Docker를 사용할 때, 표준 인증 방법은 작동하지 않습니다. 서비스와 함께 새로운 Docker 데몬이 시작되기 때문입니다. 레지스트리 인증을 참조하세요.

Docker 레이어 캐싱#

Docker 레이어를 캐시하여 빌드 속도를 높일 수 있습니다. 자세한 내용은 Docker-in-Docker 빌드에서 Docker 레이어 캐싱을 참조하세요.

OverlayFS 드라이버 사용#

Note

GitLab.com의 인스턴스 러너는 기본적으로 overlay2 드라이버를 사용합니다.

기본적으로 docker:dind를 사용할 때 Docker는 실행할 때마다 파일 시스템을 복사하는 vfs 스토리지 드라이버를 사용합니다. 예를 들어 overlay2와 같은 다른 드라이버를 사용하여 이 디스크 집약적 작업을 방지할 수 있습니다.

요구 사항#

  1. 최근 커널이 사용되는지 확인합니다. 가능하면 >= 4.2를 권장합니다.

  2. overlay 모듈이 로드되었는지 확인합니다:

    sudo lsmod | grep overlay
    

    결과가 없으면 모듈이 로드되지 않은 것입니다. 모듈을 로드하려면 다음을 사용합니다:

    sudo modprobe overlay
    

    모듈이 로드된 경우 재부팅 시 모듈이 로드되도록 해야 합니다. Ubuntu 시스템에서는 /etc/modules에 다음 줄을 추가하여 이를 수행합니다:

    overlay
    

프로젝트별 OverlayFS 드라이버 사용#

.gitlab-ci.yml에서 DOCKER_DRIVER CI/CD 변수를 사용하여 각 프로젝트별로 드라이버를 활성화할 수 있습니다:

variables:
  DOCKER_DRIVER: overlay2

모든 프로젝트에 OverlayFS 드라이버 사용#

자체 러너를 사용하는 경우, config.toml 파일의 [[runners]] 섹션에서 DOCKER_DRIVER 환경 변수를 설정하여 모든 프로젝트에 대해 드라이버를 활성화할 수 있습니다:

environment = ["DOCKER_DRIVER=overlay2"]

여러 러너를 실행 중인 경우 모든 구성 파일을 수정해야 합니다.

러너 구성OverlayFS 스토리지 드라이버 사용에 대해 자세히 알아보세요.

Docker 대안#

러너에서 privileged 모드를 활성화하지 않고 컨테이너 이미지를 빌드할 수 있습니다:

  • BuildKit: Docker 데몬 의존성을 제거하는 rootless BuildKit 옵션 포함.
  • Buildah: Docker 데몬 없이 OCI 호환 이미지 빌드.

Buildah 예시#

GitLab CI/CD와 함께 Buildah를 사용하려면 다음 executor 중 하나를 가진 러너가 필요합니다:

이 예시에서 Buildah를 사용하여 다음을 수행합니다:

  1. Docker 이미지를 빌드합니다.
  2. GitLab 컨테이너 레지스트리에 푸시합니다.

마지막 단계에서 Buildah는 프로젝트 루트 디렉터리 아래의 Dockerfile을 사용하여 Docker 이미지를 빌드합니다. 마지막으로 이미지를 프로젝트의 컨테이너 레지스트리에 푸시합니다:

build:
  stage: build
  image: quay.io/buildah/stable
  variables:
    # Buildah와 함께 vfs를 사용합니다. Docker는 기본적으로 overlayfs를 제공하지만, Buildah는
    # overlayfs 파일 시스템 위에 overlayfs를 스택할 수 없습니다.
    STORAGE_DRIVER: vfs
    # 표준 OCI 형식이 아닌 docker 형식으로 모든 이미지 메타데이터를 작성합니다.
    # 최신 버전의 docker는 OCI 형식을 처리할 수 있지만, 오래된 버전(예:
    # Fedora 30과 함께 제공된 버전)은 형식을 처리할 수 없습니다.
    BUILDAH_FORMAT: docker
    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/test"
  before_script:
    # 레지스트리에 인증하기 위해
    # [미리 정의된 CI/CD 변수](../variables/_index.md#predefined-cicd-variables)에서
    # GitLab 컨테이너 레지스트리 자격 증명을 가져옵니다.
    - echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
  script:
    - buildah images
    - buildah build -t $FQ_IMAGE_NAME
    - buildah images
    - buildah push $FQ_IMAGE_NAME

OpenShift 클러스터에 배포된 GitLab Runner Operator를 사용하는 경우, rootless 컨테이너에서 Buildah를 사용하여 이미지를 빌드하는 튜토리얼을 참조하세요.

GitLab 컨테이너 레지스트리 사용#

Docker 이미지를 빌드한 후에는 GitLab 컨테이너 레지스트리에 푸시할 수 있습니다.

트러블슈팅#

open //./pipe/docker_engine: The system cannot find the file specified#

PowerShell 스크립트에서 마운트된 Docker 파이프에 접근하기 위해 docker 명령을 실행할 때 다음 오류가 발생할 수 있습니다:

PS C:\> docker version
Client:
 Version:           25.0.5
 API version:       1.44
 Go version:        go1.21.8
 Git commit:        5dc9bcc
 Built:             Tue Mar 19 15:06:12 2024
 OS/Arch:           windows/amd64
 Context:           default
error during connect: this error may indicate that the docker daemon is not running: Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.44/version": open //./pipe/docker_engine: The system cannot find the file specified.

오류는 Docker Engine이 Windows EKS 노드에서 실행되지 않고 있으며 Windows 기반 Executor 컨테이너에서 Docker 파이프 바인딩을 사용할 수 없음을 나타냅니다.

문제를 해결하려면 Kubernetes executor와 Docker 파이프 바인딩 사용에 설명된 해결 방법을 사용하세요.

Docker를 사용하여 Docker 이미지 빌드

Tier: Free, Premium, Ultimate
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
원문 보기
요약

GitLab CI/CD와 Docker를 함께 사용하여 Docker 이미지를 생성할 수 있습니다. CI/CD job에서 Docker 명령을 실행하려면 docker 명령을 지원하도록 GitLab Runner를 구성해야 합니다.

GitLab CI/CD와 Docker를 함께 사용하여 Docker 이미지를 생성할 수 있습니다. 예를 들어 애플리케이션의 Docker 이미지를 생성하고, 테스트하고, 컨테이너 레지스트리에 푸시할 수 있습니다.

CI/CD job에서 Docker 명령을 실행하려면 docker 명령을 지원하도록 GitLab Runner를 구성해야 합니다. 이 방법은 privileged 모드가 필요합니다.

러너에서 privileged 모드를 활성화하지 않고 Docker 이미지를 빌드하려면 Docker 대안을 사용할 수 있습니다.

CI/CD job에서 Docker 명령 활성화#

CI/CD job에 Docker 명령을 활성화하려면 다음을 사용할 수 있습니다:

shell executor 사용#

CI/CD job에 Docker 명령을 포함하려면, shell executor를 사용하도록 러너를 구성할 수 있습니다. 이 구성에서 gitlab-runner 사용자가 Docker 명령을 실행하지만, 그러기 위한 권한이 필요합니다.

  1. GitLab Runner를 설치합니다.

  2. 러너를 등록합니다. shell executor를 선택합니다. 예:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor shell \
      --description "My Runner"
    
  3. GitLab Runner가 설치된 서버에 Docker Engine을 설치합니다. 지원 플랫폼 목록을 확인하세요.

  4. gitlab-runner 사용자를 docker 그룹에 추가합니다:

    sudo usermod -aG docker gitlab-runner
    
  5. gitlab-runner가 Docker에 접근할 수 있는지 확인합니다:

    sudo -u gitlab-runner -H docker info
    
  6. GitLab에서 Docker가 작동하는지 확인하기 위해 .gitlab-ci.ymldocker info를 추가합니다:

    default:
      before_script:
        - docker info
    
    build_image:
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

이제 docker 명령을 사용할 수 있습니다(필요한 경우 Docker Compose도 설치 가능).

gitlab-runnerdocker 그룹에 추가하면 gitlab-runner에게 실질적으로 전체 root 권한을 부여하게 됩니다. 자세한 내용은 docker 그룹의 보안을 참조하세요.

Docker-in-Docker 사용#

"Docker-in-Docker" (dind)의 의미:

Docker 이미지에는 모든 docker 도구가 포함되어 있으며 privileged 모드에서 이미지 컨텍스트로 job 스크립트를 실행할 수 있습니다.

TLS가 활성화된 Docker-in-Docker를 사용해야 하며, GitLab.com 인스턴스 러너에서 지원됩니다.

항상 docker:24.0.5와 같이 이미지의 특정 버전을 지정해야 합니다. docker:latest와 같은 태그를 사용하면 어떤 버전이 사용되는지 제어할 수 없습니다. 이는 새 버전이 릴리스될 때 호환성 문제를 일으킬 수 있습니다.

Docker executor와 Docker-in-Docker 사용#

Docker executor를 사용하여 Docker 컨테이너에서 job을 실행할 수 있습니다.

Docker executor에서 TLS 활성화된 Docker-in-Docker#

Docker 데몬은 TLS를 통한 연결을 지원합니다. TLS는 Docker 19.03.12 이상에서 기본값입니다.

Warning

이 작업은 --docker-privileged를 활성화하여 컨테이너의 보안 메커니즘을 실질적으로 비활성화하고 호스트를 권한 상승에 노출시킵니다. 이 작업은 컨테이너 탈출을 유발할 수 있습니다. 자세한 내용은 런타임 권한 및 Linux 기능을 참조하세요.

TLS가 활성화된 Docker-in-Docker를 사용하려면:

  1. GitLab Runner를 설치합니다.

  2. 커맨드 라인에서 GitLab Runner를 등록합니다. dockerprivileged 모드를 사용합니다:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --tag-list "tls-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-privileged \
      --docker-volumes "/certs/client"
    
    • 이 명령은 docker:24.0.5-cli 이미지를 사용하는 새 러너를 등록합니다(job 레벨에서 지정하지 않은 경우). 빌드 및 서비스 컨테이너를 시작하기 위해 privileged 모드를 사용합니다. Docker-in-Docker를 사용하려면 Docker 컨테이너에서 항상 privileged = true를 사용해야 합니다.
    • 이 명령은 서비스 및 빌드 컨테이너에 대해 /certs/client를 마운트합니다. 이는 Docker 클라이언트가 해당 디렉터리의 인증서를 사용하는 데 필요합니다. 자세한 내용은 Docker 이미지 문서를 참조하세요.

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = true
        disable_cache = false
        volumes = ["/certs/client", "/cache"]
    
  3. 이제 job 스크립트에서 docker를 사용할 수 있습니다. docker:24.0.5-dind 서비스를 포함해야 합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다. Docker 19.03은
      # https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03/docker-entrypoint.sh#L23-L29에서
      # DOCKER_HOST를 설정하여 이를 자동으로 수행합니다
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services에서 설명합니다.
      #
      # Docker에 인증서를 생성할 위치를 지정합니다. Docker는
      # 부팅 시 자동으로 생성하고 config.toml의 볼륨 마운트 덕분에
      # 서비스와 job 컨테이너 간에 공유할 `/certs/client`를 생성합니다
      DOCKER_TLS_CERTDIR: "/certs"
    
    build:
      stage: build
      tags:
        - tls-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
Docker-in-Docker와 빌드 컨테이너 간 공유 볼륨의 Unix 소켓 사용#

Docker executor에서 TLS 활성화된 Docker-in-Docker 방식의 volumes = ["/certs/client", "/cache"]에 정의된 디렉터리는 빌드 간에 지속됩니다. Docker executor 러너를 사용하는 여러 CI/CD job에서 Docker-in-Docker 서비스가 활성화된 경우, 각 job은 디렉터리 경로에 씁니다. 이 방식은 충돌을 일으킬 수 있습니다.

이 충돌을 해결하려면 Docker-in-Docker 서비스와 빌드 컨테이너 간에 공유된 볼륨의 Unix 소켓을 사용합니다. 이 방식은 성능을 개선하고 서비스와 클라이언트 간의 보안 연결을 설정합니다.

다음은 빌드와 서비스 컨테이너 간에 공유된 임시 볼륨이 있는 config.toml 샘플입니다:

[[runners]]
  url = "https://gitlab.com/"
  token = TOKEN
  executor = "docker"
  [runners.docker]
    image = "docker:24.0.5-cli"
    privileged = true
    volumes = ["/runner/services/docker"] # 빌드와 서비스 컨테이너 간에 공유된 임시 볼륨.

Docker-in-Docker 서비스가 docker.sock을 생성합니다. Docker 클라이언트는 Docker Unix 소켓 볼륨을 통해 docker.sock에 연결됩니다.

job:
  variables:
    # 이 변수는 DinD 서비스와 Docker 클라이언트 모두 공유합니다.
    # 서비스의 경우, DinD가 여기에 `docker.sock`을 생성하도록 지시합니다.
    # 클라이언트의 경우, Docker 클라이언트가 연결할 Docker Unix 소켓을 알려줍니다.
    DOCKER_HOST: "unix:///runner/services/docker/docker.sock"
  services:
    - docker:24.0.5-dind
  image: docker:24.0.5-cli
  script:
    - docker version
Docker executor에서 TLS 비활성화된 Docker-in-Docker#

때로는 TLS를 비활성화할 타당한 이유가 있습니다. 예를 들어, 사용 중인 GitLab Runner 구성을 제어할 수 없는 경우입니다.

  1. 커맨드 라인에서 GitLab Runner를 등록합니다. dockerprivileged 모드를 사용합니다:

    sudo gitlab-runner register -n \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor docker \
      --description "My Docker Runner" \
      --tag-list "no-tls-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-privileged
    

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = true
        disable_cache = false
        volumes = ["/cache"]
    
  2. job 스크립트에 docker:24.0.5-dind 서비스를 포함합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다.
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services 참조
      #
      DOCKER_HOST: tcp://docker:2375
      #
      # Docker가 TLS 없이 시작하도록 지시합니다.
      DOCKER_TLS_CERTDIR: ""
    
    build:
      stage: build
      tags:
        - no-tls-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
Docker executor에서 프록시 활성화된 Docker-in-Docker#

docker push 명령을 사용하려면 프록시 설정을 구성해야 할 수 있습니다.

자세한 내용은 dind 서비스 사용 시 프록시 설정을 참조하세요.

Kubernetes executor와 Docker-in-Docker 사용#

Kubernetes executor를 사용하여 Docker 컨테이너에서 job을 실행할 수 있습니다.

Kubernetes에서 TLS 활성화된 Docker-in-Docker#

Kubernetes에서 TLS 활성화된 Docker-in-Docker를 사용하려면:

  1. Helm 차트를 사용하여 values.yml 파일을 업데이트하여 볼륨 마운트를 지정합니다.

    runners:
      tags: "tls-dind-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = true
          [[runners.kubernetes.volumes.empty_dir]]
            name = "docker-certs"
            mount_path = "/certs/client"
            medium = "Memory"
    
  2. job에 docker:24.0.5-dind 서비스를 포함합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - name: docker:24.0.5-dind
          variables:
            HEALTHCHECK_TCP_PORT: "2376"
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다.
      DOCKER_HOST: tcp://docker:2376
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services 참조
      #
      # Docker에 인증서를 생성할 위치를 지정합니다. Docker는
      # 부팅 시 자동으로 생성하고 config.toml의 볼륨 마운트 덕분에
      # 서비스와 job 컨테이너 간에 공유할 `/certs/client`를 생성합니다
      DOCKER_TLS_CERTDIR: "/certs"
      # 이것들은 보통 entrypoint에서 지정되지만, Kubernetes executor는
      # entrypoint를 실행하지 않습니다
      # https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4125
      DOCKER_TLS_VERIFY: 1
      DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
    
    build:
      stage: build
      tags:
        - tls-dind-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
Kubernetes에서 TLS 비활성화된 Docker-in-Docker#

Kubernetes에서 TLS 비활성화된 Docker-in-Docker를 사용하려면, 이전 예시를 다음과 같이 수정해야 합니다:

  • values.yml 파일에서 [[runners.kubernetes.volumes.empty_dir]] 섹션을 제거합니다.
  • DOCKER_HOST: tcp://docker:2375로 포트를 2376에서 2375로 변경합니다.
  • DOCKER_TLS_CERTDIR: ""로 TLS 비활성화하여 Docker를 시작하도록 지시합니다.

예:

  1. Helm 차트를 사용하여 values.yml 파일을 업데이트합니다:

    runners:
      tags: "no-tls-dind-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = true
    
  2. 이제 job 스크립트에서 docker를 사용할 수 있습니다. docker:24.0.5-dind 서비스를 포함해야 합니다:

    default:
      image: docker:24.0.5-cli
      services:
        - name: docker:24.0.5-dind
          variables:
            HEALTHCHECK_TCP_PORT: "2375"
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용할 때, Docker가 서비스 내부에서 시작된
      # 데몬과 통신하도록 지시해야 합니다. 데몬은 기본
      # /var/run/docker.sock 소켓 대신 네트워크 연결로
      # 사용 가능합니다.
      DOCKER_HOST: tcp://docker:2375
      #
      # 'docker' 호스트명은 서비스 컨테이너의 별칭입니다.
      # https://docs.gitlab.com/ci/services/#accessing-the-services 참조
      #
      # Docker가 TLS 없이 시작하도록 지시합니다.
      DOCKER_TLS_CERTDIR: ""
    build:
      stage: build
      tags:
        - no-tls-dind-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Docker-in-Docker의 알려진 문제#

Docker-in-Docker는 권장 구성이지만 다음 문제에 유의해야 합니다:

  • docker-compose 명령: 이 구성에서는 기본적으로 이 명령을 사용할 수 없습니다. job 스크립트에서 docker-compose를 사용하려면 Docker Compose 설치 지침을 따르세요.

  • 캐시: 각 job은 새로운 환경에서 실행됩니다. 모든 빌드가 자체 Docker 엔진 인스턴스를 갖기 때문에 동시 job은 충돌을 일으키지 않습니다. 그러나 레이어 캐싱이 없기 때문에 job이 더 느릴 수 있습니다. Docker 레이어 캐싱을 참조하세요.

  • 스토리지 드라이버: 기본적으로 이전 버전의 Docker는 각 job에 대해 파일 시스템을 복사하는 vfs 스토리지 드라이버를 사용합니다. Docker 17.09 이상은 권장 스토리지 드라이버인 --storage-driver overlay2를 사용합니다. 자세한 내용은 OverlayFS 드라이버 사용을 참조하세요.

  • 루트 파일 시스템: docker:24.0.5-dind 컨테이너와 러너 컨테이너가 루트 파일 시스템을 공유하지 않으므로, job의 작업 디렉터리를 자식 컨테이너의 마운트 포인트로 사용할 수 있습니다. 예를 들어, 자식 컨테이너와 공유하려는 파일이 있는 경우 /builds/$CI_PROJECT_PATH 아래에 하위 디렉터리를 생성하여 마운트 포인트로 사용할 수 있습니다. 자세한 내용은 이슈 #41227을 참조하세요.

    variables:
      MOUNT_POINT: /builds/$CI_PROJECT_PATH/mnt
    script:
      - mkdir -p "$MOUNT_POINT"
      - docker run -v "$MOUNT_POINT:/mnt" my-docker-image
    

Docker 소켓 바인딩 사용#

CI/CD job에서 Docker 명령을 사용하려면 /var/run/docker.sock을 빌드 컨테이너에 바인드 마운트할 수 있습니다. 그러면 Docker를 이미지 컨텍스트에서 사용할 수 있습니다.

Docker 소켓을 바인드하면 docker:24.0.5-dind를 서비스로 사용할 수 없습니다. 볼륨 바인딩도 서비스에 영향을 미쳐 호환되지 않습니다.

Docker executor와 Docker 소켓 바인딩 사용#

Docker executor로 Docker 소켓을 마운트하려면 "/var/run/docker.sock:/var/run/docker.sock"[runners.docker] 섹션의 볼륨에 추가합니다.

  1. 러너 등록 시 /var/run/docker.sock을 마운트하려면 다음 옵션을 포함합니다:

    sudo gitlab-runner register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor "docker" \
      --description "docker-runner" \
      --tag-list "socket-binding-docker-runner" \
      --docker-image "docker:24.0.5-cli" \
      --docker-volumes "/var/run/docker.sock:/var/run/docker.sock"
    

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = RUNNER_TOKEN
      executor = "docker"
      [runners.docker]
        tls_verify = false
        image = "docker:24.0.5-cli"
        privileged = false
        disable_cache = false
        volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
      [runners.cache]
        Insecure = false
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:24.0.5-cli
      before_script:
        - docker info
    
    build:
      stage: build
      tags:
        - socket-binding-docker-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Kubernetes executor와 Docker 소켓 바인딩 사용#

Kubernetes executor로 Docker 소켓을 마운트하려면 "/var/run/docker.sock"[[runners.kubernetes.volumes.host_path]] 섹션의 볼륨에 추가합니다.

  1. 볼륨 마운트를 지정하려면 Helm 차트를 사용하여 values.yml 파일을 업데이트합니다.

    runners:
      tags: "socket-binding-kubernetes-runner"
      config: |
        [[runners]]
          [runners.kubernetes]
            image = "ubuntu:20.04"
            privileged = false
          [runners.kubernetes]
            [[runners.kubernetes.volumes.host_path]]
              host_path = '/var/run/docker.sock'
              mount_path = '/var/run/docker.sock'
              name = 'docker-sock'
              read_only = true
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:24.0.5-cli
      before_script:
        - docker info
    build:
      stage: build
      tags:
        - socket-binding-kubernetes-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Docker 소켓 바인딩의 알려진 문제#

Docker 소켓 바인딩을 사용하면 Docker를 privileged 모드로 실행하는 것을 방지할 수 있습니다. 그러나 이 방법의 영향은 다음과 같습니다:

  • Docker 데몬을 공유하면 실질적으로 컨테이너의 보안 메커니즘을 비활성화하고 호스트를 권한 상승에 노출시킵니다. 이는 컨테이너 탈출을 일으킬 수 있습니다. 예를 들어, 프로젝트에서 docker rm -f $(docker ps -a -q)를 실행하면 GitLab Runner 컨테이너가 제거됩니다.

  • 동시 job이 작동하지 않을 수 있습니다. 테스트에서 특정 이름의 컨테이너를 생성하면 서로 충돌할 수 있습니다.

  • Docker 명령으로 생성된 컨테이너는 러너의 자식이 아닌 형제입니다. 이는 워크플로에 복잡성을 더할 수 있습니다.

  • 소스 리포지터리에서 컨테이너로 파일 및 디렉터리를 공유하는 것이 예상대로 작동하지 않을 수 있습니다. 볼륨 마운팅은 빌드 컨테이너가 아닌 호스트 머신의 컨텍스트에서 수행됩니다. 예:

    docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_app_tests
    

Docker-in-Docker executor를 사용할 때처럼 docker:24.0.5-dind 서비스를 포함할 필요가 없습니다:

default:
  image: docker:24.0.5-cli
  before_script:
    - docker info

build:
  stage: build
  script:
    - docker build -t my-docker-image .
    - docker run my-docker-image /script/to/run/tests

CodeClimate를 사용한 코드 품질 스캐닝과 같은 복잡한 Docker-in-Docker 설정의 경우, 적절한 실행을 위해 호스트와 컨테이너 경로를 일치시켜야 합니다. 자세한 내용은 CodeClimate 기반 스캐닝에 개인 러너 사용을 참조하세요.

Docker 파이프 바인딩 사용#

Windows 컨테이너는 Docker-in-Docker 방식을 지원하지 않으므로, 컨테이너 내에서 중첩된 Docker Engine을 실행할 수 없습니다. Windows 컨테이너 내에서 Docker 이미지를 빌드하거나 관리하려면 Docker 파이프 바인딩(Docker-outside-of-Docker 또는 DooD라고도 함)을 사용합니다.

Warning

Docker 파이프 바인딩은 보안적 영향이 있습니다. \\\\.\\pipe\\docker_engine을 바인드 마운트하면 컨테이너가 호스트의 Docker 데몬에 대한 전체 관리자 액세스 권한을 갖게 됩니다. 컨테이너 내의 프로세스는 다른 컨테이너를 시작하거나 중지하고, 이미지를 관리하며, 호스트 시스템에서 권한을 상승시킬 수 있습니다.

Docker 파이프 바인딩을 사용하려면 호스트 Windows Server 운영 체제에 Docker Engine을 설치하고 실행해야 합니다. 자세한 내용은 Windows Server에 Docker Community Edition (CE) 설치를 참조하세요.

Windows 기반 컨테이너 CI/CD job에서 Docker 명령을 사용하려면 \\\\.\\pipe\\docker_engine을 실행된 executor 컨테이너에 바인드 마운트할 수 있습니다. 그러면 Docker를 이미지 컨텍스트에서 사용할 수 있습니다.

Windows에서의 Docker 파이프 바인딩Linux에서의 Docker 소켓 바인딩과 유사하며 알려진 문제Docker 소켓 바인딩의 알려진 문제와 유사합니다.

Docker 파이프 바인딩 사용의 필수 전제 조건은 호스트 Windows Server 운영 체제에 Docker Engine이 설치되어 실행 중인 것입니다.

Docker executor와 Docker 파이프 바인딩 사용#

Docker executor를 사용하여 Windows 기반 컨테이너에서 job을 실행할 수 있습니다.

Docker executor로 Docker 파이프를 마운트하려면 "\\\\.\\pipe\\docker_engine:\\\\.\\pipe\\docker_engine"[runners.docker] 섹션의 볼륨에 추가합니다.

  1. 러너 등록 시 \\\\.\\pipe\\docker_engine을 마운트하려면 다음 옵션을 포함합니다:

    .\gitlab-runner.exe register \
      --non-interactive \
      --url "https://gitlab.com/" \
      --registration-token REGISTRATION_TOKEN \
      --executor "docker-windows" \
      --description "docker-windows-runner"
      --tag-list "docker-windows-runner" \
      --docker-image "docker:25-windowsservercore-ltsc2022" \
      --docker-volumes "\\\\.\\pipe\\docker_engine:\\\\.\\pipe\\docker_engine"
    

    이전 명령은 다음 예와 유사한 config.toml 항목을 생성합니다:

    [[runners]]
      url = "https://gitlab.com/"
      token = RUNNER_TOKEN
      executor = "docker-windows"
      [runners.docker]
        tls_verify = false
        image = "docker:25-windowsservercore-ltsc2022"
        privileged = false
        disable_cache = false
        volumes = ["\\\\.\\pipe\\docker_engine:\\\\.\\pipe\\docker_engine"]
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:25-windowsservercore-ltsc2022
      before_script:
        - docker version
        - docker info
    
    build:
      stage: build
      tags:
        - docker-windows-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

Kubernetes executor와 Docker 파이프 바인딩 사용#

Kubernetes executor를 사용하여 Windows 기반 컨테이너에서 job을 실행할 수 있습니다.

Windows 기반 컨테이너에 Kubernetes executor를 사용하려면 Kubernetes 클러스터에 Windows 노드를 포함해야 합니다. 자세한 내용은 Kubernetes의 Windows 컨테이너를 참조하세요.

Linux 환경에서 실행 중이지만 Windows 노드를 대상으로 하는 러너를 사용할 수 있습니다.

Kubernetes executor로 Docker 파이프를 마운트하려면 "\\\\.\\pipe\\docker_engine"[[runners.kubernetes.volumes.host_path]] 섹션의 볼륨에 추가합니다.

  1. 볼륨 마운트를 지정하려면 Helm 차트를 사용하여 values.yml 파일을 업데이트합니다.

    runners:
      tags: "kubernetes-windows-runner"
      config: |
        [[runners]]
          executor = "kubernetes"
    
          # FF_USE_POWERSHELL_PATH_RESOLVER 기능 플래그는 러너가 Linux 환경에서
          # 실행 중이지만 Windows 노드를 대상으로 할 때
          # PowerShell이 Windows 경로를 올바르게 확인하도록 활성화해야 합니다.
          [runners.feature_flags]
            FF_USE_POWERSHELL_PATH_RESOLVER = true
    
          [runners.kubernetes]
            [[runners.kubernetes.volumes.host_path]]
              host_path = '\\\\.\\pipe\\docker_engine'
              mount_path = '\\\\.\\pipe\\docker_engine'
              name = 'docker-pipe'
              read_only = true
    
            [runners.kubernetes.node_selector]
              "kubernetes.io/arch" = "amd64"
              "kubernetes.io/os" = "windows"
              "node.kubernetes.io/windows-build" = "10.0.20348"
    
  2. job 스크립트에서 Docker를 사용합니다:

    default:
      image: docker:25-windowsservercore-ltsc2022
      before_script:
        - docker version
        - docker info
    
    build:
      stage: build
      tags:
        - kubernetes-windows-runner
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
AWS EKS Kubernetes 클러스터의 알려진 문제#

dockerd에서 containerd로 마이그레이션할 때, AWS EKS 부트스트래핑 스크립트 Start-EKSBootstrap.ps1이 Docker 서비스를 중지하고 비활성화합니다. 이 문제를 해결하려면 Windows Server에 Docker Community Edition (CE) 설치 후 이 스크립트로 Docker 서비스 이름을 바꿉니다:

Write-Output "Rename the just installed Docker Engine Service from docker to dockerd"
Write-Output "because the Start-EKSBootstrap.ps1 stops and disables the docker Service as part of migration from dockerd to containerd"
Stop-Service -Name docker
dockerd --register-service --service-name dockerd
Start-Service -Name dockerd
Write-Output "Ready to do Docker pipe binding on Windows EKS Node! :-)"

Docker 파이프 바인딩의 알려진 문제#

Docker 파이프 바인딩은 Docker 소켓 바인딩의 알려진 문제와 동일한 보안 및 격리 문제를 가지고 있습니다.

docker:dind 서비스의 레지스트리 미러 활성화#

Docker 데몬이 서비스 컨테이너 내에서 시작될 때 기본 구성을 사용합니다. 성능 향상 및 Docker Hub 속도 제한 초과를 방지하기 위해 레지스트리 미러를 구성할 수 있습니다.

.gitlab-ci.yml 파일의 서비스#

dind 서비스에 추가 CLI 플래그를 추가하여 레지스트리 미러를 설정할 수 있습니다:

services:
  - name: docker:24.0.5-dind
    command: ["--registry-mirror", "https://registry-mirror.example.com"]  # 사용할 레지스트리 미러를 지정합니다

GitLab Runner 구성 파일의 서비스#

GitLab Runner 관리자라면 command를 지정하여 Docker 데몬의 레지스트리 미러를 구성할 수 있습니다. dind 서비스는 Docker 또는 Kubernetes executor에 대해 정의되어야 합니다.

Docker:

[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    ...
    privileged = true
    [[runners.docker.services]]
      name = "docker:24.0.5-dind"
      command = ["--registry-mirror", "https://registry-mirror.example.com"]

Kubernetes:

[[runners]]
  ...
  name = "kubernetes"
  [runners.kubernetes]
    ...
    privileged = true
    [[runners.kubernetes.services]]
      name = "docker:24.0.5-dind"
      command = ["--registry-mirror", "https://registry-mirror.example.com"]

GitLab Runner 구성 파일의 Docker executor#

GitLab Runner 관리자라면 모든 dind 서비스에 미러를 사용할 수 있습니다. 볼륨 마운트를 지정하도록 구성을 업데이트합니다.

예를 들어, 다음 내용이 포함된 /opt/docker/daemon.json 파일이 있는 경우:

{
  "registry-mirrors": [
    "https://registry-mirror.example.com"
  ]
}

config.toml 파일을 업데이트하여 파일을 /etc/docker/daemon.json에 마운트합니다. 이렇게 하면 GitLab Runner가 생성하는 모든 컨테이너에 파일이 마운트됩니다. dind 서비스가 구성을 감지합니다.

[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    image = "alpine:3.12"
    privileged = true
    volumes = ["/opt/docker/daemon.json:/etc/docker/daemon.json:ro"]

GitLab Runner 구성 파일의 Kubernetes executor#

GitLab Runner 관리자라면 모든 dind 서비스에 미러를 사용할 수 있습니다. ConfigMap 볼륨 마운트를 지정하도록 구성을 업데이트합니다.

예를 들어, 다음 내용이 포함된 /tmp/daemon.json 파일이 있는 경우:

{
  "registry-mirrors": [
    "https://registry-mirror.example.com"
  ]
}

이 파일의 내용으로 ConfigMap을 생성합니다. 다음과 같은 명령으로 할 수 있습니다:

kubectl create configmap docker-daemon --namespace gitlab-runner --from-file /tmp/daemon.json
Note

GitLab Runner의 Kubernetes executor가 job 파드를 생성하는 데 사용하는 네임스페이스를 사용해야 합니다.

ConfigMap이 생성된 후 config.toml 파일을 업데이트하여 파일을 /etc/docker/daemon.json에 마운트할 수 있습니다. 이 업데이트는 GitLab Runner가 생성하는 모든 컨테이너에 파일을 마운트합니다. dind 서비스가 이 구성을 감지합니다.

[[runners]]
  ...
  executor = "kubernetes"
  [runners.kubernetes]
    image = "alpine:3.12"
    privileged = true
    [[runners.kubernetes.volumes.config_map]]
      name = "docker-daemon"
      mount_path = "/etc/docker/daemon.json"
      sub_path = "daemon.json"

Docker-in-Docker에서 레지스트리 인증#

Docker-in-Docker를 사용할 때, 표준 인증 방법은 작동하지 않습니다. 서비스와 함께 새로운 Docker 데몬이 시작되기 때문입니다. 레지스트리 인증을 참조하세요.

Docker 레이어 캐싱#

Docker 레이어를 캐시하여 빌드 속도를 높일 수 있습니다. 자세한 내용은 Docker-in-Docker 빌드에서 Docker 레이어 캐싱을 참조하세요.

OverlayFS 드라이버 사용#

Note

GitLab.com의 인스턴스 러너는 기본적으로 overlay2 드라이버를 사용합니다.

기본적으로 docker:dind를 사용할 때 Docker는 실행할 때마다 파일 시스템을 복사하는 vfs 스토리지 드라이버를 사용합니다. 예를 들어 overlay2와 같은 다른 드라이버를 사용하여 이 디스크 집약적 작업을 방지할 수 있습니다.

요구 사항#

  1. 최근 커널이 사용되는지 확인합니다. 가능하면 >= 4.2를 권장합니다.

  2. overlay 모듈이 로드되었는지 확인합니다:

    sudo lsmod | grep overlay
    

    결과가 없으면 모듈이 로드되지 않은 것입니다. 모듈을 로드하려면 다음을 사용합니다:

    sudo modprobe overlay
    

    모듈이 로드된 경우 재부팅 시 모듈이 로드되도록 해야 합니다. Ubuntu 시스템에서는 /etc/modules에 다음 줄을 추가하여 이를 수행합니다:

    overlay
    

프로젝트별 OverlayFS 드라이버 사용#

.gitlab-ci.yml에서 DOCKER_DRIVER CI/CD 변수를 사용하여 각 프로젝트별로 드라이버를 활성화할 수 있습니다:

variables:
  DOCKER_DRIVER: overlay2

모든 프로젝트에 OverlayFS 드라이버 사용#

자체 러너를 사용하는 경우, config.toml 파일의 [[runners]] 섹션에서 DOCKER_DRIVER 환경 변수를 설정하여 모든 프로젝트에 대해 드라이버를 활성화할 수 있습니다:

environment = ["DOCKER_DRIVER=overlay2"]

여러 러너를 실행 중인 경우 모든 구성 파일을 수정해야 합니다.

러너 구성OverlayFS 스토리지 드라이버 사용에 대해 자세히 알아보세요.

Docker 대안#

러너에서 privileged 모드를 활성화하지 않고 컨테이너 이미지를 빌드할 수 있습니다:

  • BuildKit: Docker 데몬 의존성을 제거하는 rootless BuildKit 옵션 포함.
  • Buildah: Docker 데몬 없이 OCI 호환 이미지 빌드.

Buildah 예시#

GitLab CI/CD와 함께 Buildah를 사용하려면 다음 executor 중 하나를 가진 러너가 필요합니다:

이 예시에서 Buildah를 사용하여 다음을 수행합니다:

  1. Docker 이미지를 빌드합니다.
  2. GitLab 컨테이너 레지스트리에 푸시합니다.

마지막 단계에서 Buildah는 프로젝트 루트 디렉터리 아래의 Dockerfile을 사용하여 Docker 이미지를 빌드합니다. 마지막으로 이미지를 프로젝트의 컨테이너 레지스트리에 푸시합니다:

build:
  stage: build
  image: quay.io/buildah/stable
  variables:
    # Buildah와 함께 vfs를 사용합니다. Docker는 기본적으로 overlayfs를 제공하지만, Buildah는
    # overlayfs 파일 시스템 위에 overlayfs를 스택할 수 없습니다.
    STORAGE_DRIVER: vfs
    # 표준 OCI 형식이 아닌 docker 형식으로 모든 이미지 메타데이터를 작성합니다.
    # 최신 버전의 docker는 OCI 형식을 처리할 수 있지만, 오래된 버전(예:
    # Fedora 30과 함께 제공된 버전)은 형식을 처리할 수 없습니다.
    BUILDAH_FORMAT: docker
    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/test"
  before_script:
    # 레지스트리에 인증하기 위해
    # [미리 정의된 CI/CD 변수](../variables/_index.md#predefined-cicd-variables)에서
    # GitLab 컨테이너 레지스트리 자격 증명을 가져옵니다.
    - echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
  script:
    - buildah images
    - buildah build -t $FQ_IMAGE_NAME
    - buildah images
    - buildah push $FQ_IMAGE_NAME

OpenShift 클러스터에 배포된 GitLab Runner Operator를 사용하는 경우, rootless 컨테이너에서 Buildah를 사용하여 이미지를 빌드하는 튜토리얼을 참조하세요.

GitLab 컨테이너 레지스트리 사용#

Docker 이미지를 빌드한 후에는 GitLab 컨테이너 레지스트리에 푸시할 수 있습니다.

트러블슈팅#

open //./pipe/docker_engine: The system cannot find the file specified#

PowerShell 스크립트에서 마운트된 Docker 파이프에 접근하기 위해 docker 명령을 실행할 때 다음 오류가 발생할 수 있습니다:

PS C:\> docker version
Client:
 Version:           25.0.5
 API version:       1.44
 Go version:        go1.21.8
 Git commit:        5dc9bcc
 Built:             Tue Mar 19 15:06:12 2024
 OS/Arch:           windows/amd64
 Context:           default
error during connect: this error may indicate that the docker daemon is not running: Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.44/version": open //./pipe/docker_engine: The system cannot find the file specified.

오류는 Docker Engine이 Windows EKS 노드에서 실행되지 않고 있으며 Windows 기반 Executor 컨테이너에서 Docker 파이프 바인딩을 사용할 수 없음을 나타냅니다.

문제를 해결하려면 Kubernetes executor와 Docker 파이프 바인딩 사용에 설명된 해결 방법을 사용하세요.