GitHub Actions란? - 현업에서 가장 인기있는 CI/CD 도구

김현정·2025년 5월 22일
0

🚀 GitHub Actions란? - 현업에서 가장 인기있는 CI/CD 도구


GitHub Actions란?

GitHub Actions는 GitHub에서 제공하는 CI/CD(Continuous Integration/Continuous Deployment) 플랫폼입니다.

코드 저장소에서 직접 소프트웨어 개발 워크플로우를 자동화할 수 있게 해주는 서비스로, 2019년 출시 이후 현재 세계에서 가장 인기있는 CI/CD 도구 중 하나가 되었습니다.

주요 특징

  • GitHub 네이티브: 별도 서버 설치 불필요
  • YAML 기반: 직관적이고 간단한 설정
  • 무료 제공: Public 저장소는 무제한, Private도 월 2,000분 무료
  • 풍부한 마켓플레이스: 수천 개의 사전 제작된 액션들
  • 클라우드 실행: GitHub에서 제공하는 러너에서 실행

왜 GitHub Actions인가?

📊 2024년 CI/CD 도구 사용률

1위: GitHub Actions (45%)
2위: GitLab CI/CD (22%)
3위: Jenkins (18%)
4위: Azure DevOps (8%)
5위: 기타 (7%)

출처: Stack Overflow Developer Survey 2024

GitHub Actions를 선택해야 하는 이유

압도적인 편의성

# .github/workflows/ci.yml
name: CI
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

단 8줄로 CI 완성! 🎉

GitHub과의 완벽한 통합

  • Pull Request와 자동 연동
  • Issues, Projects와 연계 가능
  • GitHub 보안 기능 활용

강력한 마켓플레이스

  • 12,000+ 사전 제작된 액션
  • 복사-붙여넣기로 즉시 사용 가능
  • 커뮤니티 기여 활발

현업 표준

"스타트업부터 대기업까지, 신규 프로젝트의 80%가 GitHub Actions를 채택" - GitHub 2024 Report


핵심 개념 이해하기

1. Workflow (워크플로우)

  • CI/CD 프로세스 전체를 정의하는 YAML 파일
  • .github/workflows/ 디렉토리에 위치

2. Event (이벤트)

  • Workflow를 실행시키는 트리거
on:
  push:              # 코드 푸시 시
  pull_request:      # PR 생성/수정 시
  schedule:          # 주기적 실행
  workflow_dispatch: # 수동 실행

3. Job (작업)

  • 동일한 러너에서 실행되는 단계들의 집합
  • 기본적으로 병렬 실행됨

4. Step (단계)

  • Job 내의 개별 작업 단위
  • 액션 실행 또는 쉘 명령어 실행

5. Action (액션)

  • 재사용 가능한 코드 단위
  • 마켓플레이스에서 다운로드 가능

6. Runner (러너)

  • Workflow를 실행하는 서버
  • GitHub 호스팅 또는 자체 호스팅 가능

첫 번째 Workflow 만들기

Step 1: 파일 생성

# 프로젝트 루트에서
mkdir -p .github/workflows
touch .github/workflows/hello-world.yml

Step 2: 기본 Workflow 작성

# .github/workflows/hello-world.yml
name: Hello World

# 언제 실행할지 정의
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

# 실행할 작업들 정의
jobs:
  hello:
    runs-on: ubuntu-latest  # 실행 환경
    
    steps:
    - name: 인사하기
      run: echo "안녕하세요, GitHub Actions!"
      
    - name: 현재 시간 출력
      run: date
      
    - name: 시스템 정보
      run: |
        echo "운영체제: $(uname -s)"
        echo "프로세서: $(uname -m)"
        echo "사용자: $(whoami)"

Step 3: 커밋 & 푸시

git add .github/
git commit -m "feat: GitHub Actions Hello World 추가"
git push origin main

Step 4: 결과 확인

  1. GitHub 저장소 → Actions 탭 클릭
  2. 실행 중인 워크플로우 확인
  3. 로그 상세 보기

실전 예제: Spring Boot CI/CD

프로젝트 구조

my-spring-app/
├── .github/
│   └── workflows/
│       └── ci-cd.yml
├── src/
├── build.gradle
└── Dockerfile

완전한 CI/CD Pipeline

# .github/workflows/ci-cd.yml
name: 🚀 Spring Boot CI/CD

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # 테스트 단계
  test:
    runs-on: ubuntu-latest
    
    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: testpassword
          MYSQL_DATABASE: testdb
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3
    
    steps:
    - name: 코드 체크아웃
      uses: actions/checkout@v4
      
    - name: Java 17 설정
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        
    - name: Gradle 캐시 설정
      uses: actions/cache@v3
      with:
        path: |
          ~/.gradle/caches
          ~/.gradle/wrapper
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
        restore-keys: |
          ${{ runner.os }}-gradle-
          
    - name: Gradle 실행 권한 부여
      run: chmod +x gradlew
      
    - name: 정적 분석 (Checkstyle)
      run: ./gradlew checkstyleMain checkstyleTest
      
    - name: 단위 테스트 실행
      run: ./gradlew test
      env:
        SPRING_DATASOURCE_URL: jdbc:mysql://localhost:3306/testdb
        SPRING_DATASOURCE_USERNAME: root
        SPRING_DATASOURCE_PASSWORD: testpassword
        
    - name: 테스트 결과 발행
      uses: dorny/test-reporter@v1
      if: success() || failure()
      with:
        name: 테스트 결과
        path: build/test-results/test/*.xml
        reporter: java-junit
        
    - name: 코드 커버리지
      run: ./gradlew jacocoTestReport
      
    - name: 커버리지 업로드 (Codecov)
      uses: codecov/codecov-action@v3
      with:
        file: build/reports/jacoco/test/jacocoTestReport.xml

  # 빌드 단계
  build:
    needs: test
    runs-on: ubuntu-latest
    
    steps:
    - name: 코드 체크아웃
      uses: actions/checkout@v4
      
    - name: Java 17 설정
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        
    - name: Gradle 캐시 설정
      uses: actions/cache@v3
      with:
        path: |
          ~/.gradle/caches
          ~/.gradle/wrapper
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
        
    - name: JAR 빌드
      run: ./gradlew bootJar
      
    - name: 빌드 결과물 저장
      uses: actions/upload-artifact@v3
      with:
        name: spring-boot-jar
        path: build/libs/*.jar
        retention-days: 30

  # Docker 빌드
  docker-build:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      
    steps:
    - name: 코드 체크아웃
      uses: actions/checkout@v4
      
    - name: 빌드 결과물 다운로드
      uses: actions/download-artifact@v3
      with:
        name: spring-boot-jar
        path: build/libs/
        
    - name: Docker Buildx 설정
      uses: docker/setup-buildx-action@v3
      
    - name: Container Registry 로그인
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
        
    - name: 메타데이터 추출
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=sha,prefix={{branch}}-
          
    - name: Docker 이미지 빌드 & 푸시
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

  # 배포 단계 (개발 환경)
  deploy-dev:
    if: github.ref == 'refs/heads/develop'
    needs: [test, build, docker-build]
    runs-on: ubuntu-latest
    environment: development
    
    steps:
    - name: 개발 서버 배포
      run: |
        echo "개발 환경에 배포 중..."
        echo "배포 완료: https://dev.myapp.com"
        
    - name: 🔍 헬스체크
      run: |
        sleep 30
        curl -f https://dev.myapp.com/actuator/health
        
    - name: 💬 슬랙 알림 (성공)
      if: success()
      uses: 8398a7/action-slack@v3
      with:
        status: success
        channel: '#dev-alerts'
        text: |
          개발 환경 배포 성공!
          
          커밋: ${{ github.event.head_commit.message }}
          작성자: ${{ github.actor }}
          서비스: https://dev.myapp.com
          테스트: 모든 테스트 통과
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

  # 배포 단계 (운영 환경)
  deploy-prod:
    if: github.ref == 'refs/heads/main'
    needs: [test, build, docker-build]
    runs-on: ubuntu-latest
    environment: production  # GitHub Environment 보호 규칙 적용
    
    steps:
    - name: 보안 스캔
      run: |
        echo "보안 취약점 검사 중..."
        echo "보안 검사 완료 - 문제 없음"
        
    - name: 성능 테스트
      run: |
        echo "성능 테스트 실행 중..."
        echo "응답시간: 평균 120ms (기준: 200ms)"
        echo "처리량: 1,200 TPS (기준: 1,000 TPS)"
        
    - name: Blue-Green 배포
      run: |
        echo "Blue-Green 배포 시작..."
        echo "Blue 환경에 새 버전 배포"
        echo "Blue 환경 헬스체크 완료"
        echo "트래픽을 Blue로 전환"
        echo "Green 환경 정리"
        echo "배포 완료: https://myapp.com"
        
    - name: 모니터링 설정
      run: |
        echo "Grafana 대시보드 업데이트"
        echo "알람 규칙 적용"
        echo "로그 수집 시작"
        
    - name: 배포 성공 알림
      uses: 8398a7/action-slack@v3
      with:
        status: success
        channel: '#prod-alerts'
        text: |
          운영 환경 배포 성공!
          
          버전: ${{ github.sha }}
          배포자: ${{ github.actor }}
          서비스: https://myapp.com
          모니터링: https://grafana.myapp.com
          
          주요 변경사항:
          ${{ github.event.head_commit.message }}
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

GitHub Secrets 설정

Repository Settings → Secrets and variables → Actions

필수 Secrets:
- SLACK_WEBHOOK_URL: 슬랙 웹훅 URL
- DB_PASSWORD: 데이터베이스 비밀번호
- JWT_SECRET_KEY: JWT 시크릿 키
- AWS_ACCESS_KEY_ID: AWS 액세스 키 (AWS 배포 시)
- AWS_SECRET_ACCESS_KEY: AWS 시크릿 키

고급 기능들

1. 조건부 실행

jobs:
  deploy:
    if: github.ref == 'refs/heads/main'  # main 브랜치만
    steps:
      - name: 조건부 단계
        if: contains(github.event.head_commit.message, '[deploy]')
        run: echo "배포 키워드 감지됨!"

2. 매트릭스 빌드

jobs:
  test:
    strategy:
      matrix:
        java-version: [11, 17, 21]
        os: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-java@v4
        with:
          java-version: ${{ matrix.java-version }}

3. 환경별 배포

jobs:
  deploy:
    environment: 
      name: ${{ github.ref == 'refs/heads/main' && 'production' || 'development' }}
      url: ${{ github.ref == 'refs/heads/main' && 'https://prod.myapp.com' || 'https://dev.myapp.com' }}

4. 재사용 가능한 워크플로우

# .github/workflows/reusable-test.yml
name: 재사용 가능한 테스트
on:
  workflow_call:
    inputs:
      java-version:
        required: true
        type: string

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-java@v4
        with:
          java-version: ${{ inputs.java-version }}
# 다른 워크플로우에서 사용
jobs:
  call-reusable:
    uses: ./.github/workflows/reusable-test.yml
    with:
      java-version: '17'

⚔️ Jenkins vs GitHub Actions

항목JenkinsGitHub Actions
설정 복잡도🔴 복잡 (Groovy, 플러그인)🟢 간단 (YAML)
서버 관리🔴 직접 관리 필요🟢 GitHub에서 관리
비용🟡 서버 비용 발생🟢 Public 무료, Private 제한적 무료
학습 곡선🔴 가파름🟢 완만함
커뮤니티🟡 오래된 커뮤니티🟢 급성장하는 커뮤니티
확장성🟢 매우 높음🟡 제한적
기업 지원🟢 강력함🟡 발전 중
GitHub 통합🟡 플러그인 필요🟢 네이티브 지원

📊 언제 어떤 걸 선택할까?

GitHub Actions 추천 상황:

  • GitHub 사용 중
  • 빠른 시작이 필요
  • 소~중규모 프로젝트
  • 최신 기술 스택 사용
  • 팀원들의 DevOps 경험 부족

Jenkins 추천 상황:

  • 복잡한 엔터프라이즈 환경
  • 기존 Jenkins 인프라 보유
  • 높은 커스터마이징 요구
  • 온프레미스 환경 필수
  • 매우 큰 규모의 빌드

실무 팁 & 베스트 프랙티스

성능 최적화

1. 캐시 적극 활용

- name: 🐘 Gradle 캐시
  uses: actions/cache@v3
  with:
    path: |
      ~/.gradle/caches
      ~/.gradle/wrapper
    key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
    restore-keys: |
      ${{ runner.os }}-gradle-

2. 병렬 실행 최대화

jobs:
  test:
    strategy:
      matrix:
        test-group: [unit, integration, e2e]
  
  lint:
    runs-on: ubuntu-latest
    # test와 병렬 실행됨

3. 불필요한 트리거 방지

on:
  push:
    paths-ignore:
      - '**.md'
      - 'docs/**'
  pull_request:
    paths:
      - 'src/**'
      - 'build.gradle'

보안 베스트 프랙티스

1. Secrets 관리

env:
  DB_PASSWORD: ${{ secrets.DB_PASSWORD }}  # ✅ 올바름
  API_KEY: "my-secret-key"                 # ❌ 위험함

2. 최소 권한 원칙

jobs:
  deploy:
    permissions:
      contents: read    # 최소한의 권한만
      packages: write   # 필요한 권한만

3. 신뢰할 수 있는 액션 사용

- uses: actions/checkout@v4        # ✅ 공식 액션
- uses: docker/build-push-action@v5 # ✅ 검증된 액션
- uses: random-user/unsafe-action   # ❌ 위험할 수 있음

📊 모니터링 & 알림

1. 실패 시 즉시 알림

- name: 💬 실패 알림
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: failure
    text: |
      🚨 빌드 실패!
      
      📋 브랜치: ${{ github.ref }}
      👤 커밋: ${{ github.actor }}
      🔗 로그: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

2. 배포 상태 추적

- name: 📊 배포 상태 업데이트
  uses: chrnorm/deployment-action@v2
  with:
    token: ${{ secrets.GITHUB_TOKEN }}
    environment: production
    state: success

🎯 팀 협업 팁

1. 워크플로우 명확히 네이밍

name: 🚀 Production Deploy  # ✅ 명확함
name: CI                   # ❌ 모호함

2. 단계별 이모지 활용

- name<: 📥 코드 체크아웃
- name: ☕ Java 설정
- name: 🧪 테스트 실행
- name: 📦 빌드
- name: 🚀 배포

3. 실패 원인 명확히 표시

- name: 🧪 테스트 실행
  run: |
    echo "::group::Unit Tests"
    ./gradlew test
    echo "::endgroup::"
    
    echo "::group::Integration Tests"
    ./gradlew integrationTest
    echo "::endgroup::"

결론

GitHub Actions는 현재 가장 접근하기 쉽고 강력한 CI/CD 플랫폼입니다.

핵심 장점

  • 진입 장벽이 낮음: YAML 문법으로 쉽게 시작
  • GitHub 생태계: 완벽한 통합과 풍부한 마켓플레이스
  • 현업 표준: 대부분의 신규 프로젝트에서 채택
  • 무료 시작: 충분한 무료 사용량 제공

다음 단계

  1. 간단한 Hello World 워크플로우로 시작
  2. 실제 프로젝트에 CI 적용
  3. CD(배포) 기능 추가
  4. 팀 협업 워크플로우 구축
  5. 모니터링 및 알림 시스템 구축

GitHub Actions로 현대적인 DevOps 문화를 경험해보세요! 🎉


참고 자료

0개의 댓글