본문 바로가기

CI/CD 기초 개념 소개

지속적 통합·제공·배포의 차이를 구분하고 React 앱의 변경 검증과 배포를 자동화하는 파이프라인을 이해합니다.

지속적으로 개발하고 배포하는 과정에서 개발 효율을 높이고 안정성을 지키는 데 꼭 필요한 개념이 CI/CD(Continuous Integration / Continuous Delivery·Deployment)입니다. 이 글에서는 CI/CD의 기초 개념을 소개하고, 개발 워크플로에 CI/CD를 왜 넣어야 하는지 설명합니다. React 앱 빌드에서 빌드와 로컬 프리뷰가 무엇을 확인하는지 먼저 떠올려 보세요. CI/CD는 React 전용 API가 아니라 저장소의 변경과 검사, 산출물, 릴리스 조건을 잇는 방식입니다.

commit과 lockfile → 정적 검사·테스트 → production build → preview 확인 → 수동 승인 또는 자동 정책 → 운영과 관찰. 앞 검증 실패는 뒤 배포를 막도록 구성하며, 같은 아티팩트 승격·롤백은 직접 설계하는 절차다.

CI / CONTINUOUS DELIVERY / DEPLOYMENT

검증 후, 수동 승인과 자동 배포를 구분한다

CI는 변경을 자주 통합하고 빌드·테스트로 피드백한다. 검증을 통과한 릴리스를 준비한 뒤 수동 승인으로 운영에 내보내면 지속적 제공, 자동으로 내보내면 지속적 배포다.

검증 후, 수동 승인과 자동 배포를 구분한다commit과 lockfile → 정적 검사·테스트 → production build → preview 확인 → 수동 승인 또는 자동 정책 → 운영과 관찰. 앞 검증 실패는 뒤 배포를 막도록 구성하며, 같은 아티팩트 승격·롤백은 직접 설계하는 절차다.
1. 입력 기록commit · lockfile
연결 관계1. 입력 기록 · commit · lockfile → 2. 검사 · 테스트 · 실패 시 뒤 단계 중지
2. 검사 · 테스트실패 시 뒤 단계 중지
연결 관계2. 검사 · 테스트 · 실패 시 뒤 단계 중지 → 3. production build · dist 아티팩트 생성
3. production builddist 아티팩트 생성
연결 관계3. production build · dist 아티팩트 생성 → 4. preview 검증 · 대표 URL · 기능
4. preview 검증대표 URL · 기능
연결 관계4. preview 검증 · 대표 URL · 기능 → 5. 릴리스 방식 선택 · 수동 승인 / 자동 정책
5. 릴리스 방식 선택수동 승인 / 자동 정책
연결 관계5. 릴리스 방식 선택 · 수동 승인 / 자동 정책 → 6. 운영 + 관찰 · 오류 · 핵심 행동 확인
6. 운영 + 관찰오류 · 핵심 행동 확인

단계와 의존성을 구성해야 실패가 배포를 차단한다

검증과 릴리스 의존 조건의 모바일 흐름입력→검사→빌드→preview→수동 승인 또는 자동 정책→운영 관찰의 여섯 노드와 다섯 간선을 그대로 둔다. 필요한 선행 검증이 실패하면 후속 배포를 차단하도록 별도로 구성한다. 실패 분기와 자동 rollback이 이 선형 그림에 추가로 구현됐다는 뜻은 아니다.1. 입력 기록commit · lockfile2. 검사 · 테스트실패 시 뒤 단계 중지3. production builddist 아티팩트 생성4. preview 검증대표 URL · 기능5. 릴리스 방식 선택수동 승인 / 자동 정책6. 운영 + 관찰오류 · 핵심 행동 확인

CI / FEEDBACK

검증 실패는 수정으로 되돌린다

commit·lockfile로 입력을 기록하고 정적 검사·테스트·빌드의 기준과 순서를 구성한다. 실패 소유자와 재실행 방법을 기록하며, 필요한 앞 단계가 실패하면 뒤 배포가 진행되지 않도록 의존성을 둔다.

ARTIFACT / VERIFY

검증한 결과물을 보존한다

정적 앱의 dist 파일을 아티팩트로 저장한다. 선택한 preview·스테이징에서 대표 URL, 자산, 오류 상태와 접근성을 확인한다. 같은 아티팩트의 승격은 이 그림의 설계 예시다.

CONTINUOUS DELIVERY

준비는 자동화, 운영 배포는 승인

검증된 릴리스를 운영에 내보낼 수 있는 상태로 준비한다. 최종 배포는 사람이 승인하거나 수동으로 시작한다.

CONTINUOUS DEPLOYMENT

기준을 통과하면 운영에 자동 반영

구성한 검사와 정책을 통과하면 별도 수동 승인 없이 운영으로 배포한다. 저장소 연결 자체가 테스트 기준이나 배포 차단 조건을 모두 만들어 주는 것은 아니다.

OBSERVE / ROLLBACK

운영 결과와 복구 대상을 기록한다

release ID·digest와 오류·핵심 사용자 행동을 기록한다. 이전 정상 아티팩트로 돌아갈 정책을 구성하고 확인한다. digest 기록·원자적 전환·자동 롤백은 각 도구에서 직접 구성할 절차다.

이 흐름은 파이프라인 설계 예시다. Netlify·Vercel의 Git 연동이나 GitHub Actions 사용만으로 검사 의존성, 승인, 동일 바이트 승격과 관찰·롤백이 모두 구현됐다고 보지 않는다.

위 그림은 검증한 뒤에 수동 승인과 자동 배포를 나누는 흐름을 보여 줍니다. 그림의 요약처럼 CI는 변경을 자주 통합하고 빌드와 테스트로 피드백을 주며, 검증을 통과한 릴리스를 준비한 뒤 수동 승인으로 운영에 내보내면 지속적 제공, 자동으로 내보내면 지속적 배포입니다. 순서는 commit과 lockfile로 입력을 기록하는 단계, 실패하면 뒤 단계를 멈추는 정적 검사와 테스트, dist 아티팩트(artifact, 파이프라인이 보관해 다음 단계로 넘기는 빌드 산출물)를 만드는 production build, 대표 URL과 기능을 확인하는 preview 검증, 수동 승인이나 자동 정책 가운데 릴리스 방식을 고르는 단계, 오류와 핵심 행동을 확인하는 운영과 관찰의 여섯 단계입니다. 그림의 캡션이 밝히듯 앞의 검증이 실패하면 뒤의 배포를 막도록 의존 관계를 따로 구성해야 하며, 실패 분기와 자동 롤백이 이 선형 그림에 이미 구현되어 있다는 뜻은 아닙니다.

그림 아래의 다섯 칸은 단계마다 할 일을 정리합니다. CI에서는 정적 검사와 테스트, 빌드의 기준과 순서를 정하고, 실패했을 때 누가 고치고 어떻게 다시 실행할지 기록하며, 필요한 앞 단계가 실패하면 배포가 진행되지 않도록 의존 관계를 둡니다. 정적 앱의 dist 파일은 아티팩트로 저장하고, 고른 preview나 스테이징 환경에서 대표 URL과 자산, 오류 상태, 접근성을 확인하며, 같은 아티팩트를 그대로 승격하는 것은 이 그림의 설계 예입니다. 지속적 제공은 검증된 릴리스를 운영에 내보낼 수 있는 상태로 자동 준비하되 최종 배포는 사람이 승인하거나 직접 시작하고, 지속적 배포는 구성한 검사와 정책을 통과하면 별도의 승인 없이 운영으로 배포합니다. 운영 단계에서는 release ID와 digest, 오류와 핵심 사용자 행동을 기록하고, 이전의 정상 아티팩트로 돌아갈 정책을 구성해 확인합니다. 그림의 마지막 설명처럼 이 흐름은 파이프라인 설계의 예이며, Netlify나 Vercel의 Git 연동, GitHub Actions를 쓰는 것만으로 검사 의존성과 승인, 같은 바이트의 승격, 관찰과 롤백이 모두 갖춰지지는 않습니다.


React에서 CI/CD란 무엇인가?

CI/CD는 변경을 통합하고 검사하는 일과 릴리스를 준비하고 배포하는 일을 되풀이할 수 있는 흐름으로 잇습니다. CI만 도입하거나 승인 같은 수동 판단을 남길 수도 있으므로, 모든 단계가 자동이어야 하는 것은 아닙니다. 테스트의 종류에 따라 빌드 전에 검사하거나, 빌드 산출물을 만든 뒤에 검사할 수도 있습니다. CI/CD는 크게 CI(Continuous Integration)와 CD(Continuous Delivery·Deployment)의 두 개념으로 나눌 수 있습니다.

CI (지속적 통합)

지속적 통합(Continuous Integration)은 개발자들이 각자 작업한 코드를 main 브랜치 같은 메인 코드 저장소에 자주, 지속적으로 통합하는 개발 방법입니다. 여러 개발자가 동시에 작업하며 생기는 코드 충돌(merge conflict)을 일찍 발견해 해결하므로 통합 비용이 줄고, 통합된 코드에 단위 테스트나 통합 테스트 같은 자동화된 테스트를 실행해 문제를 빠르게 알아챕니다. 빌드와 테스트를 자동화하면 정해 둔 조건을 되풀이해 확인할 수 있지만, 테스트하지 않은 동작의 품질까지 보증하는 것은 아닙니다.

CI 파이프라인은 일반적으로 네 단계로 이루어집니다. 먼저 개발자가 로컬에서 작업한 코드를 GitHub나 GitLab 같은 원격 Git 저장소에 푸시합니다. 푸시된 코드가 저장소에 통합되면(Pull Request의 병합이나 직접 푸시), Jenkins나 GitHub Actions, GitLab CI 같은 CI 서버가 자동으로 프로젝트를 빌드하며, 이는 React 앱의 npm run build와 비슷한 과정입니다. 빌드가 성공하면 미리 작성한 단위 테스트와 통합 테스트를 실행해 새 코드가 기존 기능을 깨뜨리지 않는지 확인하고, 빌드나 테스트가 실패하면 개발자에게 바로 알려 문제를 고치게 합니다.

CI는 버그를 일찍 발견할수록 고치기 쉽다는 원칙에 기대고 있습니다. 코드가 작게, 자주 통합되고 테스트되면 문제가 생겼을 때 그 원인을 찾아 해결하는 데 드는 시간과 노력을 크게 줄일 수 있습니다.

CD (지속적 제공·배포)

지속적 제공(Continuous Delivery)은 CI 단계를 통과한 코드를 자동으로 릴리스할 수 있는 상태로 준비하는 것을 목표로 합니다. 언제든지 버튼 한 번으로 프로덕션 환경에 배포할 수 있는 상태를 만드는 것입니다. 지속적 배포(Continuous Deployment)는 여기서 한 걸음 더 나아가, CI와 테스트를 모두 통과한 코드를 사람이 개입하지 않고 자동으로 프로덕션 환경에 배포합니다. CD는 새 기능이나 버그 수정이 사용자에게 닿는 시간을 줄이고, 배포 과정을 자동화해 사람의 실수를 줄이며, 배포 전 검증으로 확인한 범위에서 회귀의 위험을 줄입니다.

CI 다음의 CD 파이프라인은 일반적으로 이렇게 이어집니다. 빌드된 결과물(이 장의 Vite SPA라면 dist 폴더의 정적 파일)을 아티팩트로 저장하고, 필요하면 스테이징(Staging)이나 테스트 환경에 자동으로 배포해 마지막 End-to-End 테스트를 합니다. 지속적 제공이라면 프로덕션 환경에 배포하기 전에 수동 승인 단계를 거치고, 지속적 배포라면 모든 테스트를 통과했을 때 자동으로 프로덕션에 배포합니다. 앞 글에서 본 Netlify의 자동 배포가 뒤의 경우에 해당합니다.

둘을 비교하면, 지속적 제공은 배포 준비는 되어 있지만 최종 배포는 버튼 클릭 같은 수동 트리거로 이루어지므로 비즈니스적인 판단이나 추가 수동 검증이 필요할 때 유용합니다. 지속적 배포는 모든 과정이 자동화되어 코드를 Git에 푸시하면 빌드와 테스트, 배포까지 저절로 이루어지므로 가장 빠르지만, 테스트 자동화를 깊이 믿을 수 있어야 합니다. 도입 그림처럼 검증한 아티팩트를 그대로 승격하는 설계에서 digest의 기록과 승인, 배포 뒤의 관찰과 원자적 롤백은 각 CI와 호스팅 환경에서 따로 구성해야 하며, Git 연동만으로 모두 생기는 기능은 아닙니다.


왜 React 앱 개발에 CI/CD가 필요한가?

React 개발에 CI/CD를 도입하면 코드 변경이 빌드되고 테스트되며 배포되는 과정이 자동화되므로, 문제가 생겼을 때 팀이 빠르게 알아채고 고칠 수 있습니다. 자동화된 테스트로 주요 기능의 동작을 되풀이해 확인하므로 배포 전에 회귀의 가능성이 줄고, 손으로 빌드하고 배포하는 데 드는 시간을 아껴 핵심 기능 개발에 집중할 수 있습니다. 모든 개발자가 같은 통합과 배포 과정을 따르므로 코드 통합이 원활해지고 협업의 실수가 줄며, 빌드와 배포 환경이 표준화되어 환경 차이로 생기는 문제도 줄어듭니다. 작은 단위로 자주 배포하므로 문제가 생겨도 빠르게 롤백하거나 고칠 수 있습니다.

앞 글에서 경험한 Netlify의 Git 연동 자동 배포는 사실상 가장 기본적인 형태의 CI/CD입니다. 코드를 Git에 푸시하면 Netlify가 자동으로 빌드(npm run build)하고 배포하는 과정이 바로 지속적 배포의 한 예입니다.


CI/CD 도구 (React 개발 관점)

CI/CD를 구현하는 도구는 여러 가지입니다. Netlify와 Vercel은 Git 연동 빌드와 배포 기능을 제공하며, 자신의 테스트와 승인, 보안 검사를 배포 전에 연결했는지는 실제 설정으로 확인합니다. GitHub Actions는 GitHub가 제공하는 CI/CD 플랫폼으로, .github/workflows 디렉터리에 YAML 파일을 작성해 빌드와 테스트, 배포 같은 자동화 워크플로를 정의하며, React 앱의 단위 테스트 실행과 번들링, Netlify나 Vercel의 배포 트리거에 쓸 수 있습니다. GitLab CI/CD는 GitLab 저장소와 통합된 플랫폼으로 .gitlab-ci.yml 파일로 워크플로를 정의하고, Jenkins는 오래된 CI/CD 서버로 자체 서버를 구축해야 하지만 유연하고 플러그인이 많습니다. 그 밖에 CircleCI나 Bitbucket Pipelines 같은 클라우드 기반 서비스도 있습니다.

React 개발자가 CI/CD를 가장 쉽게 시작하는 방법은 이렇습니다. 먼저 Vite 프로젝트라면 Vitest, 또는 Jest와 React Testing Library 같은 도구로 단위·통합 테스트를 작성하고, package.json의 test 스크립트가 모든 테스트를 실행하도록 설정합니다. 그다음 Netlify나 Vercel을 연동해 Git 저장소에 푸시할 때마다 자동으로 빌드하고 배포되도록 합니다. 필요하면 GitHub Actions로 푸시할 때마다 npm ci, npm test, npm run build를 차례로 실행하고 성공했을 때만 배포를 트리거하는 워크플로를 구성합니다. npm ci는 lockfile에 적힌 버전 그대로 의존성을 설치하는 명령이며, CI에서 npm install 대신 쓰는 이유는 아래의 더 깊이 단락에서 설명합니다.

통과 조건을 먼저 적기

Vite로 앱을 만들었다고 npm test가 저절로 설정되지는 않으므로, package.json에 실제 test 스크립트와 테스트 파일이 있는지 먼저 확인합니다. 테스트가 없는 프로젝트에서는 테스트가 통과했다고 기록하지 않으며, 단위 검사와 빌드, 프리뷰 확인이 각각 무엇을 검사하고 실패하면 어느 단계에서 멈춰야 하는지를 적어 둡니다.

아래 표는 배포 서비스를 부르는 코드가 아니라, 한 릴리스가 지켜야 할 단계 사이의 의존 조건입니다. 검사를 모두 건너뛰고도 Git 연동 배포가 따로 실행된다면, 표의 조건이 구현된 것이 아닙니다.

단계입력과 통과 조건실패한 뒤의 동작
검사고른 commit의 코드와 테스트, 검사 성공그 릴리스를 만들거나 승격하는 다음 단계를 막음
빌드같은 commit에서 산출물 생성, 빌드 성공배포할 새 산출물이 없다고 기록
프리뷰 검증그 산출물의 주소·기능·자산 확인승인과 운영 승격을 막음
릴리스검증한 산출물과 필요한 승인같은 산출물을 운영에 전달하고 이후 응답을 관찰

GitHub Actions의 jobs.needs 문법은 앞의 job이 성공하기를 기다리는 의존 관계를 설명합니다. 실패하거나 건너뛰었을 때도 실행하는 조건을 따로 쓰면 다음 단계가 실행될 수 있으므로, 언제나 실행할 진단·정리 작업과 성공했을 때만 실행할 배포를 구별합니다. 이 글은 실제 워크플로 파일이나 원격 job을 실행한 결과를 보여 주지 않으며, .github/workflows의 YAML 파일로 설치와 검사, 빌드를 실제로 구성하는 예는 CI/CD 파이프라인 구축에서 볼 수 있습니다.

더 깊이: CI에서 의존성을 설치할 때 npm ci를 쓰는 이유

CI의 빌드가 개발자의 컴퓨터와 같은 의존성으로 이루어져야 결과를 믿을 수 있습니다. npm 문서의 npm ci는 이 명령이 npm install과 비슷하지만 테스트 플랫폼과 지속적 통합, 배포 같은 자동화 환경을 위한 것이라고 설명합니다. npm ci는 package-lock.json이나 npm-shrinkwrap.json이 반드시 있어야 하고, lockfile의 의존성이 package.json과 맞지 않으면 lockfile을 고치는 대신 오류로 멈춥니다. 또 이미 있는 node_modules를 지운 뒤 설치하고, package.json이나 lockfile에는 아무것도 쓰지 않습니다.

같은 상황에서 npm install은 lockfile을 고쳐 가며 설치를 이어 가므로, CI에서 쓰면 로컬에서 시험한 것과 다른 버전으로 빌드될 수 있습니다. npm ci는 이런 어긋남을 설치 단계의 실패로 드러내므로, 앞의 표에서 검사 단계를 시작하는 첫 명령으로 알맞습니다. 대신 프로젝트 전체를 한 번에 설치하는 명령이라 패키지 하나를 더하는 용도로는 쓸 수 없으며, 의존성을 바꾸는 일은 로컬에서 npm install로 한 뒤 바뀐 lockfile을 함께 커밋합니다.


정리

  • CI는 코드 변경을 자주 통합하고 자동 빌드와 테스트로 버그를 일찍 발견하는 방법입니다.
  • 지속적 제공은 CI를 통과한 코드를 언제든 배포할 수 있게 준비하고 최종 배포는 사람이 결정하며, 지속적 배포는 검사를 통과하면 자동으로 운영에 배포합니다.
  • 앞 단계의 실패가 뒤의 배포를 막으려면 단계 사이의 의존 관계를 직접 구성해야 합니다.
  • React 앱은 Netlify나 Vercel의 Git 연동 자동 배포로 CI/CD를 쉽게 시작할 수 있지만, 테스트와 승인을 배포 전에 연결했는지는 따로 확인합니다.
  • 같은 commit이라도 다시 빌드한 산출물이 같은 바이트라는 보장은 없으므로, 검증한 산출물을 그대로 승격하는 방식을 검토합니다.

연습 문제

1. 검사 실패와 호스트 배포

단위 검사는 실패했지만 호스트의 Git 연동 빌드는 성공해 사이트가 바뀌었습니다. 이것을 “검사가 성공한 뒤의 배포”라고 할 수 있을까요?

해설 보기

아닙니다. 검사 실패가 호스트의 배포를 막지 못하도록 구성되어 있다는 뜻입니다. 따로 성공한 호스트 빌드가 검사의 실패를 지워 주지는 않으며, 검사의 통과와 배포를 실제 의존 조건으로 이어야 표의 정책이 됩니다.

2. 승인 버튼이 있는 배포

검사와 프리뷰가 통과했고, 담당자가 승인 버튼을 누르면 검증한 산출물을 배포합니다. 이것은 지속적 제공과 지속적 배포 가운데 어느 쪽일까요?

해설 보기

운영 배포에 사람의 결정이 남아 있으므로 지속적 제공의 예입니다. 준비 과정과 배포 명령 자체를 자동화했더라도, 최종 승인에 사람이 필요하다는 점은 같습니다.

3. 같은 commit의 다른 산출물

A 산출물을 프리뷰에서 검증한 뒤, 운영에서는 다시 빌드한 B 산출물을 배포했습니다. 같은 commit이라는 사실만으로 A와 B의 바이트가 같다고 결론 내릴 수 있을까요?

해설 보기

결론 내릴 수 없습니다. 환경 값이나 의존성, 빌드 입력의 차이, 빌드의 재현성 때문에 바이트가 다를 수 있습니다. 같은 commit은 소스가 같다는 것을 알려 줄 뿐, 산출물이 같다는 것을 확인해 주지는 않습니다.

검증한 파일 묶음을 그대로 승격하거나, digest를 기록해 실제 배포 대상과 일치하는지를 따로 확인합니다.

다음 글 React 생태계와 추가 학습 자원 소개에서는 상태 관리와 라우팅, 스타일링, 성능, SSR, TypeScript로 이어지는 React의 다음 학습 경로와 공식 자료를 활용하는 방법을 정리합니다.