개발괴발/Devops

[Github Actions] CI/CD, 배포 자동화하기

nourzoo 2025. 7. 22. 10:02

 

 

데모데이 2차까지 요구사항 중 CI 스크립트 등을 활용한 배포 자동화가 있었다.

CI/CD의 대표적인 도구인 github action을 사용하기로 했다. 

젠킨스도 있었지만, 러닝커브가 적고 서버를 따로 구축할 필요가 없는 깃허브 액션을 사용하기로 했다.

Continuous Integration (CI)

  • CI(지속적인 통합)는 개발자들이 작업한 코드를 자동으로 테스트하고 병합하는 과정.

✔️ 핵심 개념

  • Integration(통합): 여러 개발자가 각자 만든 코드를 feature 브랜치에서 develop 브랜치로 병합(merge)하는 것
  • CI는 이 병합 과정에서 테스트와 빌드, 리뷰를 자동화한다.

✔️ 예시 흐름

  1. 개발자는 새로운 검색 기능을 구현하기 위해 feature/search 브랜치를 생성한다.
  2. 기능 개발이 완료되면 해당 브랜치에 커밋한다.
  3. 커밋 후 자동으로 빌드와 유닛 테스트가 실행된다.
  4. 테스트가 통과하면 코드 리뷰(PR)를 거쳐 develop 브랜치에 머지한다.
  5. 머지 후 다시 develop 브랜치에서도 자동으로 테스트가 실행되어 정상 병합 여부를 확인한다.

✔️ CI의 역할

  • 위 과정 중 3~5번 단계를 자동화한다.
  • 즉, 개발자가 코드를 푸시하면 자동으로 테스트 → 리뷰 → 머지까지 빠르게 진행된다.
  • 이 덕분에 하루에도 여러 번 테스트와 통합이 가능하다.

 

Continuous Delivery/Deployment (CD)

  • CD(지속적인 배포)는 CI 이후의 과정인 테스트 완료된 코드를 실제 서비스 서버에 자동 배포하는 것을 말한다.
  • 종류
    • Continuous Delivery (지속적인 제공)
      • 모든 변경 사항이 자동 테스트를 거쳐 언제든지 배포 가능한 상태로 유지
      • 배포는 수동으로 트리거함 (예: 운영자가 버튼 클릭)
    • Continuous Deployment (지속적인 배포)
      • 변경 사항이 테스트를 통과하면 자동으로 운영 환경에 배포
      • 별도의 수동 승인 없이 풀 자동화된 배포
  • 우리가 택한 방식
    • dev 브랜치에서 Continuous Deployment (지속적인 배포) 수행
      • 수동으로 트리거하지 않고, 자동으로 머지된 코드가 배포되도록 설정

✔️ 핵심 개념

  • develop 브랜치에 머지된 코드가 자동으로 스테이징 → 프로덕션으로 이어지며 배포된다.
  • CI가 통합까지 자동화했다면, CD는 배포까지 자동화한다.

✔️ 예시 흐름

  1. 최신 코드를 Staging 서버에 배포한다.
  2. Staging 환경에서 아래와 같은 다양한 테스트를 자동으로 실행한다:
    • Integration Test
    • E2E (End-To-End) Test
    • Load Test 등
  3. 모든 테스트를 통과하면 Production 서버에 자동으로 배포하고, main(master) 브랜치에 머지한다.

✔️ CD의 역할

  • Staging 테스트부터 실제 배포까지 모든 과정을 자동화한다.
  • 개발자는 단순히 코드를 커밋하고 푸시하기만 해도, 프로덕션 배포까지 자동으로 이루어진다.

 

Github Action

# .github/workflows/test.yml

name: CI Test Workflow   # 워크플로 이름

on: [push, pull_request] # 이 이벤트가 발생하면 전체 Workflow 실행

jobs:
  test-job:
    ...
    
------------

on:
  push:
    branches:
      - dev       # dev에 머지되면 스테이징 배포
      
------------

on:
  push:
    branches:
      - main      # main에 머지되면 프로덕션 배포
      
------------
      
on:
  push:
    branches:
      - main            # main에 push될 때만 실행됨
  pull_request:
    branches:
      - dev             # dev로 향하는 PR만 실행됨
  • Job
    • 병렬적으로 수행되거나 순차적으로 수행되어야 하는 작업 단위
    • Jobs를 실행하기 위해서는 작업 환경을 정의해야하는데, 이를 Runner라고 지칭한다.
    • 작업 환경을 정의하는 키워드는 runs-on을 통해 설정 가능하다.
jobs:
  test-job:                     # Job 이름
    name: Run Tests
    runs-on: ubuntu-latest      # Ubuntu 환경에서 실행

    steps:
      ...
  • Step
    • Job에 포함되며 Shell Script나 Action이 실행된다.
    • Shell Script는 terminal에서 수행되는 명령어의 집합 등
    • Action은 Github Actions에서 미리 정의한 script
steps:
  - name: Checkout repository   # Action
    uses: actions/checkout@v4

  - name: Run tests             # Shell Script
    run: yarn test

 

GitHub Actions에서 CI 트리거 이벤트

  • CI 실행 시점
상황 CI 실행 여부  트리거 이벤트
PR 생성 ✅ 실행됨 pull_request
브랜치에 직접 push ✅ 실행됨 push
PR을 머지함 ✅ 실행됨 push (머지 브랜치로)

 

→ 즉, merge 자체를 감지하는 트리거는 없고,

머지 시 해당 브랜치에 커밋이 생기므로 push로 감지됨.

push 트리거를 쓰는 이유

  • 꼭 PR 기반 협업이 아닐 수도 있기 때문
    • 개인 개발자나 소규모 팀은 PR 없이 바로 브랜치에 커밋하거나 머지하는 경우가 있음
  • PR 머지 후의 상태도 확인하려고
    • PR을 merge하면 결국 브랜치(dev, main 등)에 push가 발생함
    • 이 상태에서도 CI 테스트를 다시 실행해주는 게 안정적임
  • PR 간 충돌로 인해 머지 후 에러를 방지하려고
    • 예: 두 개의 PR이 따로는 테스트 통과했지만, 머지된 후엔 충돌로 인해 깨질 수 있음
    • push 트리거로 머지 이후 dev 상태를 다시 확인 가능
  • 실제 설정 예시 (YAML)
on:
  push:
    branches: [dev, main]
  pull_request:
    branches: [dev, main]

 

우리가 선택한 워크플로우 규칙

자세한 코드는 깃허브를 참고해주세요 :)

  • dev-be 브랜치
    • PR을 생성하거나 dev-be에 직접 푸시하면 CI만 실행됨
    • 즉, 빌드/ 테스트만 수행한다. 배포는 하지 않는다.
  • dev 브랜치
    • dev 브랜치에 푸시(= PR 머지 포함)되면 CI + CD 모두 실행
    • 즉, 빌드 후 EC2 서버에 자동 배포됨
단계 목적 자동화 동작
feat/*  dev-be (PR 생성) 기능 단위 개발 후 통합 전, PR 안정성 검증 dev-be로의 PR 생성 시, CI 자동 수행 (빌드/테스트)
dev-be (Push 또는 PR 머지) 통합 브랜치의 전체 코드에 대해 빌드 및 통합 테스트 수행 dev-be 기준 Push 발생 시, CI 자동 수행
dev-be  dev (머지) 통합 기능을 운영 브랜치로 반영, 자동 배포 실행 dev 브랜치 기준 Push 발생 시, CI + CD 자동 수행