11 애플리케이션 빌드 및 테스트

seohan·2022년 3월 18일
0

자동화는 Docker의 핵심입니다. 구성 요소를 Dockerfile에 패키징하고 Docker 명령줄을 사용하여 실행하는 단계를 설명합니다. Docker Compose 파일에서 앱의 아키텍처를 표현하고 Compose 명령줄을 사용하여 앱을 시작 및 중지합니다. 명령줄 도구는 데일리로 실행되거나 개발자가 코드 변경 사항을 푸시할 때마다 실행되는 작업과 같은 자동화된 프로세스에 매우 적합합니다. 이러한 작업을 실행하는 데 사용하는 도구는 중요하지 않습니다. 모두 명령 스크립트로 실행할 수 있으므로 Docker 워크플로를 자동화 서버와 쉽게 통합할 수 있습니다.

이 장에서는 Docker와 지속적 통합(CI)을 수행하는 방법을 배웁니다. CI는 애플리케이션을 구축하고 일련의 테스트를 실행하기 위해 정기적으로 실행되는 자동화된 프로세스입니다. CI 작업이 정상이면 앱의 최신 코드가 양호하고 패키징되었으며 릴리스 후보로 배포할 준비가 되었음을 의미합니다. CI 서버와 작업을 설정하고 관리하는 것은 시간이 많이 걸리고 집약적이었습니다. Docker는 CI 프로세스의 모든 부분을 단순화하고 사람들이 더 흥미로운 작업을 할 수 있도록 합니다.

11.1 CI 프로세스가 Docker와 작동하는 방식

CI 프로세스는 코드로 시작하여 일련의 단계를 실행하고 테스트된 배포 가능한 아티팩트로 끝나는 파이프라인입니다. CI의 과제 중 하나는 파이프라인이 각 프로젝트마다 고유하다는 것입니다. 다른 기술 스택은 단계에서 다른 작업을 수행하고 다른 유형의 아티팩트를 생성합니다. CI 서버는 모든 고유한 파이프라인에 대해 작동해야 하므로 프로그래밍 언어와 빌드 프레임워크의 모든 조합이 서버에 설치될 수 있고 쉽게 관리할 수 없게 될 수 있습니다.

Docker는 모든 프로젝트가 동일한 단계를 따르고 동일한 유형의 아티팩트를 생성하기 때문에 CI 프로세스에 일관성을 제공합니다. 그림 11.1은 도커가 있는 일반적인 파이프라인을 보여줍니다. 코드 변경 또는 시간 지정 일정에 의해 트리거되고 도커 이미지 세트를 생성합니다. 이러한 이미지에는 최신 버전의 코드(컴파일, 테스트, 패키징 및 배포를 위해 레지스트리로 푸시)가 포함되어 있습니다.


그림 11.1 앱을 빌드, 테스트 및 게시하기 위한 CI 파이프라인의 기본 단계(모두 Docker로 실행).

CI 파이프라인의 각 단계는 Docker 또는 Docker Compose와 함께 실행되며 모든 작업은 컨테이너 내에서 발생합니다. 컨테이너를 사용하여 애플리케이션을 컴파일하므로 CI 서버에 프로그래밍 언어나 빌드 SDK가 설치되어 있지 않아도 됩니다. 자동화된 단위 테스트는 이미지 빌드의 일부로 실행되므로 코드가 손상되면 빌드가 실패하고 CI 작업이 중지됩니다. 또한 사용자 워크플로를 시뮬레이션하기 위해 테스트를 실행하는 별도의 컨테이너와 함께 전체 애플리케이션을 Docker Compose로 시작하여 보다 정교한 종단 간 테스트를 실행할 수 있습니다.

도커화된 CI 프로세스에서는 모든 힘든 작업이 컨테이너에서 발생하지만 모든 것을 함께 유지하려면 중앙 집중식 소스 코드 시스템, 이미지를 저장하기 위한 Docker 레지스트리, CI 작업을 실행하기 위한 자동화 서버와 같은 일부 인프라 구성 요소가 여전히 필요합니다. Docker를 지원하는 모든 관리 서비스 중에서 선택할 수 있는 관리 서비스가 매우 다양합니다. GitHub와 Azure DevOps 및 Docker Hub를 혼합하여 사용하거나 일체형 솔루션을 제공하는 GitLab을 사용할 수 있습니다. 또는 Docker 컨테이너에서 자체 CI 인프라를 실행할 수 있습니다.

11.2 Docker로 빌드 인프라 스핀업

신뢰할 수 있는 관리 서비스를 무료로 얻을 수 있을 때 자체 인프라 구성 요소를 실행하고 싶어하는 사람은 아무도 없지만 Docker에서 빌드 시스템을 실행하는 것은 매우 유용한 대안입니다. 데이터 소유권 또는 전송 속도를 위해 소스 코드와 패키지 이미지를 자체 네트워크 내에 완전히 유지하려는 경우에 이상적이지만 모든 서비스에 대해 서비스를 사용하더라도 간단한 백업 옵션이 있는 것이 좋습니다.

필요한 세 가지 구성 요소는 엔터프라이즈급 오픈 소스 소프트웨어를 사용하여 컨테이너에서 쉽게 실행할 수 있습니다. 단일 명령으로 소스 제어용 Gogs, 배포용 오픈 소스 Docker Registry, 자동화 서버로 Jenkins를 사용하여 자체 설정을 실행할 수 있습니다.

TRY ch11/exercise/infrastructure 폴더에는 빌드 인프라를 정의하는 Docker Compose 파일이 있습니다.

docker-compose -f docker-compose.yml -f docker-compose-linux.yml up -d

레지스트리 도메인을 hosts 파일에 추가합니다.

 # echo $'\n127.0.0.1 registry.local' | sudo tee -a /etc/hosts

Check containers:

docker container ls

이 세 가지 도구는 서로 다른 수준의 자동화를 지원하기 때문에 흥미롭게 작업할 수 있습니다. registry 서버는 추가 설정 없이 컨테이너에서 실행되므로 이제 이미지 태그의 도메인으로 registry.local:5000을 사용하여 이미지를 푸시하고 가져올 수 있습니다. Jenkins는 플러그인 시스템을 사용하여 기능을 추가하고 수동으로 설정하거나 Dockerfile에 스크립트 세트를 번들로 묶어 설정을 자동화할 수 있습니다. Gogs는 실제로 좋은 자동화 스토리가 없기 때문에 실행 중이지만 약간의 수동 구성이 필요합니다.

TRY http://localhost:3000으로 이동하면 Gogs용 웹 UI가 표시됩니다. 첫 번째 페이지는 그림 11.3과 같이 초기 설치입니다. 이것은 새 컨테이너를 처음 사용할 때만 표시됩니다. 모든 값이 올바르게 구성되었습니다. 아래로 스크롤하여 Install Gogs를 클릭하기만 하면 됩니다.

Docker에서 소프트웨어를 실행할 때 소프트웨어를 수동으로 구성해야 하는 것은 상당히 답답하고 스크린샷을 책에 복사하여 붙여넣는 것이 훨씬 더 답답하지만 모든 앱에서 설치를 완전히 자동화할 수 있는 것은 아닙니다. 이미 완료된 설정 단계로 사용자 지정 이미지를 구축할 수 있었지만 항상 도커 컨테이너 실행 워크플로에 멋지게 패키징할 수는 없다는 점을 이해하는 것이 중요합니다.

Jenkins는 더 나은 경험입니다. Jenkins는 Java 애플리케이션이며 컨테이너가 시작될 때 실행되는 스크립트 세트를 사용하여 Docker 이미지로 패키징할 수 있습니다. 이러한 스크립트는 플러그인 설치, 사용자 등록, 파이프라인 작업 생성 등 거의 모든 작업을 수행할 수 있습니다. 이 Jenkins 컨테이너는 모든 작업을 수행하므로 바로 로그인하여 사용할 수 있습니다.

그림 11.6 컨테이너에서 Jenkins 실행 -- 이미 설정된 사용자 및 CI 작업으로 완전히 구성되었습니다.

TRY http://localhost:8080으로 이동합니다. 이미 diamol이라는 작업이 구성되어 있고 실패한 상태입니다. 오른쪽 상단의 로그인 링크를 클릭하고 사용자 이름 diamol과 암호 diamol로 로그인합니다.

Jenkins 작업은 Gogs Git 서버에서 코드를 가져오도록 구성되어 있고 아직 코드가 없기 때문에 실패했습니다. 이 책의 소스 코드는 이미 GitHub에서 복제한 Git 리포지토리입니다. 로컬 Gogs 컨테이너를 리포지토리의 다른 Git 서버로 추가하고 책의 코드를 자체 인프라에 푸시할 수 있습니다.

TRY git 서버를 추가한 다음 원격으로 푸시할 수 있습니다. 이렇게 하면 로컬 컴퓨터에서 Gogs 서버로 코드가 업로드되며, 이 서버도 컴퓨터의 컨테이너 역할을 합니다.

 git remote add local http://localhost:3000/diamol/diamol.git
 
 git push local
 
 # Gogs will ask you to login -
 # use the diamol username and password you registered in Gogs

이제 로컬 git 서버에 전체 책의 소스 코드가 있습니다. Jenkins 작업은 1분마다 코드에 대한 변경 사항을 찾도록 구성되며 변경 사항이 있으면 CI 파이프라인을 트리거합니다. 코드 저장소가 존재하지 않아 첫 번째 작업 실행이 실패하여 Jenkins가 일정을 보류했습니다. 일정을 다시 시작하려면 지금 수동으로 작업을 실행해야 합니다.

그림 11.7 Jenkins 작업 페이지는 작업의 현재 상태를 보여주고 수동으로 빌드를 시작할 수 있도록 합니다.

TRY http://localhost:8080/job/diamol로 이동합니다. 그림 11.7의 화면을 볼 수 있으며 왼쪽 메뉴에서 지금 빌드를 클릭하여 작업을 실행할 수 있습니다. 지금 빌드 옵션이 표시되지 않으면 diamol 자격 증명으로 Jenkins에 로그인했는지 확인하십시오.

1분 정도 후에 빌드가 성공적으로 완료되고 웹 페이지가 새로 고쳐지고 그림 11.8과 같은 출력이 표시됩니다.

이 파이프라인의 모든 부분은 도커 컨테이너를 사용하여 실행되었으며 깔끔한 트릭을 활용합니다. 도커에서 실행되는 컨테이너는 도커 API에 연결하고 실행 중인 동일한 도커 엔진에서 새 컨테이너를 시작할 수 있습니다. Jenkins 이미지에는 Docker CLI가 설치되어 있고 Compose 파일의 구성은 Jenkins를 설정하므로 Docker 명령을 실행할 때 시스템의 Docker 엔진으로 전송됩니다. 이상하게 들리지만 실제로는 Docker CLI가 Docker API를 호출한다는 사실을 활용하여 다른 위치의 CLI가 동일한 Docker 엔진에 연결할 수 있습니다. 그림 11.9는 이것이 어떻게 작동하는지 보여줍니다.

그림 11.9 Docker API용 프라이빗 채널을 바인딩하기 위해 볼륨이 있는 컨테이너 실행

Docker CLI는 기본적으로 시스템 전용 통신 채널(Linux의 소켓 또는 Windows의 명명된 파이프)을 사용하여 로컬 Docker API에 연결합니다. 해당 통신 채널은 컨테이너의 바인드 마운트로 사용할 수 있으므로 컨테이너의 CLI가 실행될 때 실제로 컴퓨터의 소켓 또는 명명된 파이프에 연결됩니다. 이는 컨테이너 내부의 앱이 Docker를 쿼리하여 다른 컨테이너를 찾거나 새 컨테이너를 시작 및 중지할 수 있는 몇 가지 유용한 시나리오를 잠금 해제합니다. 컨테이너의 앱은 호스트의 모든 Docker 기능에 대한 전체 액세스 권한이 있기 때문에 여기에 보안 문제도 있습니다. 따라서 신뢰할 수 있는 Docker 이미지와 함께 이를 신중하게 사용해야 합니다.

목록 11.1은 Jenkins 사양에 초점을 맞춰 인프라 컨테이너를 시작하기 위해 실행한 Docker Compose 파일의 일부를 보여줍니다. Linux 버전에서는 볼륨이 Docker 소켓에 바인딩되는 것을 볼 수 있습니다. 이것은 Docker API의 주소입니다.

목록 11.1 Jenkins의 Docker CLI를 Docker 엔진에 바인딩

docker-compose.yml

 services:
   jenkins:
       image: diamol/jenkins
       ports:
           - "8080:8080"
       networks:
           - infrastructure

docker-compose-linux.yml

 jenkins:
   volumes:
       - type: bind
           source: /var/run/docker.sock
           target: /var/run/docker.sock

이것이 필요한 모든 인프라입니다. Jenkins는 Docker 엔진에 연결하여 Docker 및 Docker Compose 명령을 실행하고, 동일한 Docker 네트워크에 있는 모든 컨테이너이기 때문에 DNS를 통해 Git 서버 및 Docker 레지스트리에 연결할 수 있습니다. CI 프로세스는 단일 명령을 실행하여 애플리케이션을 빌드하고 빌드의 모든 복잡성은 Dockerfile 및 Docker Compose 파일에 작성됩니다.

11.3 Docker Compose로 빌드 설정 캡처

Jenkins가 실행한 작업은 8장에서 난수 앱의 새 버전을 빌드했습니다. 10장에서 여러 Compose 파일에서 응용 프로그램 정의를 분할하는 방법을 보았고 이 앱은 해당 접근 방식을 사용하여 세부 정보를 캡처합니다.

Listing 11.2는 ch11/exercises 폴더의 기본 docker-compose.yml 파일에서 가져온 것으로, 이미지 이름에 환경 변수가 있는 웹 및 API 서비스 정의가 포함되어 있습니다.

목록 11.2 이미지 태그의 변수를 사용하는 핵심 Docker Compose 파일

 services:
   numbers-api:
       image: ${REGISTRY:-docker.io}/diamol/ch11-numbers-api:v3-build-${BUILD_NUMBER:-local}
       networks:
           - app-net
 
   numbers-web:
       image: ${REGISTRY:-docker.io}/diamol/ch11-numbers-web:v3-build-${BUILD_NUMBER:-local}
       environment:
           - RngApi__Url=http://numbers-api/rng
       networks:
             - app-net

여기 환경 변수 구문에는 :- 로 설정된 기본값이 포함되어 있으므로 ${REGISTRY:-docker.io} 는 런타임에 해당 토큰을 REGISTRY 라는 환경 변수 값으로 바꾸도록 Compose에 지시합니다. 해당 환경 변수가 존재하지 않거나 비어 있으면 기본값 docker.io 를 사용합니다. 이미지 태그에 동일한 접근 방식을 사용하므로 BUILD_NUMBER 환경 변수가 설정되면 해당 값이 태그에 들어가거나 아니면 local이 사용됩니다.

이는 동일한 아티팩트 세트를 사용하여 CI 프로세스 및 로컬 개발자 빌드를 지원하는 패턴입니다. 개발자가 API 이미지를 빌드할 때 환경 변수가 설정되지 않으므로 이미지 이름은 docker.io/diamol/ch11-numbers-api:v3-build-local 입니다. 하지만 docker.io는 기본 도메인인 Docker Hub이므로 이미지가 diamol/ch11-numbers-api:v3-build-local 로 표시됩니다. Jenkins에서 동일한 빌드가 실행되면 변수는 로컬 Docker 레지스트리와 작업의 실제 빌드 번호를 사용하도록 설정되며 Jenkins는 증가하는 숫자로 설정하므로 이미지 이름은 registry.local:5000/diamol/이 됩니다.

유연한 이미지 이름을 설정하는 것은 CI 설정의 중요한 부분이지만 핵심 정보는 재정의 파일 docker-compose-build.yml 에 지정되어 있습니다. 이 파일은 Dockerfile을 찾을 위치를 Compose에 알려줍니다.

TRY ch11/execise 폴더에서 CI 빌드 파이프라인과 동일한 단계를 사용하여 로컬에서 앱을 빌드할 수 있습니다. 터미널 세션에서 시작하여 해당 장의 디렉터리로 이동한 다음 Docker Compose를 사용하여 앱을 빌드합니다.

# build both images:
docker-compose -f docker-compose.yml -f docker-compose-build.yml build
 
# check the labels for the web image:
docker image inspect -f '{{.Config.Labels}}' diamol/ch11-numbers-api:v3-build-local
map[build_number:0 build_tag:local version:3.0]

Docker Compose를 통해 애플리케이션을 빌드하면 빌드 설정이 지정된 모든 서비스에 대해 docker image build 명령이 효과적으로 실행됩니다. 이미지는 12개 또는 1개가 될 수 있습니다. 하나의 이미지에 대해서도 Compose로 빌드하는 것이 좋습니다. 그러면 Compose 파일이 이미지를 빌드할 때 원하는 태그를 지정하기 때문입니다. 이 빌드에는 성공적인 CI 파이프라인의 일부인 몇 가지가 더 있습니다. 이미지의 레이블을 나열하는 최종 검사 명령에서 확인할 수 있습니다.

Docker를 사용하면 컨테이너, 이미지, 네트워크 및 볼륨과 같은 대부분의 리소스에 레이블을 적용할 수 있습니다. 리소스에 대한 추가 데이터를 저장할 수 있는 간단한 키/값 쌍입니다. 레이블은 이미지에 구워지고 이미지와 함께 움직이기 때문에 이미지에 매우 유용합니다. 이미지를 밀거나 당길 때 레이블도 함께 이동합니다. CI 파이프라인을 사용하여 앱을 빌드할 때 실행 중인 컨테이너에서 이를 생성한 빌드 작업까지 다시 추적할 수 있는 감사 추적을 갖는 것이 중요하며 이미지 레이블이 이를 수행하는 데 도움이 됩니다.

목록 11.3은 난수 API용 Dockerfile의 일부를 보여줍니다. 여기에는 ARG와 LABEL이라는 두 가지 새로운 Dockerfile 명령어가 있습니다.

목록 11.3 Dockerfile에서 이미지 레이블 및 빌드 인수 지정

 # app image
 FROM diamol/dotnet-aspnet
 
 ARG BUILD_NUMBER=0
 ARG BUILD_TAG=local
 
 LABEL version="3.0"
 LABEL build_number=${BUILD_NUMBER}
 LABEL build_tag=${BUILD_TAG}
 
 ENTRYPOINT ["dotnet", "Numbers.Api.dll"]

LABEL 명령어는 빌드될 때 Dockerfile의 키/값 쌍을 이미지에 적용합니다. Dockerfile에 지정된 version=3.0을 볼 수 있으며 이는 그림 11.10의 레이블 출력과 일치합니다. 다른 두 LABEL 명령어는 환경 변수를 사용하여 레이블 값을 설정하고 이러한 환경 변수는 ARG 명령어에서 제공합니다.

ARG는 컨테이너의 런타임이 아니라 이미지의 빌드 시간에 작동한다는 점을 제외하면 ENV 명령과 매우 유사합니다. 둘 다 환경 변수의 값을 설정하지만 ARG 명령어의 경우 해당 설정은 빌드 기간 동안만 존재하므로 이미지에서 실행하는 모든 컨테이너에는 해당 변수가 표시되지 않습니다. 컨테이너 실행과 관련이 없는 빌드 프로세스에 데이터를 전달하는 좋은 방법입니다. 이미지 레이블에 값을 제공하기 위해 여기에서 사용하고 있습니다. CI 프로세스에서 이 값은 빌드 번호와 전체 빌드 이름을 기록합니다. ARG 명령어는 기본값도 설정하므로 변수를 전달하지 않고 이미지를 로컬로 빌드하면 이미지 레이블에 build_number:0build_tag:local이 표시됩니다.

Compose 재정의 파일에서 CI 파이프라인의 환경 설정이 Docker 빌드 명령으로 전달되는 방식을 확인할 수 있습니다. 목록 11.4는 모든 빌드 설정과 함께 docker-compose-build.yml 파일의 내용을 보여줍니다.

목록 11.4 Docker Compose에서 빌드 설정 및 재사용 가능한 인수 지정

 x-args: &args
   args:
       BUILD_NUMBER: ${BUILD_NUMBER:-0}
       BUILD_TAG: ${BUILD_TAG:-local}
 services:
   numbers-api:
       build:
           context: numbers
           dockerfile: numbers-api/Dockerfile.v4
           <<: *args
 
   numbers-web:
       build:
           context: numbers
           dockerfile: numbers-web/Dockerfile.v4
             <<: *args

이 Compose 파일은 10장을 건너뛰지 않는 한 너무 복잡하지 않아야 합니다. 이 경우에는 돌아가서 읽어야 합니다. 점심시간 이상 소요되지 않습니다.

Compose 사양의 빌드 블록에는 세 부분이 있습니다.

  • context -- 이것은 Docker가 빌드의 작업 디렉토리로 사용할 경로입니다. 이것은 일반적으로 docker image build 명령에서 마침표를 사용하여 전달하는 현재 디렉터리이지만 여기에는 숫자 디렉터리가 있습니다. 경로는 Compose 파일의 위치에 상대적입니다.

  • dockerfile -- 컨텍스트를 기준으로 하는 Dockerfile의 경로입니다.

  • args --Dockerfile에서 ARG 명령으로 지정된 키와 일치해야 하는 전달할 빌드 인수입니다. 이 앱의 두 Dockerfile은 동일한 BUILD_NUMBER 및 BUILD_TAG 인수를 사용하므로 Compose 확장 필드를 사용하여 해당 값을 한 번 정의하고 YAML 병합을 사용하여 두 서비스에 적용합니다.

다양한 위치에 지정된 기본값을 볼 수 있으며 이는 CI 프로세스 지원으로 인해 다른 워크플로가 중단되지 않도록 하기 위한 것입니다. 빌드가 실행되더라도 동일한 방식으로 빌드되는 단일 Dockerfile을 항상 목표로 해야 합니다. Compose 파일의 기본 인수는 CI 환경 외부에서 빌드를 실행할 때 빌드가 성공함을 의미하고 Dockerfile의 기본값은 Compose를 사용하지 않아도 이미지가 올바르게 빌드됨을 의미합니다.

TRY ch11/exercises/numbers 폴더에서 일반 이미지 빌드 명령으로 난수 API 이미지를 빌드할 수 있으며, Compose 파일의 설정을 건너뛸 수 있습니다.

빌드 인자를 지정하고 이미지를 빌드합니다.

docker image build -f numbers-api/Dockerfile.v4 --build-arg BUILD_TAG=ch11 -t numbers-api .

레이블을 확인합니다ㅣ

$ docker image inspect -f '{{.Config.Labels}}' numbers-api
map[build_number:0 build_tag:ch11 version:3.0]

레이블을 이미지로 가져오기 위한 몇 가지 세부 수준이 있지만 올바르게 하는 것이 중요합니다. 도커 이미지 검사를 실행하고 해당 이미지의 출처를 정확히 찾아 그것을 생성한 CI 작업으로 추적한 다음 빌드를 트리거한 정확한 코드 버전으로 다시 추적할 수 있어야 합니다. 모든 환경에서 실행 중인 컨테이너에서 소스 코드로 돌아가는 감사 추적입니다.

11.4 Docker를 제외하고 종속성이 없는 CI 작업 작성

컴퓨터에 다른 도구를 설치할 필요 없이 Docker 및 Docker Compose를 사용하여 이 장의 난수 앱용 이미지를 즐겁게 빌드했습니다. 앱에는 두 가지 구성 요소가 있으며 둘 다 .NET Core 3.0으로 작성되지만 이를 빌드하기 위해 컴퓨터에 .NET Core SDK가 필요하지는 않습니다. 그들은 4장의 다단계 Dockerfile 접근 방식을 사용하여 앱을 컴파일하고 패키징하므로 Docker와 Compose만 있으면 됩니다.

이는 컨테이너화된 CI의 주요 이점이며 Docker Hub, GitHub Actions 및 Azure DevOps와 같은 모든 관리되는 빌드 서비스에서 지원됩니다. 이는 더 이상 많은 도구가 설치된 빌드 서버가 필요하지 않으며 모든 개발자와 함께 도구를 최신 상태로 유지해야 합니다. 또한 빌드 스크립트가 매우 간단해짐을 의미합니다. 개발자는 정확히 동일한 빌드 스크립트를 로컬에서 사용하고 CI 파이프라인과 동일한 출력을 얻을 수 있으므로 다른 빌드 서비스 간에 쉽게 이동할 수 있습니다.

우리는 CI 프로세스에 Jenkins를 사용하고 있으며 Jenkins 작업은 애플리케이션 코드, Dockerfiles 및 Compose 파일과 함께 소스 제어에 있는 간단한 텍스트 파일로 구성할 수 있습니다. 목록 11.5는 파이프라인 단계가 실행하는 배치 스크립트와 함께 파이프라인의 일부( ch11/exercises/Jenkinsfile 파일에서)를 보여줍니다.

Listing 11.5 CI 작업을 설명하는 Jenkinsfile의 빌드 단계

 # the build stage in the Jenkinsfile- it switches directory, then runs two
 # shell commands - the first sets up a script file so it can be executed
 # and the second calls the script:
 stage('Build') {
   steps {
       dir('ch11/exercises') {
           sh 'chmod +x ./ci/01-build.bat'
           sh './ci/01-build.bat'
           }
   }
 }
 
 # and this is what's in 01-build.bat script:
 docker-compose
   -f docker-compose.yml
   -f docker-compose-build.yml
     build --pull

잘 보세요. 로컬에서 실행한 것과 동일한 docker-compose 빌드 명령입니다. pull 플래그를 추가하는 것을 제외하고 Docker는 빌드 중에 필요한 모든 이미지의 최신 버전을 가져옵니다. 어쨌든 빌드를 할 때 익히는 좋은 습관입니다. 왜냐하면 이는 항상 최신 보안 수정 사항을 사용하여 최신 기본 이미지에서 이미지를 빌드한다는 것을 의미하기 때문입니다. Dockerfile에서 사용하는 이미지가 변경되어 앱이 손상될 수 있고 가능한 한 빨리 이를 확인하고 싶을 수 있기 때문에 CI 프로세스에서 특히 중요합니다.

빌드 스테이지는 간단한 스크립트 파일을 실행합니다. 이 단계는 빌드를 실행하고 간단한 명령줄 호출이기 때문에 Docker Compose의 모든 출력이 캡처되어 빌드 로그에 저장됩니다.

TRY Jenkins UI에서 로그를 볼 수 있습니다. http://localhost :8080/job/diamol로 이동하여 작업을 확인하고 파이프라인 보기에서 작업 #2의 빌드 단계를 클릭합니다. 그런 다음 로그를 클릭합니다. 빌드 단계를 확장하면 일반적인 Docker 빌드 출력을 볼 수 있습니다.

빌드 파이프라인의 각 단계는 동일한 패턴을 따릅니다. Docker Compose 명령을 실행하여 실제 작업을 수행하는 배치 스크립트를 호출합니다. 이 접근 방식을 사용하면 서로 다른 빌드 서비스 간에 쉽게 전환할 수 있습니다. 독점 파이프라인 구문으로 논리를 작성하는 대신 스크립트로 작성하고 파이프라인을 사용하여 스크립트를 호출합니다. GitLab 또는 GitHub Actions에서 빌드를 실행하기 위해 파이프라인 파일을 추가할 수 있으며 동일한 배치 스크립트를 호출합니다.

Jenkins 빌드의 스테이지는 모두 컨테이너로 구동됩니다.

  • 검증은 00-verify 스크립트를 호출하여 Docker 및 Docker Compose에 대한 버전 정보만 출력합니다. 이는 Docker 종속성을 사용할 수 있는지 확인하고 이미지를 빌드한 도구 버전을 기록하기 때문에 파이프라인을 시작하는 데 유용한 방법입니다.

  • 빌드는 01-build를 호출합니다. Docker Compose를 사용하여 이미지를 빌드합니다. REGISTRY 환경 변수는 Jenkinsfile에 지정되므로 이미지에 로컬 레지스트리에 대한 태그가 지정됩니다.

  • 테스트는 Docker Compose를 사용하여 전체 애플리케이션을 시작한 다음 컨테이너를 나열하고 애플리케이션을 다시 종료하는 02-test를 호출합니다. 이것은 단순한 예시일 뿐이지만 컨테이너가 실패 없이 실행된다는 것을 증명합니다. 실제 프로젝트에서는 앱을 실행한 다음 다른 컨테이너에서 종단 간 테스트를 실행합니다.

  • 푸시는 Docker Compose를 사용하여 빌드된 모든 이미지를 푸시하는 03-push를 호출합니다. 이미지 태그에는 로컬 레지스트리 도메인이 있으므로 빌드 및 테스트 단계가 성공하면 이미지가 레지스트리로 푸시됩니다.

CI 파이프라인의 스테이지는 순차적이므로 어느 지점에서든 장애가 발생하면 작업이 종료됩니다. 즉, 레지스트리는 잠재적 릴리스 후보에 대한 이미지만 저장합니다. 레지스트리에 푸시된 이미지는 빌드 및 테스트 단계를 성공적으로 통과해야 합니다.

TRY Jenkins에서 하나의 성공적인 빌드가 있습니다. 빌드 #1이 실패하고 빌드 #2가 성공했습니다. REST API를 사용하여 로컬 레지스트리 컨테이너를 쿼리할 수 있으며 각 난수 이미지에 대해 버전 2 태그만 표시되어야 합니다.

모든 이미지 저장소를 확인합니다.

$ curl http://registry.local:5000/v2/_catalog
{"repositories":["diamol/ch11-numbers-api","diamol/ch11-numbers-web"]}

저장소의 태그 목록을 확인합니다

$ curl http://registry.local:5000/v2/diamol/ch11-numbers-api/tags/list
{"name":"diamol/ch11-numbers-api","tags":["v3-build-2"]}

$ curl http://registry.local:5000/v2/diamol/ch11-numbers-web/tags/list
{"name":"diamol/ch11-numbers-web","tags":["v3-build-2"]}

이것은 상당히 간단한 CI 파이프라인이지만 빌드의 모든 주요 단계와 몇 가지 중요한 모범 사례를 보여줍니다. 핵심은 Docker가 어려운 작업을 수행하도록 하고 스크립트에서 파이프라인 단계를 빌드하도록 하는 것입니다. 그런 다음 CI 도구를 사용하고 스크립트를 도구의 파이프라인 정의에 연결하기만 하면 됩니다.

11.5 CI 프로세스의 컨테이너 이해

컨테이너에서 애플리케이션을 컴파일하고 실행하는 것은 CI 파이프라인에서 Docker로 수행할 수 있는 작업의 시작일 뿐입니다. Docker는 모든 애플리케이션 빌드 위에 일관성 계층을 추가하고, 이 일관성을 사용하여 파이프라인에 많은 유용한 기능을 추가할 수 있습니다. 그림 11.14는 알려진 취약점에 대한 보안 검색 컨테이너 이미지와 출처를 주장하기 위한 디지털 서명 이미지를 포함하는 보다 광범위한 CI 프로세스를 보여줍니다.


그림 11.14 보안 게이트 스테이지를 추가하는 프로덕션 등급 CI 파이프라인

Docker는 이 접근 방식을 보안 소프트웨어 공급망이라고 부르며 배포하려는 소프트웨어가 안전하다는 확신을 주기 때문에 모든 규모의 조직에 중요합니다. 파이프라인에서 도구를 실행하여 알려진 보안 취약점을 확인하고 문제가 있는 경우 빌드에 실패할 수 있습니다. 성공적인 빌드가 끝날 때 발생하는 프로세스인 디지털 서명된 이미지의 컨테이너만 실행하도록 프로덕션 환경을 구성할 수 있습니다. 컨테이너가 프로덕션에 배포되면 빌드 프로세스를 통해 제공된 이미지에서 컨테이너가 실행되고 있으며 모든 테스트를 통과하고 보안 문제가 없는 소프트웨어가 컨테이너에 포함되어 있음을 확신할 수 있습니다.

파이프라인에 추가한 견제와 균형은 컨테이너와 이미지에서 작동하므로 모든 애플리케이션 플랫폼에서 동일한 방식으로 적용됩니다. 프로젝트 전체에서 여러 기술로 작업하는 경우 Dockerfile에서 다른 기본 이미지와 다른 빌드 단계를 사용하게 되지만 CI 파이프라인은 모두 동일합니다.

11.6 Lab

실습 시간! 자신만의 CI 파이프라인을 구축할 것이지만 두려워하지 마십시오. 우리는 이 장의 아이디어와 연습을 사용할 것이지만 파이프라인 단계는 훨씬 간단할 것입니다.

이 장의 랩 폴더에서 6장의 할 일 앱에 대한 소스 코드 사본을 찾을 수 있습니다. 해당 앱의 빌드는 거의 준비되었습니다. Jenkinsfile이 있고 CI 스크립트가 있습니다. 핵심 Docker Compose 파일이 있습니다. 다음과 같은 몇 가지 작업을 수행할 수 있습니다.

  • 빌드 설정을 사용하여 docker-compose-build.yml이라는 재정의 파일을 작성합니다.
  • 파이프라인을 실행할 Jenkins 작업을 만듭니다.
  • 변경 사항을 diamol 저장소의 Gogs에 푸시합니다.

세 가지 작업이지만 처음 몇 가지 빌드가 실패하고 로그를 확인하고 몇 가지를 조정해야 하는 경우 낙담하지 마십시오. 역사상 누구도 첫 실행에서 통과한 Jenkins 작업을 작성한 적이 없으므로 여기에 몇 가지 힌트가 있습니다.

  • Compose 재정의는 exercise에서와 유사하며 빌드 번호 레이블에 대한 컨텍스트와 빌드 인수를 지정합니다.
  • Jenkins UI에서 New Item을 클릭하여 작업을 생성하고 기존 diamol 작업에서 복사할 수 있습니다.
  • Jenkinsfile에 대한 경로를 제외하고 새 작업 설정은 동일합니다. 연습 폴더 대신 lab 폴더를 지정해야 합니다.
profile
코드코드

0개의 댓글