튜토리얼

GitHub Actions CI/CD 파이프라인 구축: 테스트, 빌드, 배포 자동화 실전 가이드

강코의 코딩 일기 2026. 5. 24. 13:04
반응형

GitHub Actions를 활용해 개발 워크플로우를 혁신하고 싶으신가요? 이 글에서는 테스트, 빌드, 배포 자동화를 포함한 CI/CD 파이프라인 구축의 모든 과정을 실무 경험 기반으로 상세히 안내합니다. 생산성을 극대화하는 노하우를 지금 확인하세요.

개발자라면 누구나 한 번쯤 겪어봤을 겁니다. 코드 변경 후 수동으로 테스트를 돌리고, 빌드하고, 서버에 접속해서 배포하는 반복적이고 지루한 작업들 말이죠. 때로는 이 과정에서 사람이 개입하면서 의도치 않은 실수가 발생해 서비스 장애로 이어지기도 합니다. 이러한 고통은 비단 저만의 경험은 아닐 것입니다.

이런 문제들을 해결하고 개발 생산성을 극대화하기 위해 등장한 개념이 바로 CI/CD(Continuous Integration/Continuous Delivery 또는 Deployment)입니다. 그리고 이 CI/CD 파이프라인을 구축하는 데 있어 최근 가장 각광받는 도구 중 하나가 바로 GitHub Actions입니다. 저도 처음에는 CI/CD의 필요성은 알았지만, 어떤 툴을 사용해야 할지 막막했습니다. 하지만 GitHub Actions를 직접 써보고 파이프라인을 구축하면서 얻은 경험은 개발 워크플로우에 혁신을 가져왔습니다. 이 글에서는 제가 GitHub Actions를 활용해 테스트, 빌드, 배포 자동화를 어떻게 구축했는지, 그 실전 노하우를 공유하고자 합니다.

GitHub Actions, 왜 특별할까요? 다른 CI/CD 툴과 비교

시중에 많은 CI/CD 툴이 존재합니다. Jenkins, GitLab CI, CircleCI, Travis CI, AWS CodePipeline 등 각자의 장단점을 가지고 있죠. 저 역시 여러 툴을 검토했지만, GitHub Actions를 선택하고 실제로 적용해 본 결과, 몇 가지 핵심적인 강점들이 있었습니다.

  • GitHub와의 완벽한 통합: 가장 큰 장점입니다. GitHub 저장소에 코드가 올라가 있으면 별도의 연동 설정 없이 바로 Actions를 사용할 수 있습니다. Pull Request, Issue 등 GitHub의 다양한 이벤트에 반응하여 워크플로우를 실행할 수 있다는 점은 개발 프로세스를 훨씬 매끄럽게 만듭니다.
  • 간편한 사용성: YAML 파일 하나로 워크플로우를 정의합니다. 문법이 직관적이고, Marketplace에서 수많은 액션(Action)을 찾아 재사용할 수 있어 학습 곡선이 매우 낮습니다.
  • 유연성과 확장성: 다양한 운영체제(Ubuntu, Windows, macOS)에서 워크플로우를 실행할 수 있으며, 컨테이너 환경도 지원합니다. 또한, 자체 호스팅 러너(Self-hosted Runner)를 구성하여 특정 환경이나 고성능 작업도 처리할 수 있습니다.
  • 비용 효율성: 공개 저장소에는 무료로 무제한 사용 시간을 제공하며, 비공개 저장소도 매월 일정 시간까지 무료로 사용할 수 있습니다. 이는 특히 소규모 팀이나 개인 프로젝트에서 큰 이점으로 작용했습니다.

다른 CI/CD 툴과 GitHub Actions 비교

제가 고려했던 주요 CI/CD 툴들과 GitHub Actions를 비교한 테이블입니다. 각 툴의 특징을 한눈에 볼 수 있습니다.

특징 GitHub Actions Jenkins GitLab CI
설정 방식 YAML 파일 (저장소 내) Groovy 스크립트 또는 UI (서버 내) YAML 파일 (저장소 내)
통합성 GitHub와 깊은 통합 다양한 플러그인을 통한 통합 GitLab과 깊은 통합
호스팅 클라우드 호스팅 (관리형) 자체 호스팅 (설치 및 관리 필요) 클라우드/자체 호스팅 모두 가능
학습 곡선 낮음 (직관적 YAML, Marketplace) 높음 (설치, 설정, 플러그인 관리) 중간 (YAML 기반)
주요 특징 Marketplace 액션, 유연한 워크플로우 강력한 커스터마이징, 방대한 플러그인 코드 관리부터 배포까지 올인원

결론적으로, GitHub를 주요 코드 저장소로 사용한다면 GitHub ActionsCI/CD 파이프라인 구축에 있어 가장 효율적이고 강력한 선택지입니다. 저 역시 이 통합된 경험에서 오는 이점을 크게 누렸습니다.

CI/CD 파이프라인 설계: 테스트, 빌드, 배포의 큰 그림

성공적인 CI/CD 파이프라인을 구축하려면 단순히 툴을 사용하는 것을 넘어, 전체적인 개발 프로세스와 각 단계의 역할을 명확히 이해해야 합니다. 제가 프로젝트에 적용한 CI/CD 파이프라인의 큰 그림은 다음과 같습니다.

  1. 코드 푸시/PR 생성: 개발자가 코드를 작성하고 GitHub 저장소에 푸시하거나 Pull Request(PR)를 생성합니다.
  2. CI (지속적 통합) 단계:
    • 테스트 자동화: 푸시된 코드에 대해 단위 테스트, 통합 테스트 등을 자동으로 실행하여 코드의 안정성을 검증합니다. 실패 시 즉시 개발자에게 피드백을 제공합니다.
    • 빌드 자동화: 테스트를 통과한 코드를 실행 가능한 아티팩트(예: JAR 파일, Docker 이미지, JavaScript 번들)로 빌드합니다.
  3. CD (지속적 배포) 단계:
    • 배포 자동화: 빌드된 아티팩트를 개발, 스테이징, 프로덕션 환경 등 원하는 서버에 자동으로 배포합니다.
    • 모니터링 및 롤백: 배포 후 서비스 상태를 모니터링하고, 문제가 발생하면 신속하게 이전 버전으로 롤백할 수 있는 체계를 갖춥니다.

이러한 단계들을 GitHub Actions워크플로우로 구현하면서, 개발팀은 코드 변경 사항을 더 자주 통합하고, 잠재적인 문제를 조기에 발견하며, 최종 사용자에게 더 빠르게 가치를 전달할 수 있게 되었습니다. 실제로 코드 푸시부터 스테이징 환경 배포까지 걸리는 시간이 기존 수동 작업 대비 80% 이상 단축되었습니다.

GitHub Actions 워크플로우 구축 실전: 기본 원리와 YAML 파일 작성

GitHub Actions의 핵심은 워크플로우(Workflow)입니다. 워크플로우는 `.github/workflows` 디렉토리 안에 YAML 파일로 정의됩니다. 제가 처음 YAML 파일을 접했을 때 다소 복잡해 보였지만, 몇 가지 핵심 키워드만 이해하면 매우 직관적이라는 것을 알게 되었습니다.

워크플로우의 주요 구성 요소

  • name: 워크플로우의 이름입니다. GitHub UI에서 표시됩니다.
  • on: 워크플로우가 언제 실행될지 정의합니다. push, pull_request, workflow_dispatch(수동 실행) 등 다양한 이벤트가 있습니다.
  • jobs: 워크플로우 내에서 실행될 하나 이상의 작업(job)을 정의합니다. 각 작업은 독립적인 가상 환경에서 실행됩니다.
  • runs-on: 작업이 실행될 러너(Runner) 환경을 지정합니다. (예: ubuntu-latest)
  • steps: 작업 내에서 순차적으로 실행될 단계(step)들을 정의합니다.
  • uses: GitHub Actions Marketplace에서 제공되는 사전 정의된 액션이나, 다른 저장소의 액션을 재사용할 때 사용합니다.
  • run: 셸 명령어를 직접 실행할 때 사용합니다.

간단한 Node.js 프로젝트의 CI 워크플로우 예시를 통해 실제 YAML 파일을 살펴보겠습니다.


# .github/workflows/node-ci.yml
name: Node.js CI Pipeline

on:
  push:
    branches: [ "main", "develop" ]
  pull_request:
    branches: [ "main", "develop" ]
  workflow_dispatch: # 수동 실행을 허용

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18' # 사용할 Node.js 버전 지정
        cache: 'npm' # npm 캐싱 설정

    - name: Install dependencies
      run: npm ci # 패키지 설치

    - name: Run tests
      run: npm test # 테스트 실행

    - name: Build project
      run: npm run build # 프로젝트 빌드
    

워크플로우는 `main` 또는 `develop` 브랜치에 코드가 푸시되거나 PR이 생성될 때, 또는 수동으로 실행될 때 동작합니다. 코드를 체크아웃하고, Node.js 환경을 설정하며, 의존성을 설치하고, 테스트를 실행한 후 빌드까지 진행합니다. 이처럼 몇 줄의 YAML 코드만으로 복잡한 CI 프로세스자동화할 수 있습니다.

단계별 자동화 구현: 테스트, 빌드, 그리고 배포

이제 위에서 설명한 워크플로우의 각 단계, 즉 테스트, 빌드, 배포를 어떻게 자동화하는지 좀 더 구체적인 예시와 함께 살펴보겠습니다. 제가 직접 프로젝트에 적용하면서 가장 많이 사용했던 방식들입니다.

테스트 자동화: 품질의 첫 번째 관문

코드가 변경될 때마다 모든 테스트를 수동으로 실행하는 것은 시간 낭비이자 오류의 원인입니다. CI/CD 파이프라인에서 테스트 자동화는 필수적입니다. 저는 주로 단위 테스트(Unit Test)와 통합 테스트(Integration Test)를 자동화했습니다. 프로젝트에 따라 다양한 언어와 프레임워크를 사용했지만, 기본적인 원리는 동일합니다.


# ... (이전 부분 생략) ...
    - name: Run unit tests
      run: npm test -- --coverage # Jest를 사용한 커버리지 포함 테스트 실행
      env:
        CI: true # CI 환경임을 알림

    - name: Report test coverage
      uses: codecov/codecov-action@v4 # Codecov 연동 (선택 사항)
      with:
        token: ${{ secrets.CODECOV_TOKEN }} # GitHub Secrets 사용
        fail_ci_if_error: true
    

위 예시는 Node.js 프로젝트에서 Jest 프레임워크를 사용해 테스트를 실행하고, 추가적으로 Codecov 액션을 이용해 테스트 커버리지를 보고하는 단계입니다. secrets.CODECOV_TOKEN처럼 민감한 정보는 GitHub Secrets 기능을 활용하여 안전하게 관리했습니다. 테스트가 실패하면 워크플로우가 중단되고, 개발자는 즉시 실패 원인을 파악하여 수정할 수 있습니다. 이를 통해 코드 품질 저하를 방지하고 개발 속도를 유지할 수 있었습니다.

빌드 자동화: 실행 가능한 아티팩트 생성

테스트를 통과한 코드는 이제 서비스에 배포될 수 있는 형태로 빌드되어야 합니다. 웹 애플리케이션의 경우 JavaScript 번들이 될 수도 있고, 백엔드 서비스의 경우 JAR 파일이나 Docker 이미지가 될 수 있습니다.


# ... (이전 부분 생략) ...
    - name: Build Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        push: false # 일단 빌드만 하고 푸시는 나중에
        tags: my-app:latest
        cache-from: type=gha,scope=build-cache
        cache-to: type=gha,scope=build-cache,mode=max

    - name: Save Docker image to artifact
      run: |
        docker save my-app:latest | gzip > my-app.tar.gz
    - uses: actions/upload-artifact@v4
      with:
        name: my-app-docker-image
        path: my-app.tar.gz
    

이 스텝은 프로젝트의 Docker 이미지빌드하고, GitHub ActionsArtifacts 기능으로 저장하는 예시입니다. Docker 빌드cache-fromcache-to를 사용하여 GitHub Actions의 캐싱 기능을 활용하면 빌드 시간을 크게 단축할 수 있습니다. 실제로 이를 적용한 후 Docker 이미지 빌드 시간이 평균 40% 이상 감소했습니다. 빌드된 아티팩트는 다음 배포 단계에서 활용됩니다.

배포 자동화: 서비스를 세상으로

CI/CD의 꽃은 바로 배포 자동화입니다. 수동 배포는 가장 많은 실수가 발생하는 지점이며, 자동화를 통해 이 위험을 제거할 수 있습니다. 배포 대상 환경은 AWS EC2, S3, Kubernetes, Netlify 등 다양하지만, 여기서는 AWS S3에 정적 웹사이트를 배포하는 간단한 예시와 EC2에 Docker 이미지배포하는 예시를 보여드리겠습니다.

AWS S3 정적 웹사이트 배포


# ... (이전 부분 생략) ...
  deploy-s3:
    needs: build # build 작업이 성공해야 실행
    runs-on: ubuntu-latest
    environment: production # 환경 지정 (GitHub Environments 사용)

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Configure AWS credentials
      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: ap-northeast-2

    - name: Download build artifact
      uses: actions/download-artifact@v4
      with:
        name: my-web-app-build
        path: ./build # 빌드된 파일이 저장될 경로

    - name: Deploy to S3
      run: aws s3 sync ./build s3://my-static-website-bucket --delete
    

이 예시는 빌드된 웹 애플리케이션 파일을 AWS S3 버킷에 동기화하여 배포합니다. AWS 자격 증명은 GitHub Secrets에 저장하고, aws-actions/configure-aws-credentials 액션을 사용하여 안전하게 인증합니다. environment: production 설정을 통해 GitHub Environments 기능을 활용하여 승인 절차를 추가하거나 특정 환경 변수를 관리할 수 있습니다.

AWS EC2 Docker 컨테이너 배포


# ... (이전 부분 생략) ...
  deploy-ec2:
    needs: build # build 작업이 성공해야 실행
    runs-on: ubuntu-latest
    environment: staging # 스테이징 환경 배포 예시

    steps:
    - name: Download Docker image artifact
      uses: actions/download-artifact@v4
      with:
        name: my-app-docker-image
        path: .

    - name: Load Docker image
      run: docker load --input my-app.tar.gz

    - name: Deploy to EC2 via SSH
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.EC2_HOST }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
        script: |
          docker stop my-app || true
          docker rm my-app || true
          docker rmi my-app:old || true # 이전 이미지 삭제
          docker tag my-app:latest my-app:old # 현재 이미지를 old로 태깅
          docker run -d --name my-app -p 80:80 my-app:latest
          # 또는, 다운로드한 tar.gz 파일을 scp로 전송 후 EC2에서 로드 및 실행
    

워크플로우는 이전에 빌드하여 아티팩트로 저장한 Docker 이미지를 EC2 인스턴스에 배포하는 예시입니다. appleboy/ssh-action과 같은 액션을 활용하여 SSH 접속 후 원격 서버에서 Docker 컨테이너를 관리합니다. 배포 과정에서 다운타임을 최소화하기 위해 `docker tag`를 이용한 롤백 전략이나 블루/그린 배포, 카나리 배포 등을 고려할 수 있습니다. 이 과정에서 GitHub Secrets는 SSH 키나 서버 IP 주소와 같은 민감한 정보를 안전하게 보호하는 데 결정적인 역할을 했습니다.

CI/CD 파이프라인 최적화 및 운영 팁

CI/CD 파이프라인을 구축하는 것만큼 중요한 것이 바로 효율적으로 운영하고 지속적으로 최적화하는 것입니다. 제가 직접 운영하면서 체득한 몇 가지 팁을 공유합니다.

  • 캐싱(Caching) 활용: Node.js의 `node_modules`, Maven의 `.m2` 디렉토리, Docker 이미지 레이어 등은 빌드 시간이 오래 걸리는 요소입니다. actions/cache 액션이나 Docker 빌드의 캐싱 옵션을 활용하면 재빌드 시간을 획기적으로 줄일 수 있습니다. 제 프로젝트에서는 캐싱 적용 후 평균 워크플로우 실행 시간이 2분 이상 단축되었습니다.
  • 매트릭스(Matrix) 전략: 여러 버전의 Node.js, Python, 또는 다양한 운영체제에서 테스트를 실행해야 할 때 매트릭스 빌드를 사용하면 병렬로 워크플로우를 실행하여 시간을 절약할 수 있습니다.
  • 환경 변수 및 Secrets 관리: GitHub Secrets는 민감한 정보를 안전하게 관리하는 데 필수적입니다. 데이터베이스 비밀번호, API 키, 클라우드 자격 증명 등을 Secrets에 저장하고 워크플로우에서 ${{ secrets.MY_SECRET }} 형태로 사용하세요. 일반적인 환경 변수는 env 키워드를 사용합니다.
  • 워크플로우 시각화 및 모니터링: GitHub UI에서 워크플로우 실행 상태를 시각적으로 확인할 수 있으며, 각 단계의 로그를 통해 문제 발생 시 빠르게 디버깅할 수 있습니다. Slack이나 기타 알림 서비스와 연동하여 워크플로우 실패 시 즉시 알림을 받는 것도 중요합니다.
  • 재사용 가능한 액션 및 워크플로우: 반복되는 작업은 커스텀 액션을 만들거나 재사용 가능한 워크플로우(Reusable workflows)로 분리하여 관리하면 유지보수성이 높아집니다. 예를 들어, 특정 언어의 빌드 스텝을 하나의 액션으로 만들 수 있습니다.
  • 실패 처리 및 롤백 전략: 배포는 항상 성공하는 것이 아닙니다. 배포 실패 시 자동으로 이전 버전으로 롤백하거나, 수동 롤백 절차를 명확히 정의해 두어야 합니다. if: always()if: failure()와 같은 조건문을 사용하여 실패 시 특정 작업을 실행하도록 설정할 수도 있습니다.

마무리: 자동화된 개발 워크플로우의 미래

GitHub Actions를 활용한 CI/CD 파이프라인 구축은 저의 개발 프로세스에 혁명적인 변화를 가져왔습니다. 반복적인 수동 작업에서 벗어나 더 중요한 기능 개발에 집중할 수 있게 되었고, 코드 품질은 향상되었으며, 서비스 배포에 대한 불안감도 크게 줄었습니다. 테스트 자동화를 통해 버그를 조기에 발견하고, 빌드 자동화로 일관된 아티팩트를 생성하며, 배포 자동화로 빠르고 안정적으로 서비스를 제공할 수 있게 된 것이죠. 이는 단순한 도구의 사용을 넘어, DevOps 문화의 핵심을 실천하는 과정이었습니다.

물론 CI/CD 파이프라인 구축이 항상 순조롭지만은 않습니다. 초기 설정의 어려움, 복잡한 워크플로우 디버깅, 그리고 다양한 환경에 맞는 배포 전략 수립 등 여러 도전 과제가 있었습니다. 하지만 그 과정에서 얻은 경험과 지식은 어떤 어려움도 감수할 만한 가치가 있었습니다. GitHub Actions는 지속적으로 발전하고 있으며, 앞으로도 더 많은 기능과 개선 사항이 추가될 것으로 기대됩니다.

여러분도 GitHub Actions를 활용하여 자신만의 CI/CD 파이프라인을 구축하고, 개발 생산성을 한 단계 끌어올려 보시길 강력히 추천합니다. 혹시 이 글을 읽으면서 궁금한 점이 생기셨거나, 여러분만의 GitHub Actions 활용 팁이 있다면 댓글로 자유롭게 공유해주세요! 함께 더 나은 개발 워크플로우를 만들어가요.

📌 함께 읽으면 좋은 글

  • [기술 리뷰] React, Vue, Svelte 비교 분석: 모던 프론트엔드 프레임워크 선택 가이드
  • [튜토리얼] FastAPI RESTful API 서버 구축: 데이터베이스 연동과 CRUD 구현 실전 가이드
  • [보안] 시크릿 관리 자동화: 개발부터 프로덕션까지 민감 정보 처리 전략

이 글이 도움이 되셨다면 공감(♥)댓글로 응원해 주세요!
궁금한 점이나 다루었으면 하는 주제가 있다면 댓글로 남겨주세요.

반응형