GitLab CI/CD pipeline 도입기

CI/CD pipeline 도입을 통해 팀의 개발 프로세스를 개선하고 안정성을 높인 경험을 공유합니다.

2024-07-10
  • Frontend

개별 import

배경

이직 후 새로운 환경에서 프로젝트를 파악하던 중, 몇 가지 개선 사항을 시도해 보았습니다. 그중 CI/CD를 도입한 경험은 단순히 편리함과 안정성을 제공하는 것 이상으로 팀의 개발 프로세스에 좋은 변화를 가져다주었기에 공유해보고자 합니다.

프론트엔드 개발 팀은 소수였으며, 디자인 스펙이 자주 변경되어 재개발이 반복되는 상황이었습니다. 빠르게 개발을 진행하기 위해, 작업 내용을 바로바로 master 브랜치에 머지하고 있었습니다. 이 과정에서 문서화와 코드 리뷰가 생략되다 보니, 비교적 코드의 일관성이 떨어졌고 제가 빌드를 시도했을 때는 알 수 없는 지점부터 빌드가 실패하는 상태였습니다.

정해진 주기에 결과물을 QA로 넘기기 전 까지 빌드 상태를 체크하지 않았기 때문에, 나중에 빌드 실패를 해결하려면 많은 비용이 따를 것 같았습니다. 그래서 갑자기 단기간 내에 강력한 규칙을 정하기 보다는 최소한의 안전장치를 마련하는 것이 필요하다고 생각하여, CI 도입을 제안했습니다.

What is CI/CD?

CI 구성

우리 팀은 원격 저장소로 GitLab을 사용하고 있습니다. 사내에 빌드 머신이 없고, GitHub Actions를 전에 활용해 본 경험이 있어 GitLab의 Runner와 GitLab CI를 활용하기로 결정했습니다.

세팅 과정은 간단했습니다. 프로젝트 루트에 .gitlab-ci.yml 파일을 생성하여 필요한 설정을 작성하면 되었습니다.

레포지토리의 Setting > CI/CD > General pipelines에서 설정 파일 경로를 변경할 수도 있습니다.

# Node 20.14를 사용하는 프로젝트이므로 파이프라인 실행 시 사용될 환경을 설정합니다.
image: node:20.14

# pnpm을 사용하는 프로젝트이므로 corepack으로 pnpm을 활성화합니다.
before_script:
  - corepack enable
  - corepack prepare pnpm@latest --activate

# 파이프라인 단계를 정의합니다.
stages:
  - test
  - lint
  - build

# 각 단계에서 실행될 스크립트를 정의합니다.
test-job:
  stage: test
  script:
    - cd apps/mlbland-client
    - pnpm install --frozen-lockfile
    - pnpm run test
    # 모노레포를 사용하고있어서, 해당하는 파일들만 변경 발생 시 job을 실행합니다.
  only:
    changes:
      - apps/mlbland-client/**/*
  interruptible: true

lint-job:
  stage: lint
  script:
    - cd apps/mlbland-client
    - pnpm install --frozen-lockfile
    # 첫 적용 시 모든 warning을 수정하기 어려워서 임시 처리
    - pnpm run lint --max-warnings=1000
  only:
    changes:
      - apps/mlbland-client/**/*
  interruptible: true

build-job:
  stage: build
  script:
    - cd apps/mlbland-client
    - pnpm install --frozen-lockfile
    - pnpm run build
  interruptible: true

stages는 파이프라인의 단계를 정의하는 부분입니다. GitLab에서는 레포지토리 > CI/CD > Pipelines 메뉴에서 파이프라인을 시각적으로 확인할 수 있습니다. pipeline

only changes로 모노레포 구조를 사용 중이므로 특정 디렉토리 내의 파일에 변경이 있을 때만 해당 job이 실행되도록 설정했습니다. 하지만 build-job의 경우 다른 패키지의 영향을 받을 수 있으므로 예외적으로 조건 없이 실행되도록 구성했습니다.

각 파이프라인과 job이 실행될 때마다 종속성 파일을 다시 설치해야 합니다. 하지만 종속성 파일에 변경이 없을 경우 불필요하게 설치하는 것은 파이프라인 실행 시간을 낭비하게 됩니다. 특히 GitLab에서 제공하는 Runner는 월간 사용량 제한이 있기 때문에, 이를 최적화하기 위해 캐시를 설정해 시간을 절약할 수 있습니다.

# 종속성 설치 시간을 줄이기 위해 node_modules를 캐시합니다.
# pnpm-lock.ymlrhk package.json이 변경되지 않으면 캐시된 종속성을 사용합니다.
cache:
  key:
    files:
      - pnpm-lock.yaml
      - apps/mlbland-client/package.json
  paths:
    - node_modules
    - apps/mlbland-client/node_modules

기본적으로 원격 저장소에 Push 발생 시 파이프라인 실행을 트리거하는 기본값을 유지했습니다. 팀 전략에 따라 Pull Request가 발생할 때 파이프라인을 트리거할 수도 있지만, 우리는 Push 시 트리거되도록 유지했습니다.

이렇게 하면 PR 시 빌드가 성공했는지 빠르게 확인할 수 있고, 같은 브랜치에서 여러 번 Push할 경우 중복된 파이프라인이 실행되지 않도록 옵션을 설정할 수 있습니다. interruptible: true 옵션을 사용하여 이전에 실행 중이던 파이프라인을 중단시킬 수 있습니다.

CD 구성

stages:
  - test
  - lint
  - build
  # deploy 단계 추가
  - deploy

deploy-template:
  stage: deploy
  extends: .default-instance-job
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2375/
    DOCKER_TLS_CERTDIR: ""
  before_script:
    - apt-get update
    - apt-get install -y docker.io awscli
    - aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID"
    - aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY"
    - if [ "$STAGE" = "qa" ]; then export AWS_REGION=""; else export AWS_REGION=""; fi
    - aws configure set region "$AWS_REGION"
  script:
    - npm run docker:build:$STAGE
    - npm run docker:push:$STAGE
    - cd apps/mlbland-client/cdk
    - npm install
    - npm run deploy:$STAGE
  when: manual
  needs: ["build-job"]

deploy-dev-job:
  extends: deploy-template
  variables:
    STAGE: "dev"

deploy-alpha-job:
  extends: deploy-template
  variables:
    STAGE: "alpha"

deploy-qa-job:
  extends: deploy-template
  variables:
    STAGE: "qa"

레포지토리 > CI/CD > Pipelines 메뉴에서 원하는 파이프라인의 빌드까지 성공적으로 실행되었으면, deploy를 수동으로 실행할 수 있습니다. pipeline

도입 효과

안정성

각 브랜치에서 Push할 때마다 빌드 검사를 통해 즉시 문제를 발견하고 수정할 수 있게 되었습니다. 만약 실수를 놓치더라도, 빌드 실패 시점이 기록에 남아 있어 어느 순간부터 문제가 발생했는지 쉽게 추적할 수 있습니다.

편리성

이전에는 로컬에서 직접 빌드를 하고, AWS 설정이 완료된 머신에서 CLI로 배포 작업을 해야 했습니다. 번거로울 뿐만 아니라 문서화가 미흡해, 새로 들어온 사람이 환경을 설정하는 데 많은 시간이 소요될 것 같았습니다. 이제는 파이프라인에서 버튼 클릭만으로 원하는 서버에 배포할 수 있게 되어 이런 불편함이 크게 줄었습니다. 더 나아가 파이프라인에서 배포도 자동으로 진행되게 설정하면, 배포 과정까지 완전히 자동화할 수 있습니다.

코드 리뷰 도입

빌드가 성공한 후에만 머지할 수 있도록 규칙을 설정했는데, 이 과정에서 자연스럽게 Pull Request로 코드 리뷰를 진행하는 흐름이 정착되었습니다.

생산성 향상

누구나 안정적인 버전을 쉽게 배포할 수 있게 되면서, 배포 주기가 짧아졌습니다. 그 덕분에 디자이너와 기획자에게 결과물을 빠르게 공유하고 피드백을 받아, 최종 결과물의 오차를 최소화할 수 있었습니다.


이러한 도입을 통해 코드 리뷰, 머지 규칙 등 개발 프로세스를 개선할 수 있었고, 그동안 미뤄왔던 체계가 잡혀나가며 팀원들의 긍정적인 피드백도 받았습니다.

추가 정보

gitlab-ci-local

https://github.com/firecow/gitlab-ci-local
기존에는 gitlab-ci.yml 설정을 테스트하려면 원격 저장소로 푸시하여 트리거를 발생시키고 확인해야 했습니다. 하지만 gitlab-ci-local을 사용하면, 로컬 환경에서 원하는 Job을 바로 테스트할 수 있어 더 빠르고 편리하게 작업할 수 있습니다.

Profile picture

Cony Choi

Frontend Developer