GitLab CI 파이프라인에서 Docker 이미지를 빌드하는 방법

CI 파이프라인의 일반적인 사용 사례 중 하나는 애플리케이션을 배포하는 데 사용할 Docker 이미지를 빌드하는 것입니다. GitLab CI는 더 빠른 파이프라인을 의미하는 통합 풀 프록시 서비스와 빌드된 이미지를 저장하기 위한 내장 레지스트리를 지원하므로 이에 대한 훌륭한 선택입니다.
이 가이드에서는 위의 두 기능을 모두 사용하는 Docker 빌드를 설정하는 방법을 보여줍니다. 취해야 할 단계는 파이프라인에 사용할 GitLab Runner 실행기 유형에 따라 약간 다릅니다. 아래에서 Shell 및 Docker 실행기를 다룰 것입니다.
Shell Executor로 빌드하기
Shell 실행기를 사용하는 경우 러너를 호스팅하는 시스템에 Docker가 설치되어 있는지 확인하십시오. 실행기는 Runner의 호스트에서 docker 바이너리를 사용하여 일반 셸 명령을 실행하여 작동합니다.
이미지를 빌드하려는 프로젝트의 Git 리포지토리로 이동합니다. 저장소 루트에 .gitlab-ci.yml 파일을 생성합니다. 이 파일은 프로젝트에 변경 사항을 푸시할 때 실행할 GitLab CI 파이프라인을 정의합니다.
파일에 다음 콘텐츠를 추가합니다.
class="co4">stagesclass="sy2">:
- build
class="co4">
docker_build:class="co3">
stageclass="sy2">: buildclass="co4">
scriptclass="sy2">:
- docker build -t example.com/example-image:latest .
- docker push example.com/example-image:latest이 단순한 구성은 파이프라인 기반 이미지 빌드의 기본 사항을 보여주기에 충분합니다. GitLab은 자동으로 Git 리포지토리를 빌드 환경에 복제하므로 docker build를 실행하면 프로젝트의 Dockerfile을 사용하고 리포지토리의 콘텐츠를 빌드 컨텍스트로 사용할 수 있습니다.
빌드가 완료되면 이미지를 레지스트리에 docker push할 수 있습니다. 그렇지 않으면 빌드를 실행한 로컬 Docker 설치에서만 사용할 수 있습니다. 개인 레지스트리를 사용하는 경우 먼저 docker login을 실행하여 적절한 인증 세부 정보를 제공하세요.
script:
- docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORDGitLab 웹 UI에서 설정 > CI/CD > 변수로 이동하여 두 자격 증명 변수의 값을 정의합니다. 파란색 변수 추가 버튼을 클릭하여 새 변수를 만들고 값을 할당합니다. GitLab은 작업을 실행하는 데 사용되는 셸 환경에서 이러한 변수를 사용할 수 있도록 합니다.

Docker Executor로 빌드하기
GitLab Runner의 Docker 실행기는 일반적으로 각 작업에 대해 완전히 깨끗한 환경을 제공하는 데 사용됩니다. 작업은 격리된 컨테이너에서 실행되므로 Runner 호스트의 docker 바이너리에 액세스할 수 없습니다.
Docker 실행기는 이미지 빌드를 위한 두 가지 가능한 전략을 제공합니다. Docker-in-Docker를 사용하거나 호스트의 Docker 소켓을 Runner의 빌드 환경에 바인딩합니다. 그런 다음 공식 Docker 컨테이너 이미지를 작업 이미지로 사용하여 CI 스크립트에서 docker 명령을 사용할 수 있습니다.
도커 인 도커
DinD(Docker-in-Docker)를 사용하여 이미지를 빌드하면 각 작업에 대해 완전히 격리된 환경이 제공됩니다. 빌드를 수행하는 Docker 프로세스는 GitLab Runner가 CI 작업을 실행하기 위해 호스트에서 생성하는 컨테이너의 하위 프로세스입니다.
DinD를 사용하려면 권한 모드가 활성화된 GitLab Runner Docker 실행기를 등록해야 합니다. 러너를 등록할 때 --docker-privileged 플래그를 추가합니다.
sudo gitlab-runner register -n
--url https://example.com
--registration-token $GITLAB_REGISTRATION_TOKEN
--executor docker
--description "Docker Runner"
--docker-image "docker:20.10"
--docker-volumes "/certs/client"
--docker-privilegedCI 파이프라인 내에서 docker:dind 이미지를 서비스로 추가합니다. 이렇게 하면 작업 이미지에 연결된 별도의 이미지로 Docker를 사용할 수 있습니다. docker:dind 컨테이너에서 Docker 인스턴스를 사용하여 이미지를 빌드하기 위해 docker 명령을 사용할 수 있습니다.
class="co4">servicesclass="sy2">:
- docker:dind
class="co4">
docker_build:class="co3">
stageclass="sy2">: buildclass="co3">
imageclass="sy2">: docker:latestclass="co4">
scriptclass="sy2">:
- docker build -t example-image:latest .DinD를 사용하면 서로 또는 호스트에 영향을 줄 수 없는 완전히 격리된 빌드가 제공됩니다. 주요 단점은 더 복잡한 캐싱 동작입니다. 각 작업은 이전에 구축된 레이어에 액세스할 수 없는 새로운 환경을 갖게 됩니다. 빌드하기 전에 이미지의 이전 버전을 가져온 다음 --cache-from 빌드 플래그를 사용하여 가져온 이미지의 레이어를 캐시 소스로 사용할 수 있도록 하여 이 문제를 부분적으로 해결할 수 있습니다.
class="co4">docker_build:class="co3">
stageclass="sy2">: buildclass="co3">
imageclass="sy2">: docker:latestclass="co4">
scriptclass="sy2">:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:latest .소켓 바인드 마운트
호스트의 Docker 소켓을 작업 환경에 마운트하는 것은 Docker 실행기를 사용할 때 대체 옵션입니다. 이렇게 하면 원활한 캐싱이 가능하며 CI 구성에 docker:dind 서비스를 추가할 필요가 없습니다.
이를 설정하려면 호스트의 Docker 소켓을 작업 컨테이너 내부의 /var/run/docker.sock에 바인딩하는 docker-volumes 플래그로 Runner를 등록합니다.
sudo gitlab-runner register -n
--url https://example.com
--registration-token $GITLAB_REGISTRATION_TOKEN
--executor docker
--description "Docker Runner"
--docker-image "docker:20.10"
--docker-volumes /var/run/docker.sock:/var/run/docker.sock이제 docker 이미지로 실행되는 작업은 docker 바이너리를 정상적으로 사용할 수 있습니다. 작업은 실제로 호스트 시스템에서 발생하여 자식 대신 작업 컨테이너의 형제가 됩니다.
이는 호스트의 Docker 설치와 함께 셸 실행기를 사용하는 것과 사실상 유사합니다. 이미지는 호스트에 상주하여 일반 docker 빌드 레이어 캐싱을 원활하게 사용할 수 있습니다.
이 접근 방식은 성능 향상, 구성 감소, DinD의 제한 없음으로 이어질 수 있지만 고유한 문제가 있습니다. 그중 가장 눈에 띄는 것은 보안 관련 사항입니다. 작업은 Runner 호스트에서 임의의 Docker 명령을 실행할 수 있으므로 GitLab 인스턴스의 악성 프로젝트는 docker run -it malable-image:latest 또는 를 실행할 수 있습니다. docker rm -f $ (docker ps -a)는 엄청난 결과를 초래합니다.
GitLab은 또한 작업이 동시에 실행될 때 소켓 바인딩이 문제를 일으킬 수 있다고 경고합니다. 이는 특정 이름으로 생성되는 컨테이너에 의존할 때 발생합니다. 작업의 두 인스턴스가 병렬로 실행되는 경우 컨테이너 이름이 호스트에 이미 존재하므로 두 번째 인스턴스는 실패합니다.
이러한 문제 중 하나가 문제가 될 것으로 예상되는 경우 DinD를 대신 사용하는 것이 좋습니다. DinD는 더 이상 일반적으로 권장되지 않지만 동시 CI 작업을 실행하는 공용 GitLab 인스턴스에 더 적합할 수 있습니다.
GitLab의 레지스트리에 이미지 푸시
GitLab 프로젝트에는 이미지를 저장하는 데 사용할 수 있는 통합 레지스트리 옵션이 있습니다. 프로젝트의 사이드바에서 패키지 및 레지스트리 > 컨테이너 레지스트리로 이동하여 레지스트리의 콘텐츠를 볼 수 있습니다. 이 링크가 보이지 않으면 설정 > 일반 > 가시성, 프로젝트, 기능 및 권한으로 이동하고 컨테이너 레지스트리 토글을 활성화하여 레지스트리를 활성화하십시오.

GitLab은 CI 작업에서 프로젝트의 컨테이너 레지스트리를 참조할 수 있는 환경 변수를 자동으로 설정합니다. script 섹션을 조정하여 레지스트리에 로그인하고 이미지를 푸시합니다.
class="co4">scriptclass="sy2">:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:latest .
- docker push $CI_REGISTRY_IMAGE:latestGitLab은 각 CI 작업에 대한 보안 자격 증명 세트를 생성합니다. $CI_JOB_TOKEN 환경 변수에는 작업이 gitlab-ci-token 사용자로 레지스트리에 연결하는 데 사용할 수 있는 액세스 토큰이 포함됩니다. 레지스트리 서버 URL은 $CI_REGISTRY로 사용할 수 있습니다.
마지막 변수인 $CI_REGISTRY_IMAGE는 프로젝트의 컨테이너 레지스트리에 대한 전체 경로를 제공합니다. 이것은 이미지 태그에 적합한 기반입니다. 이 변수를 확장하여 $CI_REGISTRY_IMAGE/production/api:latest와 같은 하위 리포지토리를 만들 수 있습니다.
다른 Docker 클라이언트는 액세스 토큰을 사용하여 인증하여 레지스트리에서 이미지를 가져올 수 있습니다. 프로젝트의 설정 > 액세스 토큰 화면에서 이를 생성할 수 있습니다. read_registry 범위를 추가한 다음 표시된 자격 증명을 사용하여 프로젝트 레지스트리에 docker 로그인합니다.
GitLab의 종속성 프록시 사용
GitLab의 종속성 프록시는 Docker 허브에서 가져오는 업스트림 이미지에 대한 캐싱 계층을 제공합니다. 이미지가 실제로 변경된 경우에만 이미지 콘텐츠를 가져옴으로써 Docker Hub의 속도 제한 내에서 유지하는 데 도움이 됩니다. 이렇게 하면 빌드 성능도 향상됩니다.

종속성 프록시는 설정 > 패키지 및 레지스트리 > 종속성 프록시로 이동하여 GitLab 그룹 수준에서 활성화됩니다. 활성화되면 .gitlab-ci.yml 파일의 이미지 참조에 $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX 접두사를 붙여 프록시를 통해 가져옵니다.
class="co4">docker_build:class="co3">
stageclass="sy2">: buildclass="co3">
imageclass="sy2">: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:latestclass="co4">
services:class="co3">
- nameclass="sy2">: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:dindclass="co3">
aliasclass="sy2">: docker그게 전부입니다! GitLab Runner는 종속성 프록시 레지스트리에 자동으로 로그인하므로 자격 증명을 수동으로 제공할 필요가 없습니다.
GitLab은 이제 이미지를 캐시하여 향상된 성능과 네트워크 중단에 대한 복원력을 제공합니다. services 정의도 조정해야 했습니다. 환경 변수는 이전에 사용된 인라인 양식에서 작동하지 않으므로 전체 이미지 이름을 지정해야 합니다. script 섹션에서 참조할 명령 alias.
이제 작업 단계에서 직접 사용하는 이미지에 대한 프록시를 설정했지만 빌드할 Dockerfile의 기본 이미지에 대한 지원을 추가하려면 더 많은 작업이 필요합니다. 이와 같은 일반 명령은 프록시를 거치지 않습니다.
FROM ubuntu:latest이 마지막 부분을 추가하려면 Docker의 빌드 인수를 사용하여 Dockerfile을 단계별로 실행할 때 종속성 프록시 URL을 사용할 수 있도록 합니다.
ARG GITLAB_DEPENDENCY_PROXY
FROM ${GITLAB_DEPENDENCY_PROXY}/ubuntu:latest그런 다음 docker build 명령을 수정하여 변수 값을 정의합니다.
class="co4">scriptclass="sy2">:
class="sy2">>
class="co0"> - docker build
--build-arg GITLAB_DEPENDENCY_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}
-t example-image:latest .이제 기본 이미지도 종속성 프록시를 통해 가져옵니다.
요약
Docker 이미지 빌드는 GitLab CI 파이프라인에 쉽게 통합됩니다. 초기 Runner 구성 후 작업의 script 섹션에 있는 docker build 및 docker push 명령만 있으면 저장소의 Dockerfile. GitLab의 내장 컨테이너 레지스트리는 프로젝트 이미지를 위한 개인 스토리지를 제공합니다.

기본 빌드 외에도 GitLab의 종속성 프록시를 통합하여 성능을 가속화하고 Docker Hub 속도 제한에 도달하지 않도록 하는 것이 좋습니다. 또한 선택한 방법이 신뢰할 수 없는 프로젝트가 Runner 호스트에서 명령을 실행하도록 허용하는지 여부를 평가하여 설치의 보안을 확인해야 합니다. 고유한 문제가 있지만 Docker-in-Docker는 GitLab 인스턴스에 공개적으로 액세스하거나 대규모 사용자 기반에서 액세스할 때 가장 안전한 접근 방식입니다.
관련기사:
- 다양한 Linux 빌드 수정 사항이 포함된 VirtualBox 5.2.16 출시
- 커널 4.19 빌드 수정 사항과 함께 출시된 Virtualbox 5.2.20
- Pinguy Builder - 나만의 맞춤형 설치 가능한 Ubuntu ISO 구축
- 여러 플랫폼에 대해 Fpm을 사용하여 Linux 패키지를 쉽게 구축하는 방법
- CheckInstall을 사용하여 소스에서 패키지를 빌드하는 방법
- 소스에서 데비안 패키지를 빌드하는 방법
- Virt-builder를 사용하여 가상 머신 이미지를 구축하는 방법
- OpenELEC로 나만의 미디어 센터를 구축하는 방법
- 라즈베리 파이로 DIY 무선 프린터를 만드는 방법
- Linux의 소스에서 패키지를 빌드하는 방법
- Ubuntu에서 사용자 정의 커널을 구축하고 설치하는 방법
- 지금 당장 구축할 수 있는 최고의 Arduino 프로젝트 15가지
- 강력한 AI 봇을 구축하기 위한 최고의 챗봇 프레임워크 Top 30
- 최신 소프트웨어 개발을 위한 20가지 최고의 빌드 자동화 도구
- 적절한 수면 습관을 기르는 데 도움이 되는 안드로이드용 최고의 수면 앱 10가지