GitHub Actions를 이용해 웹 애플리케이션의 CI/CD 파이프라인을 처음부터 끝까지 구축하는 실전 가이드입니다. 자동 배포를 통해 개발 생산성을 극대화하고 안정적인 서비스 운영을 경험하세요.
개발팀에서 웹 애플리케이션을 만들고 있다면, 아마도 이런 문제들을 겪어보셨을 겁니다. 새로운 기능을 개발하고 테스트까지 마쳤는데, 실제 서비스에 반영하려면 수동으로 빌드하고, 서버에 접속해서 파일을 옮기고, 재시작하는 복잡한 과정을 거쳐야 합니다. 이 과정에서 휴먼 에러가 발생하기도 하고, 시간이 오래 걸려 개발 생산성이 저하되는 경우도 빈번하죠. 심지어 야간이나 주말에 긴급 패치를 배포해야 하는 상황이라면 더욱 고통스럽습니다. 이런 반복적이고 오류 발생 가능성이 높은 작업들을 어떻게 하면 효율적으로 자동화할 수 있을까요?
이 글은 바로 그 질문에 대한 실용적인 해답을 제시합니다. GitHub Actions를 활용하여 웹 애플리케이션의 CI/CD 파이프라인을 처음부터 끝까지 구축하는 방법을 상세하게 안내합니다. 자동 배포 시스템을 통해 개발 워크플로우를 혁신하고, 안정적이며 빠른 서비스 제공을 위한 기반을 다지는 여정에 동참해 보세요.
📑 목차
- 왜 CI/CD와 GitHub Actions가 필수적인가?
- 수동 배포의 문제점과 자동화의 필요성
- GitHub Actions 선택의 이유
- GitHub Actions 핵심 개념 이해
- CI/CD 파이프라인 구축 사전 준비
- 1. GitHub 저장소 준비
- 2. 배포 대상 환경 준비 (예: AWS S3 & CloudFront)
- 3. GitHub Secrets 설정
- 웹 애플리케이션 CI/CD 워크플로우 설계
- GitHub Actions 워크플로우 파일 작성
- 자동 배포 테스트 및 문제 해결
- 워크플로우 실행 및 모니터링
- 일반적인 문제 해결 팁
- 결론: 자동화된 배포의 미래
왜 CI/CD와 GitHub Actions가 필수적인가?
CI/CD(Continuous Integration/Continuous Delivery 또는 Continuous Deployment)는 소프트웨어 개발 프로세스에서 핵심적인 개념으로 자리 잡았습니다. CI는 개발자들이 작성한 코드를 지속적으로 통합하고 자동으로 빌드 및 테스트하여 코드 충돌이나 오류를 조기에 발견하는 것을 목표로 합니다. CD는 CI를 통해 검증된 애플리케이션을 자동으로 배포 가능한 상태로 만들거나, 더 나아가 실제 서비스 환경에 자동으로 배포하는 과정을 의미합니다.
수동 배포의 문제점과 자동화의 필요성
수동 배포는 여러 가지 문제점을 야기합니다. 예를 들어, 개발자가 직접 서버에 접속하여 파일을 복사하고 붙여넣는 과정에서 잘못된 파일을 배포하거나, 환경 설정 실수를 저지를 수 있습니다. 이러한 실수는 서비스 장애로 이어질 수 있으며, 문제 해결에 더 많은 시간과 자원을 소모하게 만듭니다. 반면, 자동화된 CI/CD 파이프라인은 이러한 인적 오류를 최소화하고, 배포 과정을 표준화하여 일관성과 안정성을 높입니다. 다음 표는 수동 배포와 자동화된 배포의 주요 차이점을 비교합니다.
| 특징 | 수동 배포 | 자동화된 배포 (CI/CD) |
|---|---|---|
| 배포 시간 | 길고 예측 불가능 | 짧고 일관적 |
| 오류 발생률 | 높음 (인적 오류) | 낮음 (자동화된 검증) |
| 개발 생산성 | 저하 (배포에 시간 소모) | 향상 (개발에 집중) |
| 배포 빈도 | 낮음 (부담이 큼) | 높음 (부담이 적음) |
| 서비스 안정성 | 낮음 (오류 가능성) | 높음 (신속한 피드백, 롤백 용이) |
GitHub Actions 선택의 이유
CI/CD 도구는 다양하지만, GitHub Actions는 특히 GitHub 사용자에게 강력한 이점을 제공합니다. Git 저장소와 긴밀하게 통합되어 있어, 코드 푸시, 풀 리퀘스트 생성 등 GitHub 내의 모든 이벤트에 반응하여 워크플로우를 트리거할 수 있습니다. 또한, 사용법이 직관적이고 YAML 문법으로 쉽게 정의할 수 있으며, 다양한 마켓플레이스 액션들을 활용하여 복잡한 작업도 손쉽게 구현할 수 있습니다. 별도의 CI/CD 서버를 구축하거나 관리할 필요 없이, GitHub가 제공하는 인프라를 활용할 수 있다는 점도 큰 장점입니다.
GitHub Actions 핵심 개념 이해
GitHub Actions를 효과적으로 사용하기 위해서는 몇 가지 핵심 개념을 이해하는 것이 중요합니다.
- 워크플로우 (Workflow): 하나 이상의 잡(Job)으로 구성된 자동화된 프로세스입니다. `.github/workflows` 디렉토리 내에 YAML 파일로 정의합니다. 특정 이벤트(예: `push`, `pull_request`)가 발생하면 트리거됩니다.
- 이벤트 (Event): 워크플로우를 트리거하는 특정 활동입니다. 예를 들어, `push` (코드를 저장소에 푸시할 때), `pull_request` (풀 리퀘스트가 생성되거나 업데이트될 때) 등이 있습니다.
- 잡 (Job): 워크플로우 내에서 실행되는 독립적인 작업 단위입니다. 각 잡은 가상 환경(runner)에서 실행되며, 여러 스텝(Step)으로 구성됩니다. 기본적으로 병렬로 실행되지만, `needs` 키워드를 사용하여 종속성을 정의할 수 있습니다.
- 스텝 (Step): 잡 내에서 실행되는 개별 명령 또는 액션입니다. 스텝은 쉘 스크립트 명령(예: `run: npm install`)이거나, 마켓플레이스 또는 직접 정의한 액션(Action)일 수 있습니다.
- 액션 (Action): 워크플로우의 가장 작은 빌딩 블록입니다. 특정 작업을 수행하는 재사용 가능한 코드 조각입니다. 예를 들어, `actions/checkout@v3`는 저장소 코드를 체크아웃하는 액션입니다.
- 러너 (Runner): 워크플로우를 실행하는 서버입니다. GitHub 호스팅 러너(Ubuntu, Windows, macOS)를 사용하거나, 자체 호스팅 러너를 설정할 수 있습니다.
이러한 개념들을 바탕으로 웹 애플리케이션의 빌드, 테스트, 배포 과정을 일련의 워크플로우로 정의하게 됩니다.
CI/CD 파이프라인 구축 사전 준비
본격적인 CI/CD 파이프라인 구축에 앞서 필요한 몇 가지 준비 사항이 있습니다. 이 단계들을 철저히 준비해야 원활한 자동 배포를 구현할 수 있습니다.
1. GitHub 저장소 준비
당연하게도, 배포할 웹 애플리케이션의 코드가 GitHub 저장소에 있어야 합니다. 이 저장소에 GitHub Actions 워크플로우 파일을 추가하고, 모든 변경 사항을 추적하게 됩니다.
2. 배포 대상 환경 준비 (예: AWS S3 & CloudFront)
웹 애플리케이션을 배포할 타겟 환경을 준비해야 합니다. 이 가이드에서는 프론트엔드 웹 애플리케이션(예: React, Vue, Angular)을 AWS S3에 정적 웹사이트 호스팅으로 배포하고 AWS CloudFront를 통해 캐싱 및 CDN을 구성하는 시나리오를 가정합니다. 백엔드 애플리케이션의 경우, AWS EC2, Elastic Beanstalk, 또는 Kubernetes 클러스터 등이 될 수 있습니다.
- AWS S3 버킷 생성: 정적 웹사이트 호스팅을 활성화하고, 퍼블릭 접근을 허용합니다 (또는 CloudFront OAI/OAC 설정).
- AWS CloudFront 배포 생성: S3 버킷을 원본으로 설정하고, HTTPS 통신을 위한 인증서를 연결합니다.
- AWS IAM 사용자 생성: GitHub Actions에서 AWS 리소스에 접근하기 위한 IAM 사용자를 생성합니다. 이 사용자에게는 S3 버킷에 파일을 업로드하고 CloudFront 캐시를 무효화할 수 있는 적절한 권한(예: `s3:PutObject`, `s3:DeleteObject`, `cloudfront:CreateInvalidation`)을 부여해야 합니다. 최소 권한의 원칙을 지켜 필요한 권한만 부여하는 것이 중요합니다.
3. GitHub Secrets 설정
민감한 정보(예: AWS 접근 키, API 키 등)는 워크플로우 파일에 직접 노출해서는 안 됩니다. GitHub Secrets 기능을 사용하여 안전하게 관리해야 합니다. 저장소 설정에서 `Settings > Secrets and variables > Actions`로 이동하여 새로운 저장소 시크릿을 추가합니다.
- `AWS_ACCESS_KEY_ID`: IAM 사용자 액세스 키 ID
- `AWS_SECRET_ACCESS_KEY`: IAM 사용자 시크릿 액세스 키
- `AWS_REGION`: AWS 리전 (예: `ap-northeast-2`)
- `S3_BUCKET_NAME`: 배포할 S3 버킷 이름
- `CLOUDFRONT_DISTRIBUTION_ID`: CloudFront 배포 ID (캐시 무효화용)
이러한 시크릿들은 워크플로우에서 `{{ secrets.SECRET_NAME }}` 형태로 참조하여 사용할 수 있습니다.
웹 애플리케이션 CI/CD 워크플로우 설계
이제 실제 워크플로우를 어떻게 구성할지 설계할 차례입니다. 일반적인 웹 애플리케이션의 CI/CD 파이프라인은 다음 단계를 포함합니다.
- 소스 코드 체크아웃: GitHub 저장소에서 최신 코드를 가져옵니다.
- 의존성 설치: 프로젝트에 필요한 라이브러리(예: `npm install`, `yarn install`)를 설치합니다.
- 코드 빌드: 프로덕션 배포를 위한 정적 파일(예: React 앱의 `build` 디렉토리)을 생성합니다.
- 테스트 실행 (선택 사항): 유닛 테스트, 통합 테스트 등을 실행하여 코드의 안정성을 검증합니다. 이 단계에서 실패하면 다음 단계로 진행하지 않습니다.
- 아티팩트 저장 (선택 사항): 빌드된 결과물을 아티팩트로 저장하여 나중에 재사용하거나 검토할 수 있도록 합니다.
- 배포: 빌드된 파일을 배포 대상 환경(예: S3 버킷)으로 전송합니다.
- 캐시 무효화 (선택 사항): CDN(예: CloudFront)을 사용하는 경우, 변경된 파일에 대한 캐시를 무효화하여 최신 버전이 사용자에게 즉시 제공되도록 합니다.
이러한 단계를 GitHub Actions 워크플로우의 잡과 스텝으로 매핑하여 구현합니다.
GitHub Actions 워크플로우 파일 작성
이제 실제 워크플로우 파일을 작성해 봅시다. 프로젝트 루트 디렉토리에 `.github/workflows` 경로를 생성하고, 그 안에 `deploy.yml`과 같은 이름으로 YAML 파일을 만듭니다. 여기서는 Node.js 기반의 React 웹 애플리케이션을 S3에 배포하고 CloudFront 캐시를 무효화하는 예시를 보여줍니다.
name: Web Application CI/CD Pipeline
on:
push:
branches:
- main # main 브랜치에 푸시될 때 워크플로우 실행
pull_request:
branches:
- main # main 브랜치로 풀 리퀘스트가 생성되거나 업데이트될 때
env:
NODE_VERSION: '18.x' # 사용할 Node.js 버전
jobs:
build_and_deploy:
runs-on: ubuntu-latest # 워크플로우가 실행될 가상 환경 (Ubuntu 최신 버전)
steps:
- name: Checkout Code # 1. 소스 코드 체크아웃
uses: actions/checkout@v4
- name: Setup Node.js environment # 2. Node.js 환경 설정
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm' # npm 캐싱 활성화 (의존성 설치 속도 향상)
- name: Install dependencies # 3. 의존성 설치
run: npm install
- name: Build web application # 4. 웹 애플리케이션 빌드
run: npm run build # React, Vue 등의 경우 'build' 스크립트 실행
# - name: Run tests (Optional) # 5. 테스트 실행 (선택 사항)
# run: npm test
- name: Configure AWS credentials # 6. AWS 자격 증명 설정
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Deploy to S3 # 7. S3 버킷으로 빌드 파일 배포
run: |
aws s3 sync ./build s3://${{ secrets.S3_BUCKET_NAME }} --delete
# --delete 옵션: S3 버킷에 없는 파일은 삭제하여 동기화
- name: Invalidate CloudFront cache # 8. CloudFront 캐시 무효화
run: |
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"
# "/*" 경로로 캐시를 무효화하여 모든 파일이 최신 버전으로 갱신되도록 함
위 워크플로우 파일은 다음과 같은 방식으로 동작합니다.
- `on: push`와 `on: pull_request`를 통해 `main` 브랜치에 코드가 푸시되거나 풀 리퀘스트가 발생할 때 워크플로우가 시작됩니다.
- `jobs` 섹션에는 `build_and_deploy`라는 하나의 잡이 정의되어 있습니다.
- 각 `steps`는 순서대로 실행되며, 코드를 체크아웃하고, Node.js 환경을 설정하고, 의존성을 설치하고, 애플리케이션을 빌드합니다.
- AWS 관련 스텝에서는 `aws-actions/configure-aws-credentials` 액션을 사용하여 GitHub Secrets에 저장된 AWS 자격 증명을 설정합니다.
- `aws s3 sync` 명령어를 사용하여 빌드된 `./build` 디렉토리의 내용을 S3 버킷으로 동기화합니다. `--delete` 옵션은 S3에 존재하지 않는 로컬 파일을 삭제하여 항상 최신 상태를 유지하게 합니다.
- `aws cloudfront create-invalidation` 명령어를 사용하여 CloudFront 캐시를 무효화합니다. 이로써 사용자들은 강제로 최신 버전의 파일을 CDN에서 가져오게 됩니다.
이 예시는 프론트엔드 정적 웹 애플리케이션에 최적화되어 있지만, 백엔드 애플리케이션의 경우 빌드 후 Docker 이미지 빌드 및 푸시, SSH를 통한 원격 서버 배포, Kubernetes 배포 등의 스텝으로 대체될 수 있습니다.
자동 배포 테스트 및 문제 해결
워크플로우 파일을 작성했다면, 이제 자동 배포 파이프라인이 제대로 작동하는지 테스트하고 발생할 수 있는 문제들을 해결해야 합니다.
워크플로우 실행 및 모니터링
작성한 `deploy.yml` 파일을 GitHub 저장소의 `main` 브랜치에 푸시하면, GitHub Actions가 자동으로 워크플로우를 트리거합니다. GitHub 저장소의 `Actions` 탭으로 이동하면 현재 실행 중이거나 완료된 워크플로우의 목록을 확인할 수 있습니다. 각 워크플로우 실행을 클릭하면 개별 잡과 스텝의 로그를 상세하게 볼 수 있습니다. 로그를 통해 각 스텝이 성공했는지, 어떤 오류가 발생했는지 파악할 수 있습니다.
일반적인 문제 해결 팁
- 권한 문제: 가장 흔한 문제입니다. AWS IAM 사용자에게 S3 업로드 및 CloudFront 캐시 무효화에 필요한 권한이 충분한지 다시 확인하세요. `aws-access-key-id`와 `aws-secret-access-key`가 올바르게 설정되었는지도 확인해야 합니다.
- 환경 변수/시크릿 오타: GitHub Secrets 이름이나 워크플로우 파일에서 참조하는 이름에 오타가 없는지 확인하세요. 대소문자를 구분합니다.
- 빌드 실패: `npm install`이나 `npm run build` 스텝에서 오류가 발생한다면, 로컬 환경에서 해당 명령어를 실행하여 문제가 없는지 먼저 확인하세요. Node.js 버전이나 의존성 문제일 수 있습니다.
- 경로 문제: 빌드된 파일의 경로(예: `./build`)가 정확한지, S3 버킷에 올바른 위치에 배포되고 있는지 확인하세요.
- 캐시 문제: CloudFront 캐시 무효화 스텝이 제대로 실행되었는지 확인하고, 무효화 경로(`/*`)가 올바른지 점검하세요. 캐시 무효화는 완료까지 약간의 시간이 소요될 수 있습니다.
- 워크플로우 실행이 안 될 때: `on:` 섹션의 트리거 조건(예: 브랜치 이름)이 푸시 또는 풀 리퀘스트와 일치하는지 확인하세요.
문제가 발생하면, 해당 스텝의 상세 로그를 주의 깊게 분석하는 것이 중요합니다. GitHub Actions 로그는 매우 상세하게 정보를 제공하므로, 대부분의 문제 해결의 실마리를 찾을 수 있습니다.
결론: 자동화된 배포의 미래
지금까지 GitHub Actions를 활용하여 웹 애플리케이션의 CI/CD 파이프라인을 구축하는 실전 가이드를 살펴보았습니다. 초기 설정과 워크플로우 작성에 약간의 노력이 필요할 수 있지만, 일단 구축하고 나면 자동화된 배포는 개발팀에 엄청난 이점을 가져다줍니다. 개발자는 배포의 복잡성에서 벗어나 핵심 개발에 집중할 수 있으며, 사용자들은 더욱 빠르고 안정적으로 최신 기능과 버그 패치를 경험할 수 있게 됩니다.
이 가이드에서 제시된 예시는 프론트엔드 애플리케이션의 S3/CloudFront 배포에 초점을 맞추었지만, 기본 원리와 GitHub Actions의 개념은 어떤 종류의 웹 애플리케이션이나 배포 환경에도 적용될 수 있습니다. Docker, Kubernetes, SSH 배포 등 다양한 시나리오에 맞춰 워크플로우를 커스터마이징하고 확장해 보세요.
CI/CD 파이프라인은 한 번 구축으로 끝나는 것이 아니라, 지속적인 개선과 유지보수가 필요합니다. 팀의 요구사항과 기술 스택의 변화에 맞춰 워크플로우를 최적화하고 발전시켜 나가는 것이 중요합니다. 이 글이 여러분의 개발 생산성 향상과 서비스 안정성 확보에 큰 도움이 되기를 바랍니다.
GitHub Actions를 활용한 자동 배포 경험은 어떠신가요? 여러분만의 팁이나 궁금한 점이 있다면 아래 댓글로 자유롭게 공유해 주세요!
📌 함께 읽으면 좋은 글
- [튜토리얼] React와 Spring Boot 연동: 로컬 개발 환경 구축 및 API 통신 실전 가이드
- [생산성 자동화] Pre-commit 훅을 활용한 개발 워크플로우 자동화: 코드 품질, 포매팅, 린팅 실전 가이드
- [클라우드 인프라] Terraform으로 멀티 클라우드 인프라 자동화 전략: AWS, GCP, Azure 실전 가이드
이 글이 도움이 되셨다면 공감(♥)과 댓글로 응원해 주세요!
궁금한 점이나 다루었으면 하는 주제가 있다면 댓글로 남겨주세요.
'튜토리얼' 카테고리의 다른 글
| React와 Spring Boot 연동: 로컬 개발 환경 구축 및 API 통신 실전 가이드 (0) | 2026.05.18 |
|---|---|
| Prometheus와 Grafana를 활용한 애플리케이션 성능 모니터링 시스템 구축 실전 가이드 (0) | 2026.05.18 |
| VS Code Dev Containers 완벽 가이드: 개발 환경 컨테이너화로 생산성 극대화 (0) | 2026.05.17 |
| Docker Compose 활용: 로컬 다중 서비스 개발 환경 완벽 구축 가이드 (0) | 2026.05.16 |
| Docker 컨테이너 원격 디버깅 완벽 가이드: 효율적인 개발 환경 구축 (0) | 2026.05.15 |