Docker 이미지 빌드에 Docker 사용하기

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

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

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

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

CI/CD 작업에서 Docker 명령 활성화하기

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

쉘 러너 사용

CI/CD 작업에서 Docker 명령을 사용하려면, 러너를 shell 실행기로 구성할 수 있습니다. 이 구성에서는 gitlab-runner 사용자가 Docker 명령을 실행할 수 있지만, 그에게는 그에게 그러한 권한이 있어야 합니다.

  1. GitLab Runner 설치.
  2. 러너 등록. shell 실행기를 선택하세요. 예시:

    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에서 .gitlab-ci.ymldocker info를 추가하여 Docker가 작동하는지 확인하세요:

    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에게 완전한 루트 권한을 부여하는 것입니다. 자세한 내용은 도커 그룹의 보안을 참조하세요.

Docker-in-Docker 사용

“Docker-in-Docker” (dind)란:

이 Docker 이미지에는 모든 docker 도구가 포함되어 있으며, 권한이 부여된 모드로 이미지 내에서 작업 스크립트를 실행할 수 있습니다.

_tls_를 활성화한 Docker-in-Docker를 사용해야 합니다. 이는 GitLab.com 인스턴스 러너에서 지원됩니다.

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

Docker 실행기와 tls 활성화된 Docker-in-Docker 사용

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

Docker 데몬은 TLS 연결을 지원합니다. TLS는 Docker 19.03.12 이상부터 기본값입니다.

경고: 이 작업은 실제로 --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" \
      --docker-image "docker:24.0.5" \
      --docker-privileged \
      --docker-volumes "/certs/client"
    
    • 이 명령은 docker:24.0.5 이미지를 사용하는 새 러너를 등록합니다 (작업 수준에서 지정하지 않은 경우). 빌드 및 서비스 컨테이너를 시작하려면 privileged 모드를 사용합니다. Docker-in-Docker를 사용하려면 항상 Docker 컨테이너에서 privileged = true를 사용해야 합니다.
    • 이 명령은 Docker 클라이언트가 해당 디렉토리의 인증서를 사용할 수 있도록 서비스 및 빌드 컨테이너에 /certs/client를 마운트합니다. 자세한 내용은 도커 이미지 설명서를 참조하세요.

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

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

    default:
      image: docker:24.0.5
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용하는 경우 Docker에 서비스 시작할 때 DOCKER_HOST를 사용하도록 Docker에 지시해야 합니다.
      # 기본 /var/run/docker.sock 소켓 대신 서비스 내에서 네트워크 연결을 통해 사용할 수 있습니다.
      # Docker 19.03은 이 작업을 자동으로 수행합니다
      # https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03/docker-entrypoint.sh#L23-L29
      #
      # 'docker' 호스트 이름은 https://docs.gitlab.com/ee/ci/services/#accessing-the-services에 설명된 대로 서비스 컨테이너의 별칭입니다.
      #
      # 인증서를 생성할 위치를 Docker에 지정합니다. Docker는 부팅시 자동으로 생성하고
      # 서비스 및 작업 컨테이너 사이에서 공유하기 위해 `/certs/client`를 만듭니다.
      # config.toml로부터 볼륨 마운트를 통해 Docker가 자동으로 이를 수행합니다
      DOCKER_TLS_CERTDIR: "/certs"
    
    build:
      stage: build
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    
Docker-in-Docker with TLS 비활성화된 Docker executor

가끔은 TLS를 비활성화할 합리적인 이유가 있습니다. 예를 들어 사용 중인 GitLab Runner 구성을 제어할 수 없는 경우입니다.

만약 러너의 config.toml이 다음과 유사하다고 가정해 봅시다:

[[runners]]
  url = "https://gitlab.com/"
  token = TOKEN
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "docker:24.0.5"
    privileged = true
    disable_cache = false
    volumes = ["/cache"]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

이제 작업 스크립트에서 docker를 사용할 수 있습니다. docker:24.0.5-dind 서비스를 포함해야 합니다:

default:
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  before_script:
    - docker info

variables:
  # dind 서비스를 사용할 때는 Docker에 서비스 내에서 시작된 데몬과 통신하도록 지시해야 합니다.
  # 기본 /var/run/docker.sock 소켓 대신 네트워크 연결을 통해 데몬에 액세스할 수 있습니다.
  #
  # 'docker' 호스트 이름은 https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services에서 설명된 서비스 컨테이너의 별칭입니다.
  #
  # Kubernetes executor 및 Kubernetes 1.6 이전을 사용하고 있다면 GitLab Runner 12.7 이전 버전을 사용하는 경우
  # 작업 컨테이너에 서비스를 연결하는 방법으로 인해 변수를 tcp://localhost:2375로 설정해야 합니다.
  # DOCKER_HOST: tcp://localhost:2375
  #
  DOCKER_HOST: tcp://docker:2375
  #
  # 이는 Docker에게 TLS를 통한 시작을하지 않도록 지시합니다.
  DOCKER_TLS_CERTDIR: ""

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

Docker-in-Docker와 Kubernetes executor 사용

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

TLS가 활성화된 Kubernetes에서 Docker-in-Docker 사용

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

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

    runners:
      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. 이제 작업 스크립트에서 docker를 사용할 수 있습니다. docker:24.0.5-dind 서비스를 포함해야 합니다:

    default:
       image: docker:24.0.5
       services:
         - docker:24.0.5-dind
       before_script:
         - docker info
    
       variables:
         # dind 서비스를 사용할 때는 Docker에 서비스 내에서 시작된 데몬과 통신하도록 지시해야 합니다.
         # 기본 /var/run/docker.sock 소켓 대신 네트워크 연결을 통해 데몬에 액세스할 수 있습니다.
         DOCKER_HOST: tcp://docker:2376
         #
         # 'docker' 호스트 이름은 https://docs.gitlab.com/ee/ci/services/#accessing-the-services에서 설명된 서비스 컨테이너의 별칭입니다.
         # Kubernetes executor 및 Kubernetes 1.6 이전을 사용하고 있다면 GitLab Runner 12.7 이전 버전을 사용하는 경우
         # 작업 컨테이너에 서비스를 연결하는 방법으로 인해 변수를 tcp://localhost:2376로 설정해야 합니다.
         # DOCKER_HOST: tcp://localhost:2376
         #
         # Docker에게 인증서를 생성할 위치를 지정합니다. Docker는 부팅시 자동으로 이를 생성하고
         # 볼륨 마운트로 인해 서비스와 작업 컨테이너 간에 `/certs/client`를 생성합니다.
         DOCKER_TLS_CERTDIR: "/certs"
         # 이들은 보통 엔트리포인트에 의해 지정되지만 Kubernetes executor는 엔트리포인트를 실행하지 않습니다.
         DOCKER_TLS_VERIFY: 1
         DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
    
       build:
         stage: build
         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]] 섹션을 제거합니다.
  • 포트를 2376에서 2375로 변경하고 DOCKER_HOST: tcp://docker:2375로 설정합니다.
  • TLS를 비활성화하도록 Docker에 지시하려면 DOCKER_TLS_CERTDIR: ""로 설정합니다.

예시:

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

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

    default:
      image: docker:24.0.5
      services:
        - docker:24.0.5-dind
      before_script:
        - docker info
    
    variables:
      # dind 서비스를 사용하는 경우 Docker에 서비스 내부에서 시작된 데몬과 통신하도록 지시해야 합니다.
      # 기본값인 /var/run/docker.sock 소켓 대신에 네트워크 연결을 사용할 수 있습니다.
      DOCKER_HOST: tcp://docker:2375
      #
      # 'docker' 호스트네임은
      # https://docs.gitlab.com/ee/ci/services/#accessing-the-services 에 설명된 서비스 컨테이너의 별칭입니다.
      # Kubernetes 실행기와 Kubernetes 1.6 이전을 사용하는 경우 GitLab Runner 12.7 이전을 사용하는 경우 변수는
      # 작업 컨테이너에 서비스를 연결하는 방식 때문에 tcp://localhost:2376로 설정해야 합니다.
      # DOCKER_HOST: tcp://localhost:2376
      #
      # Docker가 TLS를 시작하지 않도록 지시합니다.
      DOCKER_TLS_CERTDIR: ""
    build:
      stage: build
      script:
        - docker build -t my-docker-image .
        - docker run my-docker-image /script/to/run/tests
    

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

Docker-in-Docker는 권장 구성이지만 다음과 같은 문제점을 인지해야 합니다:

  • docker-compose 명령어: 이 구성에서는 기본적으로 이 명령어를 사용할 수 없습니다. 작업 스크립트에서 docker-compose를 사용하려면 Docker Compose 설치 지침을 따르세요.
  • 캐시: 각 작업은 새 환경에서 실행됩니다. 모든 빌드가 고유한 Docker 엔진 인스턴스를 받기 때문에 동시 작업은 충돌을 일으키지 않습니다. 그러나 레이어를 캐싱하지 않기 때문에 작업이 느릴 수 있습니다. Docker 레이어 캐싱을 참조하세요.
  • 스토리지 드라이버: 기본적으로 이전 버전의 Docker는 vfs 스토리지 드라이버를 사용하여 각 작업에 파일 시스템을 복사합니다. Docker 17.09 이상에서는 --storage-driver overlay2를 사용하여 권장되는 스토리지 드라이버를 사용합니다. 자세한 내용은 OverlayFS 드라이버 사용를 참조하세요.
  • 루트 파일 시스템: docker:24.0.5-dind 컨테이너와 러너 컨테이너는 루트 파일 시스템을 공유하지 않으므로 작업 디렉토리를 자식 컨테이너의 마운트 지점으로 사용할 수 있습니다. 예를 들어, 자식 컨테이너와 공유할 파일이 있다면, /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 소켓 바인딩으로 Docker 실행기 사용

CI/CD 작업에서 Docker 명령어를 사용하려면 /var/run/docker.sock을 컨테이너로 바인딩해야 합니다. 그러면 이미지의 컨텍스트에서 Docker를 사용할 수 있습니다.

Docker 소켓을 바인딩하면 GitLab Runner 11.11 이상을 사용하는 경우, docker:24.0.5-dind를 서비스로 더 이상 사용할 수 없습니다. 볼륨 바인딩은 서비스에도 영향을 미치므로 호환되지 않습니다.

Docker를 이미지 컨텍스트에서 사용하도록 하려면, Docker 실행기에 "/var/run/docker.sock:/var/run/docker.sock"Volumes in the [runners.docker] section에 추가하세요.

구성은 다음 예와 유사해야 합니다:

[[runners]]
  url = "https://gitlab.com/"
  token = RUNNER_TOKEN
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "docker:24.0.5"
    privileged = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
  [runners.cache]
    Insecure = false

Runner를 등록할 때 /var/run/docker.sock을 마운트하려면 다음 옵션을 포함하세요:

sudo gitlab-runner register -n \
  --url "https://gitlab.com/" \
  --registration-token REGISTRATION_TOKEN \
  --executor docker \
  --description "My Docker Runner" \
  --docker-image "docker:24.0.5" \
  --docker-volumes /var/run/docker.sock:/var/run/docker.sock

Code Quality를 사용하여 Code Climate을 통한 복잡한 Docker-in-Docker 설정을 하는 경우, 호스트와 컨테이너 경로를 일치시켜야 합니다. 자세한 내용은 Private Runner를 사용하여 코드 품질 성능 향상을 참조하세요.

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 관리자라면 Docker 데몬을 위해 레지스트리 미러를 구성하기 위해 command를 지정할 수 있습니다. 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 서비스에 대해 미러를 사용할 수 있습니다. 구성을 업데이트하여 볼륨 사용을 지정하세요.

다음과 같이 /tmp/daemon.json 파일이 있는 경우:

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

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

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

참고: GitLab Runner를 위해 사용하는 작업 파드를 생성하는 쿠버네티스 executor의 네임스페이스를 사용해야 합니다.

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 소켓 바인딩으로 알려진 문제점

Docker 소켓 바인딩을 사용하면 Docker를 특권 모드에서 실행하지 않을 수 있습니다. 그러나, 이 방법의 함의는 다음과 같습니다:

  • Docker 데몬을 공유함으로써 컨테이너의 모든 보안 메커니즘을 비활성화하고 호스트를 특권 상승에 노출시킵니다. 이는 컨테이너 탈출을 유발할 수 있습니다. 예를 들어, 프로젝트에서 docker rm -f $(docker ps -a -q)를 실행하면 GitLab Runner 컨테이너가 제거될 수 있습니다.
  • 병렬 작업이 작동하지 않을 수 있습니다. 테스트 중에 특정 이름을 가진 컨테이너를 생성하면 서로 충돌할 수 있습니다.
  • Docker 명령으로 생성된 모든 컨테이너는 Runner의 형제로 간주되며, Runner의 자식이 아닙니다. 이는 워크플로에 복잡성을 유발할 수 있습니다.
  • 소스 리포지토리에서 파일 및 디렉토리를 컨테이너로 공유하는 것이 예상대로 작동하지 않을 수 있습니다. 볼륨 마운팅은 빌드 컨테이너가 아니라 호스트 머신의 컨텍스트에서 수행됩니다. 예를 들어:

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

Docker-in-Docker 실행시 docker:24.0.5-dind 서비스를 포함할 필요가 없습니다.

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

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

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

Docker-in-Docker을 사용할 때 표준 인증 방법은 서비스와 함께 새로운 Docker 데몬이 시작되므로 작동하지 않습니다. 따라서 레지스트리로 인증해야 합니다.

Docker 레이어 캐싱을 사용하여 Docker-in-Docker 빌드 가속화

Docker-in-Docker 사용시 빌드를 생성할 때마다 Docker가 이미지의 모든 레이어를 다운로드합니다. Docker 레이어 캐싱을 사용하여 빌드를 가속화할 수 있습니다.

OverlayFS 드라이버 사용

참고: 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 대안

러너에서 특권 모드를 활성화하지 않고 Docker 이미지를 빌드하려면 다음 중 하나를 사용할 수 있습니다: - kaniko. - buildah.

Buildah 예시

GitLab CI/CD에서 Buildah를 사용하려면 다음 실행자 중 하나를 사용하는 러너가 필요합니다: - Kubernetes. - Docker. - Docker Machine.

이 예시에서 Buildah를 사용하여 다음을 수행합니다: 1. Docker 이미지를 빌드합니다. 1. 이를 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는 OCI 형식을 처리할 수 있지만, Fedora 30과 같은 이전 버전은 처리할 수 없습니다.
    BUILDAH_FORMAT: docker
    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/test"
  before_script:
    # GitLab 컨테이너 레지스트리 자격 증명은
    # [미리 정의된 CI/CD 변수](../variables/index.md#predefined-cicd-variables)
    #을 통해 레지스트리에 인증합니다.
    - 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를 사용하는 경우, 루트리스 컨테이너에서 이미지를 빌드하는 방법에 대한 튜토리얼을 확인해보세요.

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

도커 이미지를 빌드한 후, 해당 이미지를 GitLab 컨테이너 레지스트리에 푸시할 수 있습니다.

문제 해결

docker: Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?

이 오류는 Docker-in-Docker v19.03 이상을 사용할 때 일반적으로 발생합니다.

이 오류는 Docker가 TLS에서 자동으로 시작되기 때문에 발생합니다.

또한 이 오류는 Kubernetes 실행기에서도 발생할 수 있습니다. 해당 서비스가 완전히 시작되기 전에 Docker-in-Docker 서비스에 액세스하려고 시도하는 경우입니다. 보다 자세한 설명은 이슈 27215를 참조하세요.

Docker no such host 오류

다음과 같은 오류가 발생할 수 있습니다. docker: error during connect: Post https://docker:2376/v1.40/containers/create: dial tcp: lookup docker on x.x.x.x:53: no such host.

이 문제는 레지스트리 호스트명을 포함하는 서비스 이미지명이 포함될 때 발생할 수 있습니다. 예를 들어:

default:
  image: docker:24.0.5
  services:
    - registry.hub.docker.com/library/docker:24.0.5-dind

서비스의 호스트명은 전체 이미지명을 기반으로 파생됩니다. 하지만 더 짧은 서비스 호스트명인 docker가 예상됩니다. 서비스 이름 docker에 대한 명시적 별칭을 추가하여 서비스 해결 및 액세스를 허용하세요:

default:
  image: docker:24.0.5
  services:
    - name: registry.hub.docker.com/library/docker:24.0.5-dind
      alias: docker

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

docker 명령을 실행하여 dind 서비스에 액세스하려고 시도할 때 다음과 같은 오류가 발생할 수 있습니다.

$ docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

작업에 다음 환경 변수가 정의되어 있는지 확인하세요:

  • DOCKER_HOST
  • DOCKER_TLS_CERTDIR (선택 사항)
  • DOCKER_TLS_VERIFY (선택 사항)

또한 Docker 클라이언트를 제공하는 이미지를 업데이트할 수 있습니다. 예를 들어, docker/compose 이미지는 더 이상 사용되지 않습니다docker로 대체해야 합니다.

런너 이슈 30944에서 설명한대로, 이 오류는 작업이 이전에 사용되던 Docker --link 매개변수에서 파생된 환경 변수(예: DOCKER_PORT_2375_TCP)에 의존하고 있고:

  • CI/CD 이미지가 DOCKER_PORT_2375_TCP와 같은 레거시 변수에 의존하는 경우
  • 런너 기능 플래그 FF_NETWORK_PER_BUILDtrue로 설정되어 있는 경우
  • DOCKER_HOST가 명시적으로 설정되어 있지 않은 경우

작업이 이 오류로 실패할 수 있습니다.

오류: Error response from daemon: Get "https://registry-1.docker.io/v2/": unauthorized: incorrect username or password

이 오류는 폐기된 변수 CI_BUILD_TOKEN을 사용할 때 발생합니다. 사용자가 이러한 오류를 받지 않도록하려면 다음을 해야 합니다:

  • CI_JOB_TOKEN을 사용하세요.
  • gitlab-ci-token/CI_BUILD_TOKEN에서 $CI_REGISTRY_USER/$CI_REGISTRY_PASSWORD로 변경하세요.

오류: error during connect: Post "https://docker:2376/v1.24/auth": dial tcp: lookup docker on 127.0.0.11:53: no such host

이 오류는 dind 서비스가 시작하지 못했을 때 발생합니다. job log를 확인하여 mount: permission denied (are you root?)가 나타나는지 확인하세요. 예를 들어:

Service container logs:
2023-08-01T16:04:09.541703572Z Certificate request self-signature ok
2023-08-01T16:04:09.541770852Z subject=CN = docker:dind server
2023-08-01T16:04:09.556183222Z /certs/server/cert.pem: OK
2023-08-01T16:04:10.641128729Z Certificate request self-signature ok
2023-08-01T16:04:10.641173149Z subject=CN = docker:dind client
2023-08-01T16:04:10.656089908Z /certs/client/cert.pem: OK
2023-08-01T16:04:10.659571093Z ip: can't find device 'ip_tables'
2023-08-01T16:04:10.660872131Z modprobe: can't change directory to '/lib/modules': No such file or directory
2023-08-01T16:04:10.664620455Z mount: permission denied (are you root?)
2023-08-01T16:04:10.664692175Z Could not mount /sys/kernel/security.
2023-08-01T16:04:10.664703615Z AppArmor detection and --privileged mode might break.
2023-08-01T16:04:10.665952353Z mount: permission denied (are you root?)

이것은 GitLab 러너가 dind 서비스를 시작할 권한이 없음을 나타냅니다:

  1. config.toml에서 privileged = true가 설정되어 있는지 확인하세요.
  2. 이러한 권한 있는 러너를 사용하도록 CI 작업이 올바르게 Runner 태그로 정의되어 있는지 확인하세요.

오류: cgroups: cgroup mountpoint does not exist: unknown

도커 엔진 20.10에서 도입된 알려진 호환성 문제가 있습니다.

호스트가 도커 엔진 20.10 이상을 사용하는 경우, 20.10 이전 버전의 docker:dind 서비스는 예상대로 작동하지 않습니다.

서비스 자체는 문제없이 시작되지만, 컨테이너 이미지를 빌드하려고 하면 다음과 같은 오류가 발생합니다.

cgroups: cgroup mountpoint does not exist: unknown

이 문제를 해결하려면 docker:dind 컨테이너를 적어도 20.10.x 버전으로 업데이트하십시오. 예를 들어 docker:24.0.5-dind와 같은 버전입니다.

반대 구성(docker:24.0.5-dind 서비스 및 호스트의 도커 엔진이 19.06.x 이하 버전인 경우)는 문제없이 작동합니다. 최상의 전략을 위해 작업 환경 버전을 자주 테스트하고 업데이트하여 최신 버전으로 유지하는 것이 좋습니다. 이렇게 하면 새로운 기능이나 향상된 보안 그리고 이 특정 사례의 경우에는 러너 호스트의 기본 도커 엔진 업그레이드가 작업에 대해 투명하게 이루어집니다.