GitHub Actions vs Jenkins — 팀 규모별 CI/CD 선택 기준

“Jenkins 쓰고 있는데 넘어가도 되나요?” GitHub Actions vs Jenkins 선택은 기능 비교보다 팀 상황이 먼저다. 서버를 관리할 인력이 있는가, 코드가 GitHub에 있는가, 보안 정책이 SaaS를 허용하는가. 이 세 가지로 판단이 끝난다.

한눈에 보는 GitHub Actions vs Jenkins 비교

GitHub ActionsJenkins
호스팅GitHub 관리 (SaaS)직접 서버 운영
설정 파일.github/workflows/*.ymlJenkinsfile + 플러그인
비용공개 레포 무료, 비공개 월 2,000분 무료무료 (서버 비용 + 운영 공수 별도)
러닝 커브낮음높음
확장마켓플레이스 19,000+ 액션플러그인 1,800+
GitHub 연동네이티브웹훅 + 플러그인
자체 호스팅Self-hosted runner 지원기본
시크릿 관리GitHub Secrets (UI)Jenkins Credentials (플러그인)
적합 환경GitHub 기반 소규모 팀온프레미스, 대규모 멀티 레포

결론부터 말하면, 코드가 GitHub에 있고 CI/CD 전담 인력이 없다면 GitHub Actions가 맞다. Jenkins가 필요한 경우는 뒤에서 명확하게 짚는다.


GitHub Actions — YAML 한 파일로 끝난다

GitHub Actions의 최대 장점은 별도 서버 없이 시작할 수 있다는 점이다. 레포에 .github/workflows/ 디렉토리를 만들고 YAML 파일 하나를 넣으면 된다.

# .github/workflows/ci.yml — 기본 테스트 파이프라인
name: CI

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

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]  # 여러 버전 동시 테스트
    steps:
      - uses: actions/checkout@v4

      - name: Node.js ${{ matrix.node-version }} 설정
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: 의존성 설치
        run: npm ci

      - name: 테스트
        run: npm test

PR을 올리면 자동으로 위 워크플로우가 실행되고, 결과가 PR 화면에 바로 표시된다. 테스트가 실패하면 머지 버튼이 비활성화된다. 이 연동이 GitHub 네이티브이기 때문에 별도 웹훅 설정이 필요 없다.

테스트 통과 후 main에 머지되면 자동으로 배포까지 이어지는 전체 파이프라인은 아래처럼 만든다.

# .github/workflows/deploy.yml — Docker 빌드 + 서버 배포
name: Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Docker Hub 로그인
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Docker 이미지 빌드 및 푸시
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: myapp:${{ github.sha }}

      - name: 서버 배포 (SSH)
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            docker pull myapp:${{ github.sha }}
            docker stop myapp || true
            docker run -d --name myapp -p 3000:3000 myapp:${{ github.sha }}

secrets.DOCKER_PASSWORD, secrets.SSH_PRIVATE_KEY 같은 민감 정보는 GitHub 레포 Settings > Secrets에 등록한다. YAML 파일에 직접 쓰이지 않고 런타임에 주입되므로 코드에 노출되지 않는다.

마켓플레이스에서 AWS 배포, Slack 알림, 코드 커버리지 리포트 등 19,000개 이상의 액션을 가져다 쓸 수 있다. uses: 한 줄이면 된다.

GitHub Actions의 한계:

  • GitHub에 종속된다. GitLab이나 Bitbucket으로 이전하면 파이프라인도 다시 짜야 한다
  • 비공개 레포는 월 2,000분 초과 시 과금 발생
  • 복잡한 멀티 스테이지 파이프라인은 YAML이 길어져 관리가 번거롭다
  • 로컬에서 워크플로우를 직접 실행하기 어렵다 (act 도구로 부분 재현 가능)

Jenkins — 자유도가 높은 만큼 관리 비용이 따른다

Jenkins(젠킨스)는 직접 서버에 설치해서 운영하는 CI/CD 도구다. 2011년부터 쓰여온 만큼 생태계가 넓고, 어떤 환경이든 연동할 수 있다는 게 강점이다.

// Jenkinsfile — 병렬 실행 파이프라인
pipeline {
    agent any

    environment {
        DOCKER_CREDENTIALS = credentials('docker-hub-credentials')
    }

    stages {
        stage('병렬 테스트') {
            parallel {
                stage('단위 테스트') {
                    steps { sh 'npm test' }
                }
                stage('린트') {
                    steps { sh 'npm run lint' }
                }
                stage('타입 체크') {
                    steps { sh 'npm run typecheck' }
                }
            }
        }

        stage('빌드') {
            steps {
                sh 'npm run build'
                sh "docker build -t myapp:${env.BUILD_NUMBER} ."
            }
        }

        stage('배포') {
            when { branch 'main' }
            steps {
                withCredentials([usernamePassword(
                    credentialsId: 'docker-hub-credentials',
                    usernameVariable: 'DOCKER_USER',
                    passwordVariable: 'DOCKER_PASS'
                )]) {
                    sh '''
                        docker login -u $DOCKER_USER -p $DOCKER_PASS
                        docker push myapp:${BUILD_NUMBER}
                    '''
                }
            }
        }
    }

    post {
        failure {
            slackSend channel: '#deploy', message: "빌드 실패: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
        }
    }
}

parallel 블록으로 여러 스테이지를 동시에 실행할 수 있다. 단위 테스트, 린트, 타입 체크를 병렬로 돌리면 전체 파이프라인 시간이 줄어든다. 이 수준의 파이프라인 제어는 Jenkins가 강점이다.

여러 프로젝트에서 공통 파이프라인 로직을 재사용하려면 Shared Library를 만든다. 배포 스크립트, 알림 함수, 환경별 설정을 라이브러리로 만들어 각 Jenkinsfile에서 @Library('my-pipeline-lib') 한 줄로 불러온다. 20개 레포를 관리하는 팀이라면 이 기능이 생산성에 크게 기여한다.

문제는 Jenkins를 돌릴 서버를 관리해야 한다는 점이다. Java 기반이라 JVM 메모리 튜닝이 필요하고, 플러그인 업데이트가 다른 플러그인과 충돌하는 일이 빈번하다. Jenkins 서버가 죽으면 팀 전체 배포가 멈춘다.

Jenkins가 여전히 유효한 이유:

  • 온프레미스 필수 환경(금융, 의료, 공공기관)에서는 SaaS를 쓸 수 없다
  • GitHub, GitLab, Bitbucket, SVN 등 어떤 소스 저장소든 연결 가능
  • Shared Library로 수십 개 프로젝트 파이프라인을 중앙 관리
  • 파이프라인 커스터마이징에 사실상 제한이 없다

선택 기준 — 팀 상황으로 판단한다

GitHub Actions를 써야 하는 경우:

  • 코드가 GitHub에 있다
  • 팀이 10명 이하다
  • CI/CD 전담 인력(DevOps 엔지니어)이 없다
  • 지금 당장 파이프라인을 구축해야 한다
  • 서버 관리에 시간을 쓰고 싶지 않다

Jenkins가 맞는 경우:

  • 보안 정책상 코드가 외부 SaaS를 거칠 수 없다
  • 온프레미스 배포가 필수다
  • GitHub 외 다른 저장소(GitLab, Bitbucket, SVN)를 함께 쓴다
  • 이미 Jenkins 인프라가 있고 마이그레이션 비용이 크다
  • 20개 이상 레포를 Shared Library로 중앙 관리해야 한다

GitHub Actions vs Jenkins CI/CD 도구 비교에서 핵심은 이거다. 새 프로젝트에서 Jenkins를 처음 도입하는 건 대부분 오버 엔지니어링이다. 위 조건에 해당하지 않는다면 GitHub Actions로 시작하는 게 낫다.


GitHub Actions 과금 — 실제로 돈이 얼마나 나오나

비공개 레포 기준으로 월 2,000분이 무료다. 초과분은 Linux 러너 기준 분당 $0.008이다.

월 2,000분 무료 (비공개 레포, Linux 기준)
초과 시: $0.008/분 (Linux), $0.016/분 (Windows), $0.08/분 (macOS)

예시 — 5인 팀:
- 하루 20번 빌드 x 평균 5분 = 100분/일
- 월 22 영업일 = 2,200분/월
- 초과분 200분 x $0.008 = $1.6/월

소규모 팀이면 무료 범위를 넘기 어렵다. 넘더라도 월 몇 달러 수준이다. 반면 Jenkins를 직접 운영하면 서버 비용(월 $20~50), 업데이트와 장애 대응 인건비가 매달 발생한다.

macOS나 Windows 러너는 Linux보다 훨씬 비싸다. 크로스 플랫폼 빌드가 필요하거나 빌드 시간이 길어 과금이 부담되면 Self-hosted runner가 답이다.

# Self-hosted runner 사용 — ubuntu-latest 대신 self-hosted 지정
jobs:
  build:
    runs-on: self-hosted  # 내 서버에서 실행
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test

Self-hosted runner는 GitHub 레포 Settings > Actions > Runners에서 등록한다. 스크립트 한 줄로 내 서버에 에이전트를 설치하면 끝이다. GitHub Actions 워크플로우 문법은 그대로 쓰면서 과금만 없앨 수 있다. 처음 서버 배포 체크리스트에서 runner를 올릴 서버 초기 설정을 확인하자.


GitHub Actions vs Jenkins 마이그레이션 판단 기준

이미 Jenkins를 쓰고 있다면 바로 넘어갈 필요는 없다. 다만 아래 상황이라면 마이그레이션을 고려할 만하다.

  • Jenkins 서버 장애가 분기 1회 이상 발생한다
  • 플러그인 충돌로 업데이트를 수개월째 미루고 있다
  • Jenkins 관리할 수 있는 사람이 팀에 한 명뿐이고 그 사람이 나갔다
  • 새로 합류하는 팀원이 Jenkins 설정을 이해하는 데 일주일 이상 걸린다

마이그레이션은 한 번에 하지 않아도 된다. 새 레포부터 GitHub Actions를 적용하고, 기존 레포는 여유가 생길 때 순차적으로 옮기면 된다. Jenkinsfile의 각 스테이지를 GitHub Actions의 jobssteps로 1:1 대응해서 옮기면 전환 비용이 크지 않다.

Docker 컨테이너가 바로 종료되는 문제는 GitHub Actions와 Jenkins 모두에서 발생하니 배포 파이프라인 구축 시 참고하자.


자주 묻는 질문

Q. GitHub Actions와 Jenkins를 동시에 쓸 수 있나?

된다. 테스트와 린트는 GitHub Actions로, 운영 배포는 Jenkins로 나누는 팀도 있다. 다만 파이프라인이 두 곳에 분산되면 관리 포인트가 늘어나므로 장기적으로는 하나로 통일하는 게 맞다.

Q. GitLab CI/CD는 어떤가?

코드가 GitLab에 있다면 GitLab CI/CD가 GitHub Actions와 같은 포지션이다. 선택 기준도 동일하다. 코드가 있는 플랫폼의 네이티브 CI/CD를 쓰는 게 연동이 가장 간단하다.

Q. 모놀리식 구조도 GitHub Actions로 배포할 수 있나?

문제없다. 모놀리식이든 마이크로서비스든 빌드와 배포 스크립트만 있으면 YAML에 넣을 수 있다. 다만 마이크로서비스처럼 수십 개 레포를 한 번에 관리해야 하는 상황이면 Jenkins의 Shared Library와 멀티브랜치 파이프라인이 편할 수 있다.

Q. 시크릿 관리는 어느 쪽이 더 낫나?

GitHub Actions는 레포 Settings에서 UI로 시크릿을 등록하고 YAML에서 ${{ secrets.MY_KEY }}로 쓴다. Jenkins는 Credentials 플러그인으로 관리하고 withCredentials 블록에서 사용한다. 팀 단위 시크릿 관리와 접근 제어가 필요하면 Jenkins의 Credentials 시스템이 더 세밀하지만, 일반적인 규모에서는 GitHub Secrets로 충분하다.


GitHub Actions vs Jenkins — 코드가 GitHub에 있고, 서버 관리할 인력이 없고, 보안상 SaaS 제한이 없다면 GitHub Actions다. Jenkins는 온프레미스 필수, 멀티 저장소, Shared Library 기반 대규모 파이프라인 관리가 필요할 때 유효하다.

댓글 남기기