CI/CD 학습 노트 목차

CI/CD — 무엇을 자동화하는 것인가

"빌드를 자동으로 돌린다" 가 CI 의 정의가 아니다. 이 편은 CI·CD·CD 가 각각 무엇을 푸는 문제인지부터 정리한다.


1. 세 글자가 각각 다른 문제를 푼다

CI 는 "빌드 자동화" 가 아니다

원래 풀려던 문제는 통합 지옥이다. 각자 브랜치에서 2주씩 작업하면 합칠 때 충돌이 산더미가 되고, 합치고 나니 아무도 예상 못 한 곳이 깨지고, 합치는 데만 며칠이 걸린다.

해법은 자주 합치는 것이다. 하루에 여러 번 합치면 충돌이 작을 때 발견되고, 합칠 때마다 자동으로 검증할 수 있다.

그래서 CI 의 핵심은 자동 빌드가 아니라 통합 주기다. 자동 빌드는 그것을 가능하게 하는 수단일 뿐이다. CI 가 제대로 도는지는 이렇게 판단한다.

  • 메인 브랜치에 하루에 몇 번 합쳐지는가
  • 빌드가 깨진 채로 얼마나 오래 방치되는가
  • 파이프라인이 몇 분 만에 끝나는가

파이프라인이 40분이면 아무도 자주 합치지 않는다. 속도가 곧 CI 의 성패다.

Delivery 와 Deployment 의 차이

  • Continuous Delivery — 언제든 배포할 수 있는 상태를 유지한다. 배포 버튼을 누르는 것은 사람이다
  • Continuous Deployment — 통과하면 자동으로 운영까지 나간다. 사람의 개입이 없다

차이는 마지막 승인이 사람인가 하나뿐이다. 어느 쪽이 옳은가는 상황이 정한다. 자동 배포가 가능하려면 세 가지가 갖춰져야 한다.

  • 테스트를 신뢰할 수 있어야 한다
  • 롤백이 빠르고 확실해야 한다
  • 관측이 충분해 문제를 즉시 알아채야 한다

셋이 안 갖춰진 채로 자동 배포를 켜면 사고가 자동화될 뿐이다.

2. 파이프라인의 표준 모양

다이어그램 로딩 중…
  • 빌드 — 한 번만 한다. 이후 단계는 같은 산출물을 쓴다
  • 테스트 — 단위 → 통합 → E2E 순으로. 빠르고 싼 것부터
  • 분석 — 린트 · 타입 · 취약점 · 시크릿 스캔
  • 아티팩트이미지 · jar · 바이너리. 불변 태그를 붙인다
  • 배포 — 환경별로 승격(promote)한다

"한 번 빌드, 여러 번 배포" 가 원칙이다

dev 브랜치를 dev 에, staging 브랜치를 staging 에, main 을 prod 에 배포하는 구성은 각 환경이 서로 다른 빌드 산출물을 쓰게 만든다. "staging 에서는 됐는데" 가 구조적으로 발생하는 배치다.

커밋 하나로 이미지를 한 번 빌드하고, 같은 다이제스트를 dev → staging → prod 로 승격한다. 환경 차이는 설정(ConfigMap · 환경변수)으로만 표현한다. 이것이 12-factor 의 build/release/run 분리다.

3. 파이프라인을 빠르게 만드는 것들

  • 캐시 — 의존성 캐시가 가장 효과가 크다. 잠금 파일 해시를 키로 쓰면 정확도가 높다
  • 병렬 — 서로 의존하지 않는 잡을 나눈다. 테스트는 샤딩해 여러 러너에 분배한다
  • 변경분만 — 모노레포라면 바뀐 모듈만 빌드한다 (경로 필터 · 빌드 그래프 도구)
  • 빠른 실패 — 싸고 빠른 검사를 앞에 둔다. 린트 10초 → 단위 테스트 2분 → E2E 15분

목표 감각은 PR 파이프라인 10분 이내, 메인 파이프라인 30분 이내다. 10분을 넘기면 사람이 기다리지 않고 다른 일을 시작한다.

느린 파이프라인의 진짜 비용은 기다리는 시간이 아니라 자주 합치지 않게 되는 것이다.

4. 무엇을 자동으로 막을 것인가

파이프라인은 결국 무엇을 통과시키지 않을 것인가 의 목록이다.

게이트판단
빌드 실패막는다
테스트 실패막는다
커버리지 하락기준선 대비 낮아지면 막는다 (절대값보다 변화가 낫다)
린트 오류막는다. 다만 포맷은 자동 수정으로 처리한다
신규 취약점Critical/High 만. 기존 것까지 막으면 도입이 안 된다
시크릿 유출반드시 막는다. 커밋되면 이미 늦다

처음부터 전부 막으면 팀이 우회 경로를 찾는다. 기준선을 정하고 새로 늘어난 것만 막는 것이 정착이 쉽다.

브랜치 보호가 없으면 파이프라인은 권고일 뿐이다

메인에 직접 push 금지, PR 리뷰 승인, 필수 상태 체크 통과 — 이 설정이 저장소에 걸려 있어야 파이프라인이 강제력을 갖는다. 선택적으로 최신 상태 업데이트 후 병합, 서명된 커밋 요구를 더한다.

5. 환경 승격

  • dev — 커밋마다 자동 배포. 깨져도 괜찮다
  • staging — 운영과 최대한 같은 구성. 통합·성능·마이그레이션을 여기서 검증한다
  • prod — 승인 후 배포. 카나리·블루그린으로 위험을 줄인다

환경마다 다른 것은 설정뿐이어야 하고, 이미지는 같은 다이제스트를 쓴다.

그런데 staging 이 운영과 다르면 검증의 의미가 없다. 데이터 규모가 다르면 성능 문제를 못 잡고, 외부 연동이 목(mock)이면 연동 오류를 못 잡고, 노드 사양이 다르면 리소스 문제를 못 잡는다. 전부 같게 만들 수는 없으므로 무엇이 다른지를 명시적으로 적어 두고, 그 차이에서 오는 위험을 카나리와 관측으로 덮는다.

6. 배포 전략

전략특징
재생성(Recreate)전부 내리고 전부 올린다. 중단이 있다
롤링조금씩 교체한다. 구·신 버전이 공존한다
블루-그린전체를 새로 띄우고 한 번에 전환. 롤백이 빠르고 자원이 2배 든다
카나리일부 트래픽만 새 버전으로. 지표를 보고 확대한다

롤링과 카나리는 구·신 버전이 동시에 도는 것을 전제한다. 그래서 데이터 쪽이 먼저 깨진다.

  • DB 컬럼을 지우면 구버전이 죽는다 → 추가 → 양쪽 지원 → 제거 의 3단계로 나눈다 (확장-수축)
  • API 응답 필드를 지우면 구버전 클라이언트가 깨진다
  • 캐시·세션 직렬화 형식이 바뀌면 서로 못 읽는다

"배포는 무중단인데 데이터가 깨진다" 가 여기서 나온다.

기능 플래그로 배포와 출시를 분리한다

배포(deploy)는 코드를 운영에 올리는 것이고, 출시(release)는 사용자에게 기능을 보여 주는 것이다. 기능 플래그를 쓰면 둘을 분리할 수 있다.

  • 코드는 이미 나가 있고 플래그만 끄면 안 보인다
  • 문제가 생기면 재배포 없이 플래그를 끈다 (초 단위 롤백)
  • 일부 사용자에게만 켤 수 있다

대가는 플래그가 쌓이면 코드가 분기 지옥이 된다는 점이다. 만료일을 정하고 정리하는 절차가 함께 있어야 한다.

7. DORA 지표 — 무엇을 좋아지게 할 것인가

지표성격
배포 빈도얼마나 자주 배포하나속도
변경 리드 타임커밋에서 운영까지 얼마나 걸리나속도
변경 실패율배포 중 몇 %가 장애로 이어지나안정성
평균 복구 시간회복에 얼마나 걸리나안정성

흔한 오해는 속도와 안정성이 상충한다는 것이다. 실제로는 함께 좋아진다. 작게 자주 배포하면 한 번의 변경 폭이 작아 원인을 찾기 쉽고, 롤백이 쉽고, 그래서 실패율과 복구 시간이 함께 준다.

"안정성을 위해 배포를 줄인다" 는 대개 반대 결과를 낳는다. 변경이 뭉쳐 커질수록 무엇이 문제인지 찾기 어려워진다.


한눈에 정리

  • CI — 핵심은 자주 합치는 것. 파이프라인이 느리면 아무도 자주 안 합친다
  • Delivery / Deployment — 마지막 승인이 사람인가 아닌가의 차이
  • 빌드 한 번 — 같은 산출물을 환경 간에 승격한다. 환경 차이는 설정으로만
  • 속도 — 캐시 · 병렬 · 변경분만 · 빠른 실패
  • 게이트 — 기준선을 정하고 새로 늘어난 것만 막는다. 브랜치 보호가 없으면 권고일 뿐
  • 배포 전략 — 롤링·카나리는 구·신 공존이 전제다 → 스키마는 3단계로
  • 기능 플래그 — 배포와 출시를 분리한다. 대신 정리 절차가 필요하다
  • DORA — 속도와 안정성은 상충하지 않는다. 함께 좋아진다

출처 — DORA / Accelerate 의 네 지표 · The Twelve-Factor App (build/release/run) · Martin Fowler "Continuous Integration" · GitHub Docs "About continuous integration"

GitHub Actions — 문법과 실행 모델