CI/CD 구축 with GitHub Actions

하이솝·2026년 5월 27일

소프트웨어공학

목록 보기
21/27

GitHub Actions

  • 깃허브에서 제공하는 자동화 플랫폼
  • 개발자가 코드를 올리거나 변경하는 특정 이벤트 발생 시,
    미리 정의해둔 작업들을 자동으로 실행
  • 깃허브 액션을 실행시키는 주요 이벤트 트리거로는,
    push, pull request, web hook 등이 있음

CI/CD와 GitHub Actions의 관계

  • 개발자가 코드를 수정하면,
    자동으로 빌드하고 테스트 환경을 거쳐 코드의 품질을 검증 - CI

  • 이후 지속적 배포를 통해 검증된 코드를 실제 서비스 환경인
    프로덕션에 자동으로 배포 - CD

  • GitHub Actions는 이 전체 파이프라인 과정을 자동화하여,
    개발자가 코드 작성에만 집중할 수 있게 도와주고 휴먼 에러를 줄여줌

GitHub Actions workflow 분석


name: 전체 자동화 작업의 이름을 정의

on: 특정 이벤트가 발생했을 때, 이 작업이 시작될지 결정하는 설정
예시에서는 main 브랜치에 PR, Push가 발생했을 때 작동

jobs: 실제 수행할 작업들을 정의하는 구역
여러 개를 설정하여 병렬로 실행하거나 순차적으로 실행 가능

runs-on: 이 작업을 실행할 가상 머신 환경 지정
예시에서는 ubuntu-latest 최신 버전의 리눅스 환경 사용 중

steps: 세부 실행 단계

  • Checkout code
    uses 구문을 사용해서 깃허브 저장소의 코드를 가상 환경으로 복사

  • Set up Node.js
    with 항목을 통해 특정 노드 버전 지정

  • install dependencies, Run tests
    run 항목을 통해 터미널 명령어를 직접 실행

CI/CD 구축을 위한 프롬프트

CI

정적 분석

  • 코드 자체에 문제가 없는지 점검

security scan

  • 소스 코드 및 의존성의 보안 취약점을 점검

건물을 짓기 전, 설계도와 자재를 꼼꼼히 검사하는 것과 같음

단위 테스트

  • 비즈니스 로직이 잘 작동하는지 확인

통합 테스트

  • 여러 모듈이 서로 잘 연결되는지 확인

CD

도커 빌드

  • 어떤 환경에서도 동일하게 작동할 수 있도록
    도커 이미지를 생성
    이때 빌드 시간을 단축하고 효율성을 높이기 위해
    dependency도커 레이어 캐싱 전략을 반드시 적용해야 함

container security scan

  • 이미지가 만들어진 후, 이미지 레이어 자체에 보안 문제가 없는지 확인

E2E

  • 실제 사용자 관점에서 시스템이 전체적으로 잘 작동하는지 확인

GitHub Pages 배포

  • 모든 테스트가 성공적으로 마무리되었을 때 진행하는 절차

  • upload pages artifacts, deploy pages와 같은 도구를 이용하여,
    모든 절차를 수동 작업 없이 자동화

smoke test

  • 배포된 사이트가 실제로 살아있는지, 기본적인 기능이 응답하는지 확인
    배포가 끝났다고 해서 모든 과정이 완료된 것이 아님

  • 해당 테스트로 전체 파이프라인의 성공 여부 확정

CI 이슈 라벨 생성을 위한 프롬프트

Label Data

ci: 파이프라인 관련 이슈풀 리퀘스트를 식별하는 데에 사용

testing: 테스트 코드품질 검증 관련 작업에 할당

static-analysis: 코드의 정적 분석 결과 추적

실행 로직

  • GitHub CLI를 통해 일관된 명령 수행

  • 라벨이 존재하지 않을 때, gh label create: 라벨 생성
    라벨이 이미 존재할 때, gh label edit: 색상과 설명 최신화

  • 명령어 실행 중 특정 라벨에서 오류가 발생하더라도
    전체 프로세스가 중단되지 않고 다음 라벨로 넘어가도록 설계
    자동화의 안정성 확보를 위함

CD 이슈 라벨 생성을 위한 프롬프트

Label Data

cd: CD 파이프라인과 배포 전반 담당
docker: 도커 이미지와 컨테이너화 관련 이슈
e2e-testing: playwright을 기반으로 실제 사용자 환경에서의 동작을 검증
infrastructure: 인프라 및 배포 환경 설정 관리

CI/CD 구축을 위한 프롬프트

[이슈 등록]

  • gh CLI 깃허브 명령줄 도구를 이용하여 이슈 생성

  • Phase, description, Acceptance criteria로 구성

  • 한꺼번에 많은 요청을 보내면 시스템 부하 가능성이 있으므로,
    이슈들을 하나씩 순차적으로 생성해야함

GitHub Projects 칸반보드

[구현-테스트-커밋]

  • gh project 명령어로 Todo 열의 가장 위에 있는 이슈 번호와 제목 추출
    해당 이슈의 상태를 In Progress로 변경 후 본인을 assignee로 할당

  • gh issue view 명령어로 내용 상세히 확인
    이슈 번호와 요약 키워드를 조합한 피처 브랜치 생성

  • 실제 수용 기준인 AC를 바탕으로 실제 코드 구현

  • 검증 통과 시 PR 생성
    PR 본문에는 해당 이슈를 자동으로 닫아주는 closes 구문 추가

CI 워크플로우

on:push
이 모든 과정이 코드가 저장소에 업로드되는 순간 시작된다는 트리거를 의미

첫 번째 단계: 코드의 기초적인 결함 검사

  • static analysis - ESLint
    실제로 코드를 실행하지 않고도, 문법적 오류나 코딩 컨벤션 위반을 검사

  • Security Scan - npm audit
    보안 스캔으로,
    프로젝트에서 사용하는 외부 라이브러리에 알려진 취약점이 없는지 검사

  • 중앙의 연결선은 의존성 관계를 나타냄

  • 기초적인 문법 오류나 보안 결함이 있는 코드에 대해
    리소스가 많이 드는 테스트를 수행하지 않음
    컴퓨팅 자원을 효율적으로 관리하기 위함

두 과정은 병렬/그룹화되어 실행됨

첫 번째 작업의 모든 작업이 성공적으로 마무리되어야만
두번째 단계로 넘어갈 수 있음

두 번째 단계: 본격적인 코드 검증

  • 프론트엔드 환경에서 Unit Tests(단위 테스트)
    각각의 함수나 컴포넌트가 독립적으로 잘 작동하는지 검증한다는 사실

  • Integration Tests(통합 테스트) 및 커버리지 확인
    이들이 서로 연결되었을 때도 비즈니스 로직에 맞게 돌아가는지 확인
    커버리지: 전체 소스 코드에 대한 테스트 코드의 비율을 수치화한 것

두 단계 정리

  • 정적 분석과 보안 스캔을 통해 코드의 무결성 확인

  • 이를 통과한 코드에 한해서만 단위 테스트와 통합 테스트를 수행

CI 정적 분석

  • 개발자가 작성한 코드의 안정성을 실시간으로 확인하는 파이프라인 역할

워크플로우 트리거

  • main, develop 브랜치에 코드가 push 또는 PR 생성 시,
    해당 워크플로우가 자동으로 실행되도록 설계됨
    개발자가 일일이 수동으로 검사하지 않아도 되며
    코드에 변경 사항이 생길 때 마다 즉각적인 피드백을 받을 수 있음

정적 분석 단계

  • npm install이 아닌 npm ci를 사용하는 이유는
    package-lock.json 파일을 기준으로 의존성을 엄격하게 설치
    개발 환경과 CI 환경 사이의 일관성 보장을 위함

  • 프론트엔드와 백엔드를 독립적으로 검사함으로 인해,
    각각의 영역에서 발생하는 결함을 보다 명확하게 분리해서 파악 가능

결과 요약 및 가시성

  • if: always() 조건문을 사용함으로써
    앞선 단계들의 성공 여부에 관계없이 무조건 결과를 출력하기 위함

security scan

1) 깃허브 저장소에 있는 최신 코드를 가상 환경으로 가져옴

2) 프론트엔드 스캔
npm audit

  • --audit-level=high 설정
    보안 취약점 중 심각도가 높은 항목이 발견될 때만 빌드를 실패하게 만듦
    개발자가 사소한 경고에 지치지 않게 하며, 치명적인 위험은 확실히 잡음

  • --omit=dev
    배포 시 포함되는 핵심 패키지들의 안정성만 집중적으로 검증
    실제 서비스 실행 시 포함되지 않는 ESLintJest등의 개발 도구는 미포함

3) 백엔드 스캔

  • 프론트엔드 스캔과 같은 과정으로 진행됨

프론트엔드와 백엔드를 나누어 검사함으로써
어느 영역에 보안 결함이 발생했는지 즉각적인 파악 가능

CI: 보안 검사

Trivy

  • 라이브러리 내의 보안 취약점 검사

  • 파일 시스템을 뜻하는 fs 모드를 통해 프로젝트 전체를 검사

  • HIGH, CRITICAL 단계의 문제만 집중하도록 만듦
    해결 방법이 나오지 않은 문제는 ignore-unfixed 옵션으로 제외
    개발자가 수정 가능한 실질적인 위협에만 집중할 수 있도록 함

  • exit-code: 1
    치명적인 보안 결함 발견 시, 빌드 과정 강제 종료

  • 모든 검사 결과는 Github Step Summary를 통해 깔끔한 표 형태로 출력

CI 단위 테스트

needs

  • 앞 단계인 static-analysis
    보안 스캔 단계인 security scan이 모두 통과되어야만 시작됨

Vitest

  • 프론트엔드 테스트에 사용하는 도구

  • 웹 화면의 버튼이 잘 눌리는지, 카드가 제대로 표시되는지 등
    화면의 최소 단위 검사

Jest

  • 카드 섞기 로직이나 데이터 처리 함수 같은
    복잡한 수학적 계산이 정확한지 꼼꼼하게 따져보는 역할

Vitest, Jest를 사용하기 위해 npm ci라는 명령어를 통해
개발 환경을 완벽하게 복제하고 각각의 테스트를 실행

if: always()

  • 에러가 나서 테스트가 실패하더라도 결과 보고서는 반드시 만들어야 함
    개발자가 무엇이 틀렸는지 알기 위해

단위 테스트 사례: 피셔 에이츠 셔플 알고리즘 검증

카드를 무작위로 섞는 알고리즘

CI 통합 테스트

  • 단위 테스트가 개별 부품의 이상 유무 확인을 했다면,
    그 부품들이 연결되었을 때 이상이 없는지 점검

npm run test:integration

  • 백엔드의 통합 테스트 실행

coverage

  • "전체 코드에 대해 몇 퍼센트를 테스트했는가" 를 나타내는 지표
    설정한 임계값을 넘지 못하면 exit-code 1을 통한 품질 유지

if: always()

  • 성공 여부에 관계 없이 보고서로 남겨짐

통합 테스트 사례: 게임 API 연동 검증

  • 단위 테스트는 내부 로직에 집중하고, 통합 테스트는 통신과 흐름에 집중

데이터 규약 검증 (API Contract)

  • 프론트엔드와 백엔드 사이의 데이터 약속(타입, 속성)이 지켜지는지 검증

성능 요구사항(Performance)

  • 사용자 경험을 보장하기 위함
    비기능적 요구사항까지 통합 테스트의 영역으로 끌어들임

  • 서버의 라우팅, 비즈니스 로직, 데이터 생성 과정이 하나로 묶여
    실제 서비스 환경에서 문제없이 작동할 것임을 보장

CD


on: workflow_run
CI 워크플로우가 성공적으로 완료되었을 때만 배포 과정이 시작되도록 설계됨

Docker Build and Push to~
소스 코드를 도커 이미지의 독립적인 단위로 묶어 저장소에 업로드

Container Security Scan
도커 이미지 내부의 보안 취약점이나 악성 코드 검사

E2E Test
playwright라는 도구를 사용해, 실제 사용자가 브라우저를 사용하는 것과
똑같은 환경
에서 기능들이 유기적으로 작동하는지 확인
실제 사용자 경험을 시뮬레이션 하기 때문에 가장 긴 시간이 소모됨

Deploy to GitHub Pages
실제 서비스가 서버에 배포
전 세계 사용자들이 접속할 수 있는 상태

Smoke Test
배포 직후 서비스가 최소한의 정상 작동을 하는지 테스트

  • 이러한 선형적 구조는 각 단계가 이전 단계의 성공을 보장받아야 실행되는
    강력한 의존성 관계를 보여줌

  • 개발자의 수동 개입 없이
    빌드, 보안, 검증, 테스트, 배포, 최종 확인 과정이 모두 자동화

Docker

  • 소프트웨어를 담는 표준화된 컨테이너

Docker Concepts

  • 애플리케이션과 그 실행에 필요한 라이브러리를 하나로 묶어 패키징하는 도구
    이렇게 패키징 된 결과물을 docker image라고 부름

docker image

  • 실행 가능한 정적인 상태의 템플릿

  • 도커 엔진 위에서 실행하면, container라는 격리된 실행 객체가 생성됨

container

  • 기존 가상 머신보다 훨씬 가볍고 빠름

  • 독립적인 환경 제공

  • 표준화된 소프트웨어 단위

  • 어떤 환경에서도 동일하게 작동함

Registry & GHCR

  • 우리가 만든 이미지는 Docker HubGHCR(GitHub Container Registry)
    와 같은 온라인 저장소에 보관하고 관리함

  • 이렇게 업로드된 이미지는 환경에 관계없이 어디서든 실행 가능함

GHCR

  • 깃허브의 생태계 내에 있어, 깃허브 액션과 긴밀하게 통합됨
    보안, 자동화 배포 파이프라인 구축 시 효율적

Dockerfile Structure

  • 이미지를 빌드하기 위한 명령어 집합

FROM

  • 베이스 이미지를 지정하는 시작점

LABEL

  • 이미지의 관리자나 버전 정보를 기록하는 메타데이터

ENV

  • 애플리케이션 안에서 사용할 환경 변수

WORKDIR

  • 컨테이너 내부의 작업 디렉토리를 설정하여
    이후 명령어들이 실행될 위치를 잡음

COPY

  • 로컬 컴퓨터의 파일들을 이미지 내부로 복사

RUN

  • 빌드 과정 중 필요한 패키지 설치 또는 업데이트 명령어 실행

EXPOSE

  • 컨테이너가 외부와 통신할 때 사용할 포트 번호를 알려줌

CMD

  • 컨테이너가 실행되는 시점에 기본으로 동작할 명령어를 정의

CD: Docker 이미지 빌드 및 GHCR 푸시

1. 파이프라인 시작 & 조건

  • CD 워크플로우는 메인 브랜치에서 CI 작업이 성공적으로 끝났을 때만 자동으로 시작되도록 설정됨

2. 빌드 환경 & 도구

  • Buildx
    여러 환경에 맞춰 빌드 속도를 빠르게 해 주는 레이어 캐싱 기능 제공
    배포 시간을 대폭 단축해 줌

3. 인증 및 Frontend 빌드

  • GITHUB_TOKEN을 사용하여
    GHCR 컨테이너 저장소에 자동 로그인을 통한 보안성 확보

  • nginx
    웹 서버 설정 파일로, 해당 파일을 포함하여 저장소로 푸시

4. Backend 빌드 & 결과 리포트

  • 컨텍스트를 최소화하여 가벼운 이미지 생성

  • GitHub Step Summary 기능을 통해
    현재 빌드된 이미지 태그와 상태를 시각화

CD: Container Scan

  • 소프트웨어를 실제 운영 환경에 배포하기 전 안정성을 최종적으로 검증

1) 보안 파이프라인 시작 & 조건

  • 도커 빌드(이미지 만들기)푸시(이미지를 저장소에 등록) 작업이
    성공적으로 완료된 직후 실행되도록 설계

  • 배포 전 보안 검사는 선택이 아닌 필수 선행 작업

  • 취약점이 포함된 이미지가 외부로 유출되는 것을 원천 차단

2) 인증 및 코드 접근

  • GHCR 저장소에 안전하게 접근하기 위해 깃허브 토큰을 사용해 로그인

  • 보안 도구가 프라이빗 저장소에 있는 이미지를 내려받아 검사할 수 있도록
    적절한 권한을 확보하는 과정으로 파이프라인의 신뢰성을 보장

3) 프론트엔드 이미지 보안 스캔

  • Trivy라는 도구를 사용하여 시스템에 치명적인 영향을 줄 수 있는
    CRITICAL 등급의 취약점을 집중적으로 점검

  • 심각한 보안 결함 발생 시 엑시트 코드 1번을 반환하여 전체 파이프라인 중단
    결함이 있는 소프트웨어가 배포되는 것을 막음

4) 백엔드 이미지 보안 스캔

  • 패치가 존재하지 않는(해결 방법이 없는) 취약점
    결과에서 제외하여 불필요한 경고인 노이즈를 줄임
    개발자가 당장 해결할 수 있는 문제에만 집중하게 만듦

5) 결과 리포팅 및 공유

  • 모든 스캔이 완료되면 GitHub Step Summary 기능을 통해
    각 이미지의 보안 상태와 스캔 요약 결과를 시각적으로 출력함
    팀원 전체에게 공개되어
    누구나 현재 배포된 소프트웨어의 품질과 안정성 확인 가능

CD: E2E 테스트

  • 실제 사용자가 우리 서비스를 이용하는 것과 똑같은 환경에서
    전체 시스템이 잘 돌아가는지 확인

1) 통합 검증 환경 구축

  • 컨테이너 스캔까지 무사히 마친 후 실행되며,
    파이프라인 내부에서 프런트엔드와 백엔드 모두 구동하여 전체 시스템을 구성

2) 의존성 설치 레이어

  • Node.js 20 버전에서 npm cache 기능을 적극 활용하여
    매번 모든 패키지를 새로 받는 수고를 덜어냄
    테스트 속도를 비약적으로 높임

3) 브라우저 최적화 및 자동 실행

  • CD 속도를 최대한 끌어올리기 위해
    여러 브라우저 대신 Chronium 하나만 설치해서 집중적으로 테스트
    구글 크롬, 엣지, 웨일 등의 대부분 브라우저가 Chronium 기반임

  • 서버 환경에서 테스트를 돌릴 때, 브라우저 창을 직접 띄울 수 없음
    이 때 사용하는 것이 headless 모드

  • 이후 Playwright 라는 도구를 이용하여
    웹 서버를 자동으로 띄우고 테스트를 실행하여 정밀한 검증 실행

4) 실패 분석 및 결과 보관

  • 테스트가 실패할 경우에만 HTML 형태의 리포트를 아티팩트 형태로 업로드
    해당 기록은 7일동안 기록됨

playwright E2E Test Scenarios: Card Matching Game

CD: Smoke 테스트

  • 하드웨어 수리 분야에서 유래됨
    기기를 수리한 뒤 처음 전원을 켰을 때, 연기가 나지 않으면 큰 문제는 없는 것

  • 전체 기능을 상세히 점검하기 전
    가장 핵심적인 서비스가 죽지 않고 살아있는지 확인
    최소한의 가용성 테스트

curl 명령어를 통해 GitHub Pages 사이트로 실제 접속 시도

  • 소프트웨어 공학의 회복 탄력성 원칙이 적용된 재시도 로직으로
    리트라이 횟수를 5회로 설정, 각 시도 사이에 10초의 지연 시간을 가짐

  • CDN(Content Delivery Network) 전파가 전 세계적으로 완료되는데 걸리는
    물리적인 시간을 고려한 설정
    웹 서버가 서울에만 있다면, 미국 사용자는 데이터를 받기까지 오랜 시간 대기,
    CDN을 사용하면 미국에 있는 거점 서버에서 바로 데이터 전송

    일시적인 네트워크 지연으로 인한 테스트 실패 현상 방지

  • 접속 거부 시에도 재시도하도록 설정하고,
    최대 대기 시간을 30초로 제한하여 파이프라인의 무한 대기를 방지

  • HTTP 200 응답 수신 시 스모크 테스트 통과 메시지 출력과 함께 작업 종료

Health Check API 활용

  • 단순히 메인 페이지가 열리는 것을 넘어, 서버 내부의 데이터베이스 연결이나
    캐시 시스템이 정상적으로 작동하는지 확인

  • 겉으로는 멀쩡해 보이지만, 실제 기능은 마비된 상태인 좀비 서버를 미리 감지

핵심 UI 요소의 렌더링 확인

  • HTTP 응답 코드가 200이라고 해서 화면에 내용이 제대로 보인다는 보장 없음
    Playwright와 같은 도구를 이용하여
    페이지 제목, 로그인 버튼 등의 돔 트리 점검

외부 연동 서비스의 연결성 점검

  • 서비스와 연결된 외부 게이트웨이나 인증 API 서버와의 통신이 원활한지 확인

0개의 댓글