튜토리얼: 복잡한 파이프라인 만들기

튜토리얼: 복잡한 파이프라인 만들기

작고 반복적인 단계를 통해 점점 더 복잡한 CI/CD 파이프라인을 구성하는 튜토리얼이에요. 각 단계에서 파이프라인은 항상 완전히 동작하지만, 단계를 거듭할수록 기능이 늘어나요. 목표는 문서 사이트를 빌드, 테스트, 배포하는 것이에요.

이 튜토리얼을 마치면 GitLab.com에 새 프로젝트와 Docusaurus를 사용하는 작동 중인 문서 사이트를 갖게 됩니다.

출처: 문서

본문

이 튜토리얼은 작고 반복적인 단계를 통해 점점 더 복잡한 CI/CD 파이프라인을 구성하는 방법을 안내해요. 파이프라인은 항상 완전히 동작하지만, 각 단계마다 더 많은 기능을 얻게 돼요. 목표는 문서 사이트를 빌드, 테스트, 배포하는 거예요.

이 튜토리얼을 완료하려면:

  1. Docusaurus 파일을 담을 프로젝트 만들기
  2. 초기 파이프라인 설정 파일 만들기
  3. 사이트를 빌드하는 작업 추가하기
  4. 사이트를 배포하는 작업 추가하기
  5. 테스트 작업 추가하기
  6. 머지 리퀘스트 파이프라인 사용 시작하기
  7. 중복 설정 줄이기

전제 조건

  • GitLab.com 계정이 필요해요.
  • Git에 익숙해야 해요.
  • 로컬 머신에 Node.js가 설치되어 있어야 해요. 예를 들어 macOS에서는 brew install nodenode를 설치할 수 있어요.

Docusaurus 파일을 담을 프로젝트 만들기

파이프라인 설정을 추가하기 전에 먼저 GitLab.com에 Docusaurus 프로젝트를 설정해야 해요.

  1. 사용자 이름 아래에(그룹이 아니라) 새 프로젝트를 만드세요.
    1. 오른쪽 위에서 Create new(+)와 New project/repository를 선택하세요.
    2. Create blank project를 선택하세요.
    3. 프로젝트 세부 정보를 입력하세요.
      • Project name 필드에 프로젝트 이름을 입력하세요. 예: My Pipeline Tutorial Project.
      • Initialize repository with a README를 선택하세요.
    4. Create project를 선택하세요.
  2. 로컬에 프로젝트를 복제하세요.
    1. 프로젝트 개요 페이지 오른쪽 위에서 Code를 선택해 프로젝트의 복제 경로를 찾으세요. SSH 또는 HTTP 경로를 복사하고, 그 경로를 사용해 프로젝트를 로컬에 복제하세요.
    2. 예를 들어 SSH로 컴퓨터의 pipeline-tutorial 디렉터리에 복제하려면:
      git clone [email protected]:my-username/my-pipeline-tutorial-project.git pipeline-tutorial
      
  3. 새 Docusaurus 사이트를 생성하세요. 프로젝트 디렉터리로 이동한 뒤:
    cd pipeline-tutorial
    npm init docusaurus
    
    Docusaurus 초기화 마법사가 사이트에 대한 질문을 표시해요. 모든 기본 옵션을 사용하세요.
  4. 파일을 프로젝트 루트로 옮기세요. 초기화 마법사는 사이트를 website/에 설정하지만, 사이트는 프로젝트 루트에 있어야 해요. 파일을 루트로 옮기고 이전 디렉터리를 삭제하세요.
    mv website/* .
    rm -r website
    
  5. GitLab 프로젝트 세부 정보로 Docusaurus 설정 파일을 업데이트하세요. docusaurus.config.js에서:
    • url:https://<my-username>.gitlab.io/ 형식의 경로로 설정하세요.
    • baseUrl:을 프로젝트 이름(예: /my-pipeline-tutorial-project/)으로 설정하세요.
  6. 변경 사항을 커밋하고 GitLab에 푸시하세요.
    git add .
    git commit -m "Add simple generated Docusaurus site"
    git push origin
    

초기 CI/CD 설정 파일 만들기

프로젝트에서 CI/CD가 활성화되고 작업을 실행할 러너가 사용 가능한지 확인하기 위해 가장 간단한 파이프라인 설정 파일부터 시작할게요.

이 단계에서 소개하는 것들:

  • 작업(Jobs): 작업은 파이프라인에서 명령을 실행하는 독립적인 부분이에요. 작업은 GitLab 인스턴스와 분리된 러너에서 실행돼요.
  • script: 작업 설정에서 명령을 정의하는 섹션이에요. 여러 명령(배열)이 있다면 순서대로 실행돼요. 각 명령은 CLI 명령으로 실행된 것처럼 동작해요. 기본적으로 명령이 실패하거나 오류를 반환하면 작업이 실패로 표시되고 더 이상 명령이 실행되지 않아요.

이 단계에서 프로젝트 루트에 다음 설정으로 .gitlab-ci.yml 파일을 만드세요.

test-job:
  script:
    - echo "This is my first job!"
    - date

이 변경 사항을 커밋하고 GitLab에 푸시한 다음:

  1. Build > Pipelines로 이동해 이 단일 작업으로 파이프라인이 GitLab에서 실행되는지 확인하세요.
  2. 파이프라인을 선택한 다음 작업을 선택해 작업 로그를 보고 This is my first job! 메시지 뒤에 날짜가 표시되는지 확인하세요.

이제 프로젝트에 .gitlab-ci.yml 파일이 있으니, 이후 파이프라인 설정 변경은 모두 파이프라인 편집기로 할 수 있어요.

사이트를 빌드하는 작업 추가하기

CI/CD 파이프라인의 일반적인 작업은 프로젝트의 코드를 빌드한 다음 배포하는 거예요. 먼저 사이트를 빌드하는 작업을 추가해볼게요.

이 단계에서 소개하는 것들:

  • image: 러너에게 작업을 실행할 Docker 컨테이너를 알려줘요. 러너는:
    1. 컨테이너 이미지를 다운로드하고 시작해요.
    2. 실행 중인 컨테이너에 GitLab 프로젝트를 복제해요.
    3. script 명령을 하나씩 실행해요.
  • artifacts: 작업은 독립적이고 서로 리소스를 공유하지 않아요. 한 작업에서 생성된 파일을 다른 작업에서 사용하려면 먼저 artifacts로 저장해야 해요. 그러면 이후 작업이 artifacts를 가져와 생성된 파일을 사용할 수 있어요.

이 단계에서 test-jobbuild-job으로 바꿔볼게요.

  • image를 사용해 작업이 최신 node 이미지로 실행되도록 구성하세요. Docusaurus는 Node.js 프로젝트이고 node 이미지에는 필요한 npm 명령이 내장되어 있어요.
  • npm install을 실행해 실행 중인 node 컨테이너에 Docusaurus를 설치하고, npm run build를 실행해 사이트를 빌드하세요.
  • Docusaurus는 빌드된 사이트를 build/에 저장하므로 이 파일들을 artifacts로 저장하세요.
build-job:
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

파이프라인 편집기를 사용해 이 파이프라인 설정을 기본 브랜치에 커밋하고 작업 로그를 확인하세요. 다음을 할 수 있어요.

  • npm 명령이 실행되어 사이트를 빌드하는 것을 확인.
  • 끝에 artifacts가 저장되는지 확인.
  • 작업이 완료된 후 작업 로그 오른쪽의 Browse를 선택해 artifacts 파일 내용을 탐색.

사이트를 배포하는 작업 추가하기

build-job에서 Docusaurus 사이트가 빌드되는 것을 확인했다면, 배포하는 작업을 추가할 수 있어요.

이 단계에서 소개하는 것들:

  • stagestages: 가장 일반적인 파이프라인 설정은 작업들을 스테이지로 묶어요. 같은 스테이지의 작업은 병렬로 실행될 수 있고, 이후 스테이지의 작업은 이전 스테이지 작업이 끝날 때까지 기다려요. 어떤 작업이 실패하면 전체 스테이지가 실패한 것으로 간주되고 이후 스테이지의 작업은 실행되지 않아요.
  • GitLab Pages: 정적 사이트를 호스팅하려면 GitLab Pages를 사용해요.

이 단계에서:

  • 빌드된 사이트를 가져와 배포하는 작업을 추가하세요. GitLab Pages를 사용할 때 작업 이름은 항상 pages예요. build-job의 artifacts는 자동으로 가져와 작업에 추출돼요. 하지만 Pages는 public/ 디렉터리에서 사이트를 찾으므로, 사이트를 그 디렉터리로 옮기는 script 명령을 추가하세요.
  • stages 섹션을 추가하고 각 작업의 스테이지를 정의하세요. build-jobbuild 스테이지에서 먼저 실행되고, pagesdeploy 스테이지에서 이후에 실행돼요.
stages:          # List of stages for jobs and their order of execution
  - build
  - deploy

build-job:
  stage: build   # Set this job to run in the `build` stage
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

pages:
  stage: deploy  # Set this new job to run in the `deploy` stage
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"

파이프라인 편집기를 사용해 이 파이프라인 설정을 기본 브랜치에 커밋하고, Pipelines 목록에서 파이프라인 세부 정보를 확인하세요. 다음을 확인하세요.

  • 두 작업이 builddeploy라는 서로 다른 스테이지에서 실행된다는 것.
  • pages 작업이 완료되면 Pages 사이트를 배포하는 GitLab 프로세스인 pages:deploy 작업이 나타난다는 것. 그 작업이 완료되면 새 Docusaurus 사이트를 방문할 수 있어요.

사이트를 보려면:

  1. 왼쪽 사이드바에서 Deploy > Pages를 선택하세요.
  2. Use unique domain이 꺼져 있는지 확인하세요.
  3. Access pages 아래에서 링크를 선택하세요. URL 형식은 https://<my-username>.gitlab.io/<project-name>과 비슷해야 해요. 자세한 내용은 GitLab Pages 기본 도메인 이름을 참고하세요.
  4. 고유 도메인을 사용해야 한다면 docusaurus.config.js에서 baseUrl:을 /로 설정하세요.

테스트 작업 추가하기

이제 사이트가 의도한 대로 빌드되고 배포되므로 테스트와 린팅을 추가할 수 있어요. 예를 들어 Ruby 프로젝트는 RSpec 테스트 작업을 실행할 수 있어요. Docusaurus는 Markdown과 생성된 HTML을 사용하는 정적 사이트이므로, 이 튜토리얼은 Markdown과 HTML을 테스트하는 작업을 추가해요.

이 단계에서 소개하는 것들:

  • allow_failure: 간헐적으로 실패하거나 실패할 것으로 예상되는 작업은 생산성을 떨어뜨리거나 문제 해결을 어렵게 만들 수 있어요. allow_failure를 사용하면 작업이 실패해도 파이프라인 실행을 중단하지 않게 할 수 있어요.
  • dependencies: dependencies를 사용해 어느 작업에서 artifacts를 가져올지 나열함으로써 개별 작업의 artifact 다운로드를 제어할 수 있어요.

이 단계에서:

  • builddeploy 사이에서 실행되는 새 test 스테이지를 추가하세요. 이 세 스테이지는 설정에서 stages가 정의되지 않았을 때의 기본 스테이지예요.
  • markdownlint를 실행하고 프로젝트의 Markdown을 검사하는 lint-markdown 작업을 추가하세요. markdownlint는 Markdown 파일이 포맷 표준을 따르는지 검사하는 정적 분석 도구예요.
    • Docusaurus가 생성하는 샘플 Markdown 파일은 blog/docs/에 있어요.
    • 이 도구는 원본 Markdown 파일만 검사하고 build-job artifacts에 저장된 생성 HTML은 필요하지 않아요. dependencies: []로 작업을 빠르게 만들어 artifacts를 가져오지 않게 하세요.
    • 일부 샘플 Markdown 파일이 기본 markdownlint 규칙을 위반하므로 allow_failure: true를 추가해 규칙 위반에도 불구하고 파이프라인을 계속 실행하게 하세요.
  • HTMLHint를 실행하고 생성된 HTML을 검사하는 test-html 작업을 추가하세요. HTMLHint는 생성된 HTML을 알려진 문제에 대해 검사하는 정적 분석 도구예요.
  • test-htmlpages 모두 build-job artifacts에 있는 생성 HTML이 필요해요. 작업은 기본적으로 이전 스테이지의 모든 작업에서 artifacts를 가져오지만, dependencies:를 추가해 향후 파이프라인 변경 후에도 작업이 다른 artifacts를 실수로 다운로드하지 않게 하세요.
stages:
  - build
  - test               # Add a `test` stage for the test jobs
  - deploy

build-job:
  stage: build
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

lint-markdown:
  stage: test
  image: node
  dependencies: []     # Don't fetch any artifacts
  script:
    - npm install markdownlint-cli2 --global           # Install markdownlint into the container
    - markdownlint-cli2 -v                             # Verify the version, useful for troubleshooting
    - markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"  # Lint all markdown files in blog/ and docs/
  allow_failure: true  # This job fails right now, but don't let it stop the pipeline.

test-html:
  stage: test
  image: node
  dependencies:
    - build-job        # Only fetch artifacts from `build-job`
  script:
    - npm install --save-dev htmlhint                  # Install HTMLHint into the container
    - npx htmlhint --version                           # Verify the version, useful for troubleshooting
    - npx htmlhint build/                              # Lint all markdown files in blog/ and docs/

pages:
  stage: deploy
  dependencies:
    - build-job        # Only fetch artifacts from `build-job`
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"

이 파이프라인 설정을 기본 브랜치에 커밋하고 파이프라인 세부 정보를 확인하세요.

  • lint-markdown 작업은 샘플 Markdown이 기본 markdownlint 규칙을 위반하므로 실패하지만, 실패해도 괜찮게 허용돼요. 다음을 할 수 있어요.
    • 지금은 위반을 무시하세요. 튜토리얼의 일부로 고칠 필요는 없어요.
    • Markdown 파일 위반을 고치세요. 그런 다음 allow_failurefalse로 바꾸거나, 정의하지 않았을 때의 기본 동작이 allow_failure: false이므로 allow_failure를 완전히 제거할 수 있어요.
    • 어떤 규칙 위반에 대해 경고할지 제한하는 markdownlint 설정 파일을 추가하세요.
  • Markdown 파일 내용을 변경하고 다음 배포 후 사이트에서 변경 사항을 확인할 수도 있어요.

머지 리퀘스트 파이프라인 사용 시작하기

이전 파이프라인 설정에서는 파이프라인이 성공적으로 완료될 때마다 사이트가 배포되지만, 이는 이상적인 개발 워크플로가 아니에요. 기능 브랜치와 머지 리퀘스트에서 작업하고, 변경 사항이 기본 브랜치에 병합될 때만 사이트를 배포하는 것이 더 좋아요.

이 단계에서 소개하는 것들:

  • rules: 각 작업에 규칙을 추가해 어떤 파이프라인에서 실행할지 구성해요. 작업을 머지 리퀘스트 파이프라인, 예약 파이프라인, 또는 다른 특정 상황에서 실행하도록 구성할 수 있어요. 규칙은 위에서 아래로 평가되고, 규칙이 일치하면 작업이 파이프라인에 추가돼요.
  • CI/CD 변수: 이 환경 변수를 사용해 설정 파일과 스크립트 명령에서 작업 동작을 구성해요. 사전 정의 CI/CD 변수는 수동으로 정의할 필요가 없는 변수예요. 파이프라인에 자동으로 주입되어 파이프라인 구성에 사용할 수 있어요. 변수는 보통 $VARIABLE_NAME 형식이고, 사전 정의 변수는 보통 $CI_로 시작해요.

이 단계에서:

  • 새 기능 브랜치를 만들고 기본 브랜치 대신 그 브랜치에서 변경하세요.
  • 각 작업에 rules를 추가하세요.
    • 사이트는 기본 브랜치에 대한 변경에만 배포되어야 해요.
    • 다른 작업들은 머지 리퀘스트나 기본 브랜치의 모든 변경에 대해 실행되어야 해요.
  • 이 파이프라인 설정을 사용하면 작업을 실행하지 않고 기능 브랜치에서 작업할 수 있어서 리소스를 절약할 수 있어요. 변경 사항을 검증할 준비가 되면 머지 리퀘스트를 만들고, 머지 리퀘스트에서 실행되도록 구성된 작업으로 파이프라인이 실행돼요.
  • 머지 리퀘스트가 수락되고 변경 사항이 기본 브랜치에 병합되면 pages 배포 작업도 포함된 새 파이프라인이 실행돼요. 어떤 작업도 실패하지 않으면 사이트가 배포돼요.
stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  image: node
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'  # Run for all changes to a merge request's source branch
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH       # Run for all changes to the default branch

lint-markdown:
  stage: test
  image: node
  dependencies: []
  script:
    - npm install markdownlint-cli2 --global
    - markdownlint-cli2 -v
    - markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"
  allow_failure: true
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'  # Run for all changes to a merge request's source branch
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH       # Run for all changes to the default branch

test-html:
  stage: test
  image: node
  dependencies:
    - build-job
  script:
    - npm install --save-dev htmlhint
    - npx htmlhint --version
    - npx htmlhint build/
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'  # Run for all changes to a merge request's source branch
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH       # Run for all changes to the default branch

pages:
  stage: deploy
  dependencies:
    - build-job
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH      # Run for all changes to the default branch only

머지 리퀘스트에서 변경 사항을 병합하세요. 이 작업은 기본 브랜치를 업데이트해요. 새 파이프라인에 사이트를 배포하는 pages 작업이 포함되어 있는지 확인하세요.

앞으로 파이프라인 설정의 모든 변경에는 기능 브랜치와 머지 리퀘스트를 사용하세요. Git 태그 만들기나 파이프라인 예약 추가 같은 다른 프로젝트 변경은 해당 경우에 대한 규칙을 추가하지 않는 한 파이프라인을 트리거하지 않아요.

중복 설정 줄이기

이제 파이프라인에는 모두 동일한 rulesimage 구성을 가진 세 개의 작업이 있어요. 이 규칙들을 반복하는 대신 extendsdefault를 사용해 단일 소스(단일 진실)를 만들어볼게요.

이 단계에서 소개하는 것들:

  • 숨겨진 작업(Hidden jobs): .로 시작하는 작업은 절대 파이프라인에 추가되지 않아요. 재사용하려는 구성을 보관하는 데 사용하세요.
  • extends: 여러 곳에서 구성을 반복하는 데 사용해요. 주로 숨겨진 작업에서 가져와요. 숨겨진 작업의 구성을 업데이트하면 그 작업을 확장하는 모든 작업이 업데이트된 구성을 사용해요.
  • default: 정의되지 않았을 때 모든 작업에 적용되는 키워드 기본값을 설정해요.
  • YAML 재정의: extends 또는 default로 구성을 재사용할 때, 작업에서 키워드를 명시적으로 정의해 extends 또는 default 구성을 재정의할 수 있어요.

이 단계에서:

  • build-job, lint-markdown, test-html에서 반복되는 rules를 담을 .standard-rules 숨겨진 작업을 추가하세요.
  • extends를 사용해 세 작업에서 .standard-rules 구성을 재사용하세요.
  • image 기본값을 node로 정의하는 default 섹션을 추가하세요.
  • pages 배포 작업은 기본 node 이미지가 필요 없으므로 극도로 작고 빠른 이미지인 busybox를 명시적으로 사용하세요.
stages:
  - build
  - test
  - deploy

default:               # Add a default section to define the `image` keyword's default value
  image: node

.standard-rules:       # Make a hidden job to hold the common rules
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

build-job:
  extends:
    - .standard-rules  # Reuse the configuration in `.standard-rules` here
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - "build/"

lint-markdown:
  stage: test
  extends:
    - .standard-rules  # Reuse the configuration in `.standard-rules` here
  dependencies: []
  script:
    - npm install markdownlint-cli2 --global
    - markdownlint-cli2 -v
    - markdownlint-cli2 "blog/**/*.md" "docs/**/*.md"
  allow_failure: true

test-html:
  stage: test
  extends:
    - .standard-rules  # Reuse the configuration in `.standard-rules` here
  dependencies:
    - build-job
  script:
    - npm install --save-dev htmlhint
    - npx htmlhint --version
    - npx htmlhint build/

pages:
  stage: deploy
  image: busybox       # Override the default `image` value with `busybox`
  dependencies:
    - build-job
  script:
    - mv build/ public/
  artifacts:
    paths:
      - "public/"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

머지 리퀘스트를 사용해 이 파이프라인 설정을 기본 브랜치에 커밋하세요. 파일은 더 단순하지만 이전 단계와 동일하게 동작해야 해요.

방금 완전한 파이프라인을 만들고 효율적으로 다듬었어요. 멋지네요! 이제 이 지식을 바탕으로 CI/CD YAML 문법 참조에서 나머지 .gitlab-ci.yml 키워드를 배우고 여러분만의 파이프라인을 만들 수 있어요.

더 알아보기

파이프라인 구성의 핵심 키워드(rules, extends, default, stages)를 익혔다면, CI/CD YAML 문법 참조를 통해 더 다양한 키워드를 살펴보고, 파이프라인 편집기로 설정을 시각적으로 검증하며 파이프라인을 계속 확장해 보시면 좋아요.