개발 도구

Jenkins 빌드 스케줄러 완벽 가이드 — Jenkinsfile에 cron 트리거 추가하는 방법

Jenkins UI에서 직접 관리하던 파이프라인을 Jenkinsfile로 전환하고, cron 트리거로 매일 자동 빌드를 구성하는 방법을 정리했다.

JenkinsCI/CD파이프라인cron자동배포
Jenkins Configure 화면의 Triggers 섹션 — Build periodically 체크 후 'H 17 * * *' cron 표현식을 입력한 상태. 다음 실행 예정 시각이 UTC 기준으로 표시되어 있다.
  • ·Jenkins 최초 출시: 2011년 (Hudson 포크)
  • ·cron 표현식: 분 시 일 월 요일 순서로 5개 필드
  • ·Jenkinsfile 위치: 프로젝트 루트 디렉토리
  • ·triggers 등록: 파이프라인을 최소 1회 수동 실행해야 스케줄 활성화
Next.js 정적 사이트 빌드를 Jenkins UI에서 직접 관리하다가 Jenkinsfile로 전환했다. triggers { cron('H 17 * * *') } 블록을 추가하고 파일만 저장하면 스케줄이 알아서 등록될 줄 알았는데, Job을 한 번 수동으로 실행해야 비로소 스케줄이 잡힌다는 걸 직접 겪고 나서 알았다. Jenkins 서버가 UTC로 돌고 있어서 한국 시간 새벽 2시를 맞추려면 UTC 17시를 입력해야 했고, 정각(0분) 대신 H를 쓰면 서버 부하를 분산해준다는 것도 그때 처음 확인했다.

Jenkins란 무엇인가

Jenkins가 CI/CD 자동화 서버로 쓰이는 이유

Jenkins는 소프트웨어 빌드, 테스트, 배포 파이프라인 전체를 자동으로 처리해주는 오픈소스 자동화 서버다. 2004년 Sun Microsystems에서 Hudson이라는 이름으로 처음 만들어졌고, 2011년 Oracle과의 분쟁으로 커뮤니티가 분리되면서 Jenkins라는 이름으로 독립했다. Java로 작성됐고 WAR 파일로 배포되기 때문에 Tomcat 같은 서블릿 컨테이너 위에 올리거나, 내장 Jetty 서버로 단독 실행하는 것도 가능하다. 처음 Jenkins 관리 화면을 열면 플러그인 관리, 시스템 설정, 자격증명 항목들이 잔뜩 나와서 어디서 시작해야 할지 막막한데, 막상 파이프라인 하나 만들어보면 구조 자체는 단순하다는 걸 알게 된다. 플러그인이 2000개가 넘어서 웬만한 배포 시나리오는 조합만으로 다 해결된다. GitHub Actions나 GitLab CI 같은 클라우드 기반 대안들이 많이 나왔지만, 외부 인터넷이 차단된 내부망 환경이나 온프레미스 서버에서 직접 제어해야 하는 상황이라면 여전히 Jenkins가 가장 현실적인 선택이다.

Jenkins 빌드 파이프라인의 두 가지 방식

Jenkins에서 빌드 자동화를 구성하는 방법은 크게 두 가지다. 첫 번째는 Jenkins UI에서 직접 파이프라인 스크립트를 입력하는 방식이다. Job 설정 화면의 Pipeline 섹션에 Groovy 스크립트를 바로 작성하는 방식으로, 파일을 따로 만들 필요 없이 빠르게 시작할 수 있다. 처음 Jenkins를 접할 때 이 방식으로 시작하는 경우가 많은데, 문제는 빌드 설정이 Jenkins 서버 안에만 저장된다는 점이다. 변경 이력을 추적할 수 없고, 서버를 재설치하거나 마이그레이션할 때 설정을 처음부터 다시 입력해야 한다. 실제로 서버 이전 작업을 하면서 이 방식으로 관리하던 파이프라인을 전부 다시 작성한 적이 있다. 두 번째는 프로젝트 루트에 Jenkinsfile을 만들고, Job 설정에서 'Pipeline script from SCM'을 선택해서 Git 저장소에서 읽어오는 방식이다. 빌드 설정이 코드와 함께 버전 관리되고, 팀원 모두가 동일한 파이프라인을 공유할 수 있다. 초기 셋업이 조금 번거롭지만, 한 번 구성해두면 이후 수정은 Jenkinsfile을 commit하는 것만으로 끝난다.

Jenkins 트리거(Trigger)의 종류와 역할

Jenkins에서 cron 트리거란 무엇인가

Jenkins에서 트리거(Trigger)는 특정 조건이 충족되면 빌드를 자동으로 시작하라는 규칙이다. 트리거 없이는 매번 직접 Build Now 버튼을 눌러야 한다. cron 트리거는 그중에서도 시간 기반으로 빌드를 실행하는 방식으로, 리눅스의 crontab과 동일한 문법을 사용한다. 매일 새벽 자동 배포, 주말마다 전체 테스트 실행, 매월 1일 리포트 생성처럼 특정 시각에 반복적으로 실행해야 하는 작업에 적합하다. Jenkinsfile에서는 triggers { cron('H 2 * * *') } 형태로 선언한다. cron 트리거를 처음 사용하면서 가장 헷갈렸던 부분은, Jenkinsfile에 블록을 추가하고 저장만 하면 스케줄이 바로 등록될 거라고 착각한 것이었다. 실제로는 파이프라인을 한 번 직접 실행해야 Jenkins가 트리거를 인식하고 스케줄을 잡는다. 이걸 모르고 하루를 기다렸다가 빌드가 한 번도 안 돈 걸 확인한 뒤 찾아봤다. 처음 설정할 때 반드시 수동 실행을 먼저 한 번 해야 한다는 걸 기억해두면 이 삽질은 피할 수 있다.

Jenkins cron을 포함한 주요 트리거 종류 비교

Jenkins에서 자주 쓰는 트리거는 네 가지다. 첫 번째인 cron은 시간 기반 스케줄로 매일 특정 시각이나 주기마다 빌드를 실행한다. 사람이 아무것도 하지 않아도 정해진 시각에 자동으로 빌드가 돌아가는 방식이라, 매일 새벽에 배포가 필요하거나 정기적인 데이터 처리 작업이 있을 때 주로 쓴다. 두 번째인 pollSCM은 설정한 주기마다 Git 저장소를 직접 확인해서 새 커밋이 있을 때만 빌드를 실행한다. cron과 달리 코드가 바뀌었을 때만 반응하지만, Jenkins가 주기적으로 저장소를 직접 폴링하기 때문에 Webhook 방식보다 응답이 느리다. 세 번째인 GitHub Webhook 방식은 push가 발생하는 순간 GitHub가 Jenkins에 HTTP 알림을 보내 즉시 빌드를 시작한다. 응답이 가장 빠르고 불필요한 폴링이 없어서 일반적인 배포에는 Webhook이 사실상 표준처럼 쓰인다. 다만 Jenkins 서버가 외부에서 접근 가능해야 한다는 조건이 붙는다. 네 번째인 upstream은 다른 Jenkins Job이 완료되면 연쇄적으로 현재 Job을 실행한다. 빌드가 끝나면 테스트를 자동으로 돌리거나, 테스트 통과 후 자동 배포까지 이어지는 멀티 스테이지 파이프라인을 구성할 때 유용하다.

cron 표현식 이해하기

Jenkins cron 표현식 5개 필드 읽는 법

Jenkins의 cron 표현식은 공백으로 구분된 5개 필드로 이루어진다. 순서는 분(0-59), 시(0-23), 일(1-31), 월(1-12), 요일(0-7)이고, 0과 7이 모두 일요일을 뜻한다. 각 필드에 *를 쓰면 모든 값, 특정 숫자를 쓰면 그 값에만 실행된다. 쉼표(,)는 여러 값 나열, 하이픈(-)은 범위 지정, 슬래시(/)는 간격 반복에 쓴다. '0 2 * * *'는 매일 새벽 2시 정각 실행, '0 9,18 * * 1-5'는 평일 오전 9시와 오후 6시 실행, '0 0 1 * *'는 매월 1일 자정 실행이다. 처음 cron 표현식을 작성할 때 가장 많이 하는 실수가 필드 순서를 헷갈리는 것이다. 시간을 먼저 쓰고 싶어지는 게 직관적으로 느껴지는데, 실제 순서는 분이 앞이다. crontab.guru 같은 사이트에서 표현식을 입력하면 언제 실행되는지 바로 확인할 수 있으니, 처음에는 그 도구를 옆에 띄워두고 작성하는 걸 추천한다. 표현식을 확신하기 어려울 때는 Jenkins 설정 화면 내 미리보기에서도 다음 실행 시각을 실시간으로 확인할 수 있다.

Jenkins cron의 H 표현식과 UTC 시간대 주의사항

Jenkins는 표준 cron에 없는 H(Hash)라는 특수 값을 제공한다. H는 Job 이름을 해시 함수로 변환해서 지정한 범위 안에서 고정된 임의의 분을 선택한다. 'H 2 * * *'라고 쓰면 Jenkins가 02:00~02:59 사이의 특정 분을 자동으로 정한다. Job마다 선택되는 분은 다르지만 같은 Job 안에서는 항상 동일한 분에 실행된다. 이게 왜 필요하냐면, Jenkins 서버에 Job이 여러 개 있을 때 모두 정각(0분)으로 설정하면 그 시각에 빌드가 한꺼번에 몰려 서버에 부하가 집중되기 때문이다. H를 쓰면 각 Job이 자연스럽게 분산되어 실행된다. Jenkins도 설정 화면에서 정각 대신 H 사용을 공식으로 권장하고 있다. 한 가지 더 주의할 점이 UTC 시간대다. Jenkins 서버가 UTC로 돌고 있다면, 한국 시간(UTC+9) 새벽 2시에 빌드를 돌리려면 cron에 UTC 기준인 17시를 입력해야 한다. 처음 이걸 모르고 설정했다가 빌드가 9시간 뒤에 실행되는 걸 보고 당황한 적이 있다. 서버 시간대는 Manage Jenkins → System Information에서 user.timezone 항목으로 확인할 수 있다.

Jenkinsfile 작성과 Pipeline script from SCM 전환

Jenkinsfile에 cron triggers 블록 추가하는 방법

기존에 Jenkins UI에서 직접 입력하던 파이프라인을 Jenkinsfile로 옮기는 방법은 간단하다. 프로젝트 루트 디렉토리에 확장자 없이 'Jenkinsfile'이라는 파일을 만들고, UI에 있던 스크립트를 그대로 붙여넣으면 된다. 여기에 triggers 블록을 추가한다. 위치가 중요한데, pipeline { } 블록 안에서 agent 선언 바로 아래, stages { } 블록 앞에 있어야 한다. triggers { cron('H 17 * * *') } 형태로 선언하면 된다. 처음에 triggers를 stage 블록 안에 넣는 실수를 해서 파이프라인이 실행조차 안 됐던 적이 있다. Groovy 문법 에러가 나거나 트리거가 아예 무시되기 때문에 블록 위치를 반드시 지켜야 한다. 작성이 끝나면 Git에 커밋하고 push한다. 이후 Jenkins Job 설정에서 'Pipeline script from SCM'으로 바꾸고 저장소 URL과 브랜치를 설정해두면 Jenkins가 저장소에서 Jenkinsfile을 직접 읽어온다. 한 번 셋업해두면 이후 파이프라인 수정은 Jenkinsfile을 commit하는 것만으로 끝난다.

pipeline {
  agent any
  tools { nodejs 'NodeJS' }
  triggers { cron('H 17 * * *') }
  stages {
    stage('Checkout') { steps { checkout scm } }
    stage('Install')  { steps { sh 'npm ci' } }
    stage('Build')    { steps { sh 'npm run build' } }
    stage('Deploy')   { steps { sh './deploy.sh' } }
  }
  post {
    success { echo '배포 완료' }
    failure { echo '배포 실패' }
  }
}

Jenkins Job을 Pipeline script from SCM으로 전환하기

Jenkinsfile을 저장소에 push했으면 Jenkins Job 설정을 변경해야 한다. 해당 Job을 열고 좌측의 Configure를 클릭한다. 페이지 아래쪽 Pipeline 섹션에서 Definition 드롭다운을 'Pipeline script'에서 'Pipeline script from SCM'으로 바꾼다. SCM 항목에서 Git을 선택하고 Repository URL을 입력한다. 인증이 필요하면 Credentials에서 미리 등록한 GitHub Personal Access Token이나 SSH 키를 선택하면 된다. Branches to build에는 빌드할 브랜치를 입력하고, Script Path에는 'Jenkinsfile'을 그대로 쓰면 된다. 저장 후 반드시 Build Now로 한 번 수동 실행해야 한다. 이 수동 실행이 없으면 Jenkinsfile의 cron 트리거가 Jenkins에 등록되지 않는다. 처음에 이걸 몰라서 Jenkinsfile을 올리고 저장만 했다가 하루가 지나도 자동 빌드가 안 돌아가서 한참을 찾아봤다. 수동 실행 한 번이 스케줄 등록의 시작점이라는 걸 반드시 기억해두자.

Jenkins cron 트리거 등록 확인 방법

cron 트리거가 정상으로 등록됐는지 확인하는 방법은 간단하다. Job 설정 화면(Configure)의 Build Triggers 섹션을 보면 'Build periodically' 항목이 자동으로 체크되어 있고, 입력한 cron 표현식 옆에 다음 실행 예정 시각이 표시된다. 'H 17 * * *'를 입력한 경우 화면에 'Would next run at ...'처럼 정확한 다음 실행 시각을 미리 보여준다. 이 시각이 의도한 한국 시간과 맞는지 확인하는 게 중요하다. UTC와 KST 차이를 빠뜨리면 생각한 것과 9시간 어긋난 시각에 빌드가 도는 상황이 생긴다. 직접 겪어보면 알겠지만 새벽에 돌아야 할 빌드가 오후에 도는 걸 발견하는 건 꽤 당황스럽다. 설정을 저장한 뒤 다음 날 Build History에서 자동 실행된 빌드 항목이 있는지 확인하면 전체 설정이 제대로 됐다는 걸 최종으로 알 수 있다. 표현식이 틀렸다면 설정 화면에서 수정할 때마다 미리보기가 실시간으로 바뀌니, 저장 전에 꼭 한 번 더 확인하는 습관을 들이는 게 좋다.

자주 묻는 질문

Jenkinsfile에 triggers를 추가했는데 왜 스케줄이 자동으로 등록되지 않나요?+

triggers 블록은 파이프라인이 최소 한 번 실행되어야 Jenkins에 등록됩니다. Jenkinsfile을 저장하고 SCM 설정을 완료한 뒤 'Build Now'로 한 번 수동 실행하면 그 이후부터 cron 스케줄대로 자동 실행됩니다.

Jenkins 서버 시간대가 UTC인지 KST인지 어떻게 확인하나요?+

Jenkins 메인 페이지에서 Manage Jenkins → System Information으로 이동하면 'user.timezone' 항목에서 서버 시간대를 확인할 수 있습니다. 또는 파이프라인에 sh 'date' 명령을 추가하고 빌드 로그를 확인하는 방법도 있습니다.

cron에서 H와 0의 차이는 무엇인가요?+

0은 정각(예: 17:00)에만 실행되어 여러 Job이 동시에 실행될 수 있습니다. H는 Job 이름 기반으로 17:00~17:59 사이의 특정 분을 자동 선택하여 서버 부하를 분산합니다. Jenkins는 H 사용을 공식 권장합니다.

Jenkinsfile은 어느 브랜치에 올려야 하나요?+

Jenkins Job의 'Branches to build' 설정과 일치하는 브랜치에 올려야 합니다. 일반적으로 main 또는 master 브랜치에 올리며, 스테이징 환경을 위한 별도 Job은 develop 브랜치를 바라보도록 구성합니다.

관련 글