🔧 CI/CD 파이프라인 구축

180

왜 CI/CD 파이프라인을 구축해야 할까?

어느 스타트업의 이야기입니다. 개발자 5명이 열심히 코드를 작성합니다. 기능 개발은 빠릅니다. 하지만 배포가 문제입니다.

CI/CD 파이프라인을 공장 조립 라인으로 비유한 개요도

매주 목요일 저녁, "배포 담당자"로 지정된 개발자가 다음 과정을 수동으로 수행합니다. 서버에 SSH 접속 → git pullnpm installnpm run build → PM2 재시작 → 브라우저에서 확인 → 문제 발생 시 롤백. 이 과정이 순조로우면 30분, 문제가 생기면 2시간입니다. 그리고 문제는 항상 생깁니다.

"내 로컬에서는 잘 됐는데..." 개발자라면 한 번쯤 해본 말입니다. 로컬 환경과 서버 환경의 Node.js 버전이 다르거나, 환경 변수 하나가 빠졌거나, 의존성 충돌이 발생하거나. 수동 배포는 인간의 실수를 허용하는 시스템입니다.

CI/CD 파이프라인은 이 모든 과정을 자동화합니다. 개발자가 git push를 하는 순간, 코드는 자동으로 빌드되고, 테스트를 통과하고, 스테이징 환경에 배포됩니다. 승인 버튼 하나를 클릭하면 프로덕션까지 자동 배포. 사람의 손이 닿을 일이 없으니 실수도 없습니다.

이 실습에서는 AWS의 4가지 개발자 도구를 조합하여 완전 자동화된 파이프라인을 직접 구축합니다:

  • CodeCommit: 소스 코드 저장소 (Git 호스팅)
  • CodeBuild: 빌드 및 테스트 자동화
  • CodeDeploy: EC2/ECS에 코드 자동 배포
  • CodePipeline: 위 3가지를 연결하는 오케스트레이터

파이프라인이 완성되면, git push 한 번으로 코드가 프로덕션까지 자동으로 흘러갑니다. "배포 담당자" 역할은 사라지고, 모든 개발자가 매일 안전하게 배포할 수 있게 됩니다.

실습을 시작하기 전에 AWS 콘솔에 로그인되어 있는지 확인하세요. 리전은 ap-northeast-2 (서울) 을 사용합니다. Git 클라이언트가 로컬에 설치되어 있어야 합니다.

아키텍처 개요

CI/CD 파이프라인 5단계 — 소스부터 프로덕션까지

파이프라인 흐름

다이어그램 로딩 중...
CodePipeline 기반 CI/CD 자동화 흐름

비용 예측

비용 계산기

4시간
0h24h
CodeBuild (build.general1.small)

빌드 분

$0.0200
CodePipeline

파이프라인당 $1/월

$0.0400
CodeCommit (5 사용자 무료)

시간당 과금

$0.0400
예상 총 비용$0.1000

* 실제 비용은 AWS 요금 정책에 따라 달라질 수 있습니다.

Step 1: CodeCommit 리포지토리 생성

CodeCommit은 AWS가 관리하는 프라이빗 Git 호스팅 서비스입니다. GitHub와 비슷하지만 AWS IAM과 완전히 통합되어 있어, AWS 계정의 인증/인가 체계를 그대로 사용할 수 있습니다. 팀원별로 특정 리포지토리에만 접근을 허용하는 것도 IAM 정책 하나로 가능합니다.

HTTPS(GRC) 자격 증명은 AWS 콘솔에서 IAM → 사용자 → 보안 자격 증명 탭에서 생성할 수 있습니다. Git 명령 실행 시 이 자격 증명으로 인증됩니다.

  1. AWS 콘솔 → CodeCommit → 리포지토리 생성 클릭
  2. 리포지토리 이름: lab-cicd-app
  3. 설명: CI/CD 파이프라인 실습용 리포지토리
  4. 생성 클릭
  5. HTTPS(GRC) 자격 증명 설정 후 로컬에 클론
코드
aws codecommit create-repository \
  --repository-name lab-cicd-app \
  --repository-description "CI/CD 파이프라인 실습용 리포지토리"
 
git clone https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/lab-cicd-app
cd lab-cicd-app

CodeCommit 대신 GitHub를 소스로 사용할 수도 있습니다. CodePipeline은 GitHub, Bitbucket, S3 등 다양한 소스를 지원합니다.

Step 2: buildspec.yml 작성

buildspec.yml은 CodeBuild에게 "무엇을 어떤 순서로 실행할지"를 알려주는 설정 파일입니다. 4개의 빌드 단계(phase)가 순서대로 실행되며, 하나라도 실패하면 빌드가 중단됩니다. 각 단계의 역할을 명확히 이해하는 것이 중요합니다.

  • install: 런타임 버전 지정과 의존성 설치. npm cinpm install보다 빠르고 재현성이 높습니다.
  • pre_build: 테스트 실행. 테스트가 실패하면 빌드 자체가 중단되어 불량 코드가 배포되지 않습니다.
  • build: 실제 빌드. React라면 npm run build, Next.js라면 next build 등을 실행합니다.
  • post_build: 빌드 결과 정리. 타임스탬프 기록, 알림 전송 등에 사용합니다.
진행률 0/6
  1. 1리포지토리 루트에 buildspec.yml 파일 생성
  2. 2phases → install: 런타임 및 의존성 설치
  3. 3phases → pre_build: 테스트 실행
  4. 4phases → build: 애플리케이션 빌드
  5. 5phases → post_build: 아티팩트 패키징
  6. 6artifacts 섹션: 빌드 결과물 지정
코드
version: 0.2
phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - npm ci
  pre_build:
    commands:
      - echo "테스트 실행 중..."
      - npm test
  build:
    commands:
      - echo "빌드 시작: $(date)"
      - npm run build
  post_build:
    commands:
      - echo "빌드 완료: $(date)"
artifacts:
  files:
    - '**/*'
  base-directory: dist

Step 3: CodeBuild 프로젝트 생성

CodeBuild는 완전 관리형 빌드 서비스입니다. 빌드를 위한 서버를 직접 관리할 필요가 없습니다. 빌드가 실행될 때만 컨테이너가 생성되고, 빌드가 끝나면 자동으로 정리됩니다. Jenkins 서버를 직접 운영하는 것에 비해 관리 부담이 제로입니다.

빌드 환경 이미지로 amazonlinux2-x86_64-standard:5.0을 선택하면 Node.js, Python, Java, Go 등 대부분의 런타임이 사전 설치되어 있습니다. build.general1.small은 3 GB 메모리를 제공하며, 간단한 Node.js 빌드에 충분합니다.

  1. AWS 콘솔 → CodeBuild → 빌드 프로젝트 생성 클릭
  2. 프로젝트 이름: lab-cicd-build
  3. 소스: CodeCommit, 리포지토리: lab-cicd-app, 브랜치: main
  4. 환경: 관리형 이미지, Amazon Linux 2, 표준 런타임
  5. 빌드 사양: buildspec.yml 사용
  6. 아티팩트: S3 버킷에 저장
  7. 빌드 프로젝트 생성 클릭
코드
aws codebuild create-project \
  --name lab-cicd-build \
  --source "type=CODECOMMIT,location=https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/lab-cicd-app" \
  --environment "type=LINUX_CONTAINER,computeType=BUILD_GENERAL1_SMALL,image=aws/codebuild/amazonlinux2-x86_64-standard:5.0" \
  --service-role arn:aws:iam::<ACCOUNT_ID>:role/codebuild-service-role \
  --artifacts "type=S3,location=lab-cicd-artifacts"

Step 4: appspec.yml 작성

appspec.yml은 CodeDeploy에게 "파일을 어디에 복사하고, 배포 전후에 어떤 스크립트를 실행할지"를 알려주는 설정 파일입니다. buildspec.yml이 빌드 과정을 정의한다면, appspec.yml은 배포 과정을 정의합니다.

hooks 섹션의 라이프사이클 이벤트를 활용하면, 배포 전에 기존 서버를 안전하게 중지하고, 배포 후 의존성을 설치하고, 새 서버를 시작하는 것까지 자동화할 수 있습니다.

진행률 0/5
  1. 1리포지토리 루트에 appspec.yml 파일 생성
  2. 2version: 0.0 지정
  3. 3os: linux 지정
  4. 4files 섹션: 소스 → 대상 경로 매핑
  5. 5hooks: BeforeInstall, AfterInstall, ApplicationStart 스크립트 지정
코드
version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/app
hooks:
  BeforeInstall:
    - location: scripts/stop_server.sh
      timeout: 300
  AfterInstall:
    - location: scripts/install_dependencies.sh
      timeout: 300
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300

hooks 스크립트의 실행 권한 누락 주의! scripts/ 디렉토리의 쉘 스크립트에 실행 권한이 없으면 CodeDeploy가 실패합니다. Git에 커밋하기 전에 반드시 chmod +x scripts/*.sh를 실행하세요. 리포지토리에서 파일 권한은 git update-index --chmod=+x scripts/start_server.sh로 설정할 수 있습니다.

Step 5: CodeDeploy 애플리케이션 생성

CodeDeploy는 EC2, ECS, Lambda 등 다양한 컴퓨팅 대상에 코드를 자동으로 배포하는 서비스입니다. 태그 기반으로 배포 대상 인스턴스를 지정하므로, Name=lab-server 태그가 붙은 EC2 인스턴스에만 코드가 배포됩니다.

배포 대상 EC2에는 CodeDeploy Agent가 미리 설치되어 있어야 합니다. Agent가 CodeDeploy 서비스와 통신하여 배포 명령을 수신하고 실행합니다.

  1. AWS 콘솔 → CodeDeploy → 애플리케이션 생성 클릭
  2. 애플리케이션 이름: lab-cicd-deploy
  3. 컴퓨팅 플랫폼: EC2/온프레미스
  4. 배포 그룹 생성: lab-deploy-group
  5. 서비스 역할: CodeDeploy 서비스 역할 선택
  6. 배포 유형: 인플레이스(In-Place)
  7. 환경 구성: 태그 기반으로 EC2 인스턴스 지정
코드
aws deploy create-application \
  --application-name lab-cicd-deploy \
  --compute-platform Server
 
aws deploy create-deployment-group \
  --application-name lab-cicd-deploy \
  --deployment-group-name lab-deploy-group \
  --service-role-arn arn:aws:iam::<ACCOUNT_ID>:role/codedeploy-service-role \
  --ec2-tag-filters Key=Name,Value=lab-server,Type=KEY_AND_VALUE

Step 6: CodePipeline 연결

CodePipeline은 앞서 만든 CodeCommit, CodeBuild, CodeDeploy를 하나의 흐름으로 연결하는 오케스트레이터입니다. 소스 리포지토리에 변경이 감지되면 자동으로 파이프라인을 시작하고, 각 단계를 순서대로 실행합니다. 하나의 단계가 실패하면 이후 단계는 실행되지 않습니다.

진행률 0/6
  1. 1AWS 콘솔 → CodePipeline → 파이프라인 생성 클릭
  2. 2파이프라인 이름: lab-cicd-pipeline
  3. 3소스 단계: CodeCommit → lab-cicd-app → main 브랜치
  4. 4빌드 단계: CodeBuild → lab-cicd-build 프로젝트
  5. 5배포 단계: CodeDeploy → lab-cicd-deploy 애플리케이션
  6. 6파이프라인 생성 클릭하여 첫 실행 확인

Step 7: 수동 승인 단계 추가

수동 승인 단계는 프로덕션 배포 전 "마지막 관문" 역할을 합니다. 빌드가 성공하더라도 비즈니스 검증이나 QA 확인이 필요한 경우, 담당자가 확인 후 승인해야 다음 단계로 넘어갑니다. 승인 요청은 SNS를 통해 이메일이나 Slack으로 알릴 수 있습니다.

개발/스테이징 환경에서는 승인 단계를 생략하고, 프로덕션 파이프라인에만 추가하는 것이 일반적입니다. 이렇게 하면 개발 속도를 유지하면서도 프로덕션 안전성을 확보할 수 있습니다.

진행률 0/7
  1. 1파이프라인 → 편집 클릭
  2. 2빌드 단계와 배포 단계 사이에 스테이지 추가
  3. 3스테이지 이름: Approval
  4. 4작업 공급자: 수동 승인
  5. 5SNS 주제 ARN: (선택사항) 알림 설정
  6. 6검토 URL 및 코멘트 입력
  7. 7완료 클릭 후 파이프라인 저장

수동 승인 단계는 프로덕션 배포 전 검증 게이트로 활용됩니다. 개발/스테이징 환경에서는 생략하고, 프로덕션에서만 적용하는 것이 일반적입니다.

Step 8: 파이프라인 테스트

파이프라인이 완성되었으면 실제로 코드를 변경하여 전체 흐름을 검증합니다. 단순히 파이프라인이 "녹색"으로 성공하는지만 보는 것이 아니라, 배포된 EC2에서 실제 애플리케이션이 정상 동작하는지까지 확인해야 합니다.

진행률 0/5
  1. 1로컬에서 코드 수정 후 git push 실행
  2. 2CodePipeline 콘솔에서 파이프라인 실행 상태 확인
  3. 3소스 → 빌드 → 승인 → 배포 단계별 진행 확인
  4. 4승인 단계에서 승인/거부 선택
  5. 5배포 성공 후 EC2에서 애플리케이션 동작 확인
✏️

본인의 말로 설명해 보세요

CI(지속적 통합)와 CD(지속적 배포)의 차이를 동료에게 설명해보세요.

💡 CI는 코드를 합칠 때마다 자동 빌드+테스트. CD는 테스트를 통과한 코드를 자동으로 프로덕션에 배포. CI 없는 CD는 위험하고, CD 없는 CI는 미완성...

트러블슈팅 가이드

CodeBuild 빌드가 실패하는 경우

  • CloudWatch Logs에서 빌드 로그를 확인하세요. 대부분 npm ci 단계에서 의존성 충돌이 원인입니다.
  • buildspec.yml의 런타임 버전이 프로젝트의 package.json engines 필드와 일치하는지 확인하세요.
  • CodeBuild 서비스 역할에 S3(아티팩트 저장)와 CloudWatch Logs(로그 저장) 권한이 있는지 확인하세요.

CodeDeploy 배포가 실패하는 경우

  • EC2 인스턴스에 CodeDeploy Agent가 설치되어 실행 중인지 확인하세요: sudo service codedeploy-agent status
  • EC2 인스턴스의 IAM 역할에 S3 읽기 권한이 있는지 확인하세요. CodeDeploy는 S3에서 아티팩트를 다운로드합니다.
  • appspec.yml의 hooks 스크립트가 실행 권한(chmod +x)을 가지고 있는지 확인하세요.

파이프라인이 소스 변경을 감지하지 못하는 경우

  • CodePipeline의 소스 단계가 올바른 리포지토리와 브랜치를 가리키는지 확인하세요.
  • CloudWatch Events 규칙이 정상 생성되었는지 확인하세요. CodePipeline 생성 시 자동으로 규칙이 만들어지지만, 간혹 권한 문제로 생성에 실패할 수 있습니다.

핵심 개념 확인

완성 후 테스트 가이드

진행률 0/5
  1. 1기본 플로우 테스트: README.md에 한 줄 추가 후 git push. 파이프라인이 자동 시작되고 모든 단계가 성공하는지 확인합니다.
  2. 2빌드 실패 테스트: 의도적으로 테스트를 실패시키는 코드를 push합니다. pre_build에서 파이프라인이 중단되고 배포가 진행되지 않는지 확인합니다.
  3. 3승인 거부 테스트: 수동 승인 단계에서 "거부"를 클릭합니다. 배포 단계로 넘어가지 않는지 확인합니다.
  4. 4롤백 테스트: 정상 배포 후 오류 코드를 배포하고, EC2에서 이전 버전이 동작하는지 확인합니다.
  5. 5동시 실행 테스트: 빠르게 두 번 git push하여 파이프라인 동시 실행 시 동작을 확인합니다 (기본적으로 직렬 실행).

확장 아이디어

  1. GitHub 소스 연동: CodeCommit 대신 GitHub를 소스로 연결합니다. GitHub App 또는 OAuth 토큰으로 연동할 수 있습니다.
  2. 병렬 빌드: CodeBuild에서 여러 환경(Node 18, Node 20)의 빌드를 병렬로 실행하여 호환성을 검증합니다.
  3. 슬랙 알림 연동: SNS → Lambda → Slack Webhook으로 빌드 성공/실패/승인 요청을 실시간 알림합니다.
  4. Docker 이미지 빌드: buildspec.yml에서 Docker 이미지를 빌드하고 ECR에 push하는 과정을 추가합니다.
  5. 멀티 환경 파이프라인: dev → staging → production 3단계 환경에 순차 배포하는 파이프라인을 구성합니다.

학습 정리

핵심 치트시트

리소스 정리

실습 완료 후 반드시 아래 순서대로 리소스를 정리하여 불필요한 과금을 방지하세요.

  1. CodePipeline 파이프라인 삭제
  2. CodeDeploy 배포 그룹 및 애플리케이션 삭제
  3. CodeBuild 프로젝트 삭제
  4. CodeCommit 리포지토리 삭제
  5. S3 아티팩트 버킷 비우기 및 삭제
  6. IAM 서비스 역할 삭제 (CodeBuild, CodeDeploy, CodePipeline)
  7. EC2 인스턴스 종료 (사용한 경우)
  8. SNS 주제 삭제 (생성한 경우)