이전 포스팅에서 변화에 유연하게 대응하기 위해 TDD(테스트 주도 개발)와 리팩토링이 얼마나 중요한지 알아보았다.

https://hsunnystory.tistory.com/268

 

[Software Enginnering] 애자일(Agile)을 지탱하는 엔지니어링 프랙티스 : XP와 TDD의 본질

이전 포스팅에서 우리는 기획자와 개발자가 유저 스토리를 통해 비즈니스 가치를 어떻게 맞추고 일정을 추정하는지 알아보았다. https://hsunnystory.tistory.com/267 [Sofeware Enginnering] 애자일(Agile) 요구

hsunnystory.tistory.com

 

개발팀이 TDD를 완벽하게 숙달하여 훌륭한 테스트 커버리지를 갖췄다고 가정해 보자. 그런데 기능을 배포하기 위해서버에 SSH로 접속하고, 스크립트를 수동으로 실행하며, DB 스키마를 직접 콘솔에서 반영해야 한다면 어떨까? 배포 과정이 고통스럽고 위험하다면, 팀은 자연스럽게 배포 주기를 한 달에 한번으로 미루게 될 것이다. 한 달에 한번 배포하는 팀은 결코 애자일하다고 할 수 없다.

 

애자일의 핵심은 고객으로 부터 빠른 피드백을 받는 것이다. 그리고 이 피드백 루프를 물리적으로 가능하게 만들어주는 심장 역할이 바로 CI/CD(지속적 통합 및 배포) 파이프라인이다. 이번 포스팅에서는 CI/CD가 실무에 가저오는 극적인 변화를 살펴본다.

 

1. 지속적 통합(Continuos Integration): 머지 지옥(Merge Hell) 탈출하기

워터폴(Waterfall) 시절에는 개발자들이 각자의 브랜치(혹은 로컬)에서 한 달 동안 코드를 짜다가, 릴리즈 전날에 코드를 한 번에 합치는(Merge) 방식을 자주 썼다. 이때 수백 개의 충돌(Conflict)이 발생하고 서버가 기동조차 되지 않는 현상을 우리는 머지 지옥(Merge Hell)이라 부른다.

 

지속적 통합(CI)은 이 지옥을 피하기 위한 전략이다.

 - 개발자는 하루에도 몇 번씩 작은 단위로 코드를 중앙 저장소(Main/Master 브랜치)에 병합한다.

 - 코드가 푸시(Push)될 때마다 CI 서버(GitHub Actions, Jenkins 등)가 자동으로 코드를 빌드하고, 수백개의 단위 테스트를 1분 안에 실행한다.

 - 만약 누군가 짠 코드가 기존 기능을 망가뜨렸다면(테스트 실패), CI 파이프라인은 즉시 빨간불(Red)을 띄우고 병합을 차단한다.

 

즉, CI는 "우리 시스템은 현재 언제든 배포가 가능한, 완벽하게 건강한 상태인가?"를 실시간으로 증명해주는 자동화된 감사관이다.

 

2. 지속적 배포(Continuous Depolyment/Delivery): 작고 빈번한 배포의 마법

"금요일 오후 5시에는 절대 배포하지 마라(No Depoly Friday)" 개발자들 사이에 유행하는 밈이다. 주말에 장애가 터져 출근하는 것을 막기 위함이다.

 

왜 배포가 두려울까? 한 번에 너무 많은 변경 사항을 배포하기 때문이다.

 - 10,000줄의 코드를 한 번에 배포하다 장애가 나면 원인을 찾기 위해 밤을 새워야 한다. (폭발 반경이 큼)

 - 10줄의 코드를 매일 배포하다 장애가 나면, 방금 올린 10줄만 롤백(Rollback)하면 그만이다. (폭발 반경이 작음)

 

지속적 배포(CD) 파이프라인이 구축되어 있다면 코드가 CI(테스트/빌드)를 통과하는 즉시 스테이징 서버나 운영 서버로 자동으로 릴리즈 된다. 작고 빈번한 배포는 배포 자체를 지루하고 일상적인 이벤트로 만들어 주며, 개발자에게 강력한 심리적 안정감을 제공한다.

 

3. [Bad vs Good] 수동 배포와 파이프라인 자동화의 차이

인프라 관점에서 배포라는 행위를 어떻게 다루느냐에 따라 팀의 생산성은 극명하게 갈린다.

 

[Bad] 휴먼 에러를 유발하는 수동 배포 프로세스

과거의 방식이거나 성숙하지 못한 팀은 배포 과정을 사람의 기억력과 수동 스크립트에 의존한다. A가 배포할 때는 성공 했는데, B가 배포할 때는 권한 문제로 서버가 뻗는 식이다.

 - 개발자가 로컬 머신에서 Build 버튼을 누른다.

 - 생성된 .jar 혹은 .war 파일을 FTP 툴로 서버에 업로드 한다.

 - 운영 서버에 SSH로 접속해 기존 프로세스를 kill하고 새 스크립트를 백그라운드로 실행한다.

 - 문제점 : 누군가 로컬에서 테스트를 안 돌리고 빌드했다면? 서버 설정이 미세하게 다르다면? 휴먼 에러가 발생할 확률이 100%다.

 

[Good] 코드화된 인프라와 CI/CD 파이프라인(GitLab CI 예시)

진정한 애자일 팀은 배포 과정 자체를 코드(Infrastructure as Code)로 작성하여 버전 관리를 한다. 개발자가 저장소에 코드를 push 하는 순간, 개발자의 손을 떠나 모든 것이 시스템에 의해 통제된다.

 

아래는 실무에서 쓰이는 아주 심플한 GitLab CI/CD(.gitlab-ci.yml) 워크플로우 예시다.

 

YAML
# .gitlab-ci.yml
# 파이프라인의 실행 단계를 정의한다.
stages:
  - test
  - build
  - deploy

# 1. 단위 테스트 및 검증 (CI)
test_job:
  stage: test
  image: amazoncorretto:17 # 일관된 JDK 환경 보장
  script:
    - ./gradlew clean test
  # 이 단계에서 단위 테스트가 하나라도 실패하면 파이프라인은 즉시 중단(Fail)된다.

# 2. 애플리케이션 빌드 및 도커 이미지 생성 (CD 준비)
build_job:
  stage: build
  image: docker:20.10.16
  services:
    - docker:20.10.16-dind
  script:
    - ./gradlew assemble
    # 빌드된 애플리케이션을 불변(Immutable) 상태인 도커 이미지로 굽는다.
    - docker build -t $CI_REGISTRY_IMAGE/my-backend-api:latest .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push $CI_REGISTRY_IMAGE/my-backend-api:latest
  only:
    - main # main 브랜치에 코드가 병합될 때만 실행

# 3. 운영 서버 자동 배포 (CD)
deploy_job:
  stage: deploy
  image: alpine:latest
  before_script:
    # SSH 접속을 위한 환경 세팅
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
  script:
    # 운영 서버에 접속하여 무중단 배포(Blue-Green 등) 스크립트를 트리거한다.
    - ssh -o StrictHostKeyChecking=no user@production-server "sh deploy.sh"
  only:
    - main

 

이처럼 파이프라인이 코드로 정의되어 있으면, 어떤 개발자가 코드를 작성하든 반드시 모든 테스트를 통과한 격리된 도커 이미지만이 서버에 배포된다는 것을 100% 보장할 수 있다. 작업자의 컨디션이나 실수가 개입할 여지가 원천 차단되는 것이다.

 

4. 결론

CI/CD 파이프라인은 인프라 담당자나 DevOps 엔지니어만의 전유물이 아니다. 자신이 작성한 코드가 어떻게 빌드되고, 어떤 보안 검증을 거쳐, 어떻게 고객의  트래픽을 받는 서버에 안착하는지 그 여정을 완벽히 이해하고 통제하는 것은 실무 엔지니어의 가장 중요한 역량중 하나다.

 

우리는 기획이 계속 바뀌어서 애자일하게 일합니다라고 말하면서, 정작 배포는 수동으로 1~2주에 한 번씩 날을 잡고 하고 있다면 그것은 애자일이 아니다. 요구사항이 하루에 한 번 바뀐다면, 우리는 하루에 세 번 배포할 수 있는 인프라적 체력을 길러야 한다. 자동화된 CI/CD 파이프라인 없이 빠른 피드백을 논하는 것은 허상이다.

 

탄탄한 테스트 코드(TDD)와 자동화된 파이프라인(CI/CD)이라는 쌍발 엔진이 장착될 떄, 백엔드 개발자는 비로소 변경 사항을 두려워하지 않고 비즈니스의 요구를 즐겁게 수용할 수 있게 된다.

+ Recent posts