“Jenkins 쓰고 있는데 넘어가도 되나요?” GitHub Actions vs Jenkins 선택은 기능 비교보다 팀 상황이 먼저다. 서버를 관리할 인력이 있는가, 코드가 GitHub에 있는가, 보안 정책이 SaaS를 허용하는가. 이 세 가지로 판단이 끝난다.
한눈에 보는 GitHub Actions vs Jenkins 비교
| GitHub Actions | Jenkins | |
|---|---|---|
| 호스팅 | GitHub 관리 (SaaS) | 직접 서버 운영 |
| 설정 파일 | .github/workflows/*.yml | Jenkinsfile + 플러그인 |
| 비용 | 공개 레포 무료, 비공개 월 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의 jobs와 steps로 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 기반 대규모 파이프라인 관리가 필요할 때 유효하다.