CI/CD 파이프라인: 나만의 배포 로봇 설계하기

자동화는 낯선 것이 아니다

지난 시간, 나는 10분의 다운타임과 시말서를 통해 뼈저린 교훈을 얻었다. 배포는 마법이 아니라, ‘Git(기록) – Test(검증) – Build(포장) – Deploy(배달)’로 이어지는 깐깐한 안전장치들의 연속이어야 한다는 것을.

이제 목표는 명확해졌다. 이 복잡하고 귀찮은 안전장치들을 매번 내 손으로 확인할 수는 없다. 내가 퇴근한 후에도, 혹은 휴가를 갔을 때도 대신 일해줄 ‘성실한 로봇’이 필요하다.

“자동화라니, 너무 거창한 거 아니야?”

처음엔 겁부터 났지만, 곰곰이 생각해보니 나는 이미 비슷한 것을 경험했다. 바로 지난 시리즈에서 다뤘던 ‘도커(Docker)’다.

우리가 Dockerfile에 “우분투 깔고, 자바 설치하고, 코드 복사해”라고 적어두면, 도커는 그걸 읽고 알아서 서버 환경을 구축했다. 덕분에 우리는 수동으로 명령어를 치는 노가다에서 해방되었다.

‘CI/CD 파이프라인’도 똑같다. 도커가 ‘서버 세팅’을 자동화한 것이라면, 파이프라인은 ‘배포 프로세스 전체’를 자동화하는 것이다. 단지 그 범위가 내 컴퓨터 안에서 ‘GitLab과 운영 서버’라는 더 큰 무대로 확장되었을 뿐이다.

도커파일이 서버 조립 설명서라면, 파이프라인은 공장 가동 설명서다.

CI/CD: 자동화된 컨베이어 벨트

우리의 ‘디지털 물류 센터’에 이제 ‘자동화 라인’을 깔아보자. 거창해 보이지만 원리는 간단하다.

1. CI (Continuous Integration, 지속적 통합)

  • 의미: “개발자들의 코드를 계속해서 하나로 합치고 검사한다.”
  • 역할: [빌드 + 테스트]. 내가 코드를 올리자마자 기계가 “이거 문법 맞아요?”, “기존 기능 안 망가졌나요?”라고 확인해 주는 단계다. 불량품은 여기서 걸러진다.

2. CD (Continuous Delivery/Deployment, 지속적 배포)

  • 의미: “검사가 끝난 코드를 고객에게 전달한다.”
  • 역할: [이미지 생성 + 서버 배포]. 검사를 통과한 정상 제품(Docker Image)을 트럭에 실어 운영 서버로 보내고, 실행까지 시키는 단계다.

파이프라인의 설계도: .gitlab-ci.yml

“그래서 그 로봇한테 일을 어떻게 시키나요?” GitLab에서는 프로젝트 최상위 경로에 .gitlab-ci.yml이라는 파일 하나만 만들면 된다. 이것이 바로 로봇에게 줄 ‘작업 지시서’다.

지난 시간에 내가 겪었던 수동 배포의 고통을 기억하는가? 그 과정을 그대로 코드로 옮겨보자. 마치 Dockerfile을 짜듯이 한 줄 한 줄 적어내려가면 된다.

# .gitlab-ci.yml (작업 지시서)

stages:          # 1. 전체 작업의 순서를 정의한다.
  - test         #   (1단계: 검사)
  - build        #   (2단계: 포장)
  - deploy       #   (3단계: 배송)

# [1단계] 테스트: 기계야, 내 코드가 멀쩡한지 봐줘 (CI)
unit_test_job:
  stage: test
  image: openjdk:17-alpine # 자바가 깔린 환경에서 실행해
  script:
    - ./gradlew test       # "테스트 코드 돌려!" (지난번 실수 방지)

# [2단계] 빌드: 테스트 통과했으면 이미지로 만들어줘 (CI)
build_image_job:
  stage: build
  image: docker:latest     # 도커가 깔린 환경에서 실행해
  script:
    - docker build -t my-app:v1 .  # "이미지 구워!"
    - docker push my-regisry/my-app:v1 # "창고에 올려!" (롤백용 태그 필수)

# [3단계] 배포: 이제 운영 서버에 갖다 놔줘 (CD)
deploy_job:
  stage: deploy
  script:
    - ssh user@server "docker service update my-app" # "서버 업데이트해!"

이 파일 하나만 있으면 된다. 내가 git push를 하는 순간(Trigger), GitLab은 이 지시서를 읽고 ‘GitLab Runner’라는 일꾼 로봇을 깨워 일을 시킨다.

[Check] 우리가 챙겨야 할 안전장치들

이 파이프라인 안에는 지난 시간에 뼈저리게 느꼈던 ‘3가지 안전장치’가 모두 녹아있다.

  1. Git (Trigger):
    • 내가 로컬에서 코드를 push 하는 행위 자체가 파이프라인의 ‘시작 버튼’이 된다. 기록(Commit)이 남지 않으면 배포도 시작되지 않는다.
  2. Unit Test (Quality Gate):
    • unit_test_job에서 테스트가 실패하면? 파이프라인은 즉시 ‘멈춘다(Fail)’. 불량품이 다음 단계(빌드/배포)로 넘어가는 것을 원천 봉쇄한다. (이제 바쁘다고 테스트 생략 못 한다!)
  3. Docker Image (Artifact):
    • 빌드 단계에서 생성된 이미지는 Docker Hub에 안전하게 저장된다. 나중에 서버가 터져도 이 이미지만 있으면 1초 만에 복구 가능하다.
테스트를 통과하지 못한 코드는 절대로 배포 트럭에 실릴 수 없다.

실무 조언: 파이프라인은 생물이다

처음부터 완벽한 파이프라인을 짜려고 하지 마라. 나도 처음엔 builddeploy 두 단계만 만들었다가, 사고를 치고 나서야 test 단계를 앞에 추가했다.

  • 초기: 빌드 -> 배포 (일단 자동화에 의의를 둠)
  • 중기: 테스트 -> 빌드 -> 배포 (안전장치 추가)
  • 고도화: 테스트 -> 정적분석(SonarQube) -> 빌드 -> 개발서버 배포 -> (승인) -> 운영서버 배포

파이프라인은 우리 팀의 성장 속도에 맞춰 계속해서 진화하는 ‘살아있는 시스템’이다.

마치며: 지시서는 썼는데, 누가 일하지?

이제 완벽한 설계도(.gitlab-ci.yml)가 완성됐다. 하지만 종이에 적힌 지시서가 스스로 움직이진 않는다. 도커파일이 있어도 도커 데몬이 깔려 있어야 실행되듯, 파이프라인 지시서도 실제로 땀 흘려 코드를 빌드하고 실행할 ‘현장직 로봇’이 필요하다.

이 로봇의 이름은 ‘깃랩 러너(GitLab Runner)’다. 공장장(GitLab Server)은 지시만 내릴 뿐, 실제 작업은 이 러너가 수행한다.

다음 시간에는 내 컴퓨터나 별도의 서버에 이 러너를 설치하고, GitLab과 연동하여 실제로 파이프라인을 가동해보자. 드디어 자동화의 첫 단추가 끼워지는 순간이다.

“CI/CD 파이프라인: 나만의 배포 로봇 설계하기”에 대한 2개의 생각

댓글 남기기