본문으로 건너뛰기
ZEKILO Dev
변환

GitHub Actions·Kubernetes cron UTC 함정

2026.10.03 업데이트 · 6분 읽기

GitHub Actions의 cron은 기본이 UTC이고 Kubernetes CronJob은 컨트롤러의 시간대를 따릅니다. 한국 시간으로 맞추는 방법과 5필드 문법, 일·요일을 함께 쓸 때의 OR 규칙을 정리했습니다.

Cron 표현식 해석 바로 사용하기

Cron 표현식에는 시간대가 없고, 실행하는 플랫폼이 시간대를 정합니다. GitHub Actions의 schedule은 기본이 UTC이고, 시간대를 지정하지 않은 Kubernetes CronJob은 kube-controller-manager의 현지 시간대를 따릅니다. 그래서 0 9 * * 1-5는 GitHub에서 한국 시간 오전 9시가 아니라 오후 6시에 실행됩니다. 시간을 UTC로 바꿔 쓰거나 플랫폼의 시간대 필드를 지정하세요. 표현식을 Cron 표현식 해석에 붙여 넣으면 뜻과 다음 실행 시간을 UTC와 한국 시간으로 확인할 수 있습니다.

5필드 문법

두 플랫폼 모두 전통적인 5필드 형식을 씁니다.

┌──────── 분       0-59
│ ┌────── 시       0-23
│ │ ┌──── 일       1-31
│ │ │ ┌── 월       1-12
│ │ │ │ ┌ 요일     0-6 (0 = 일요일)
* * * * *
연산자 뜻 예
* 모든 값 * * * * * 매분
, 목록 0 9,18 * * * 9시와 18시
- 범위 0 9 * * 1-5 월요일부터 금요일 9시
/ 간격 */15 * * * * 15분마다

POSIX가 정의하는 것은 별표, 숫자, 범위, 목록뿐입니다. / 간격은 Vixie cron의 확장이고, GitHub Actions와 Kubernetes 문서 모두 지원한다고 적고 있습니다. 초가 앞에 붙는 6필드나 Quartz 7필드는 다른 스케줄러의 형식입니다.

Asia/Seoul 시간대로 계산한 기준 결과입니다.

표현식 기준 시각 다음 실행
0 9 * * 1-5 2026-10-02(금) 10:00 10-05(월) 09:00, 이어서 10-06·10-07·10-08·10-09 09:00
*/15 * * * * 2026-10-02 10:07 10:15, 10:30, 10:45, 11:00, 11:15
0 0 31 2 * 언제든 실행되지 않음(2월 31일 없음)
0 25 * * * 언제든 오류: 시 필드는 0부터 23까지

두 플랫폼의 차이

2026년 10월 기준 공식 문서의 내용입니다.

항목 GitHub Actions schedule Kubernetes CronJob
기본 시간대 UTC kube-controller-manager의 현지 시간대
시간대 지정 timezone 키(IANA 이름) .spec.timeZone(IANA 이름, v1.27부터 안정 기능)
@daily 같은 매크로 지원하지 않음 @yearly @monthly @weekly @daily @hourly
/ 간격 지원 지원
이름 표기 JAN-DEC, SUN-SAT 요일 sun부터 sat
물음표 ? 문서에 없음 *와 같은 뜻
가장 짧은 간격 5분마다 명시 없음(문서 예제는 매분 실행)

Kubernetes는 .spec.schedule 안에 CRON_TZ=나 TZ=를 쓰는 방식을 지원하지 않으며 검증 오류가 납니다. 시간대 필드를 쓰세요.

숫자로 보는 UTC 함정

한국 시간(KST)은 UTC+9이고 서머타임이 없습니다. 2026년 10월 2일 금요일 오전 10시에 평일 9시 실행을 기대하고 0 9 * * 1-5를 GitHub 워크플로에 넣었다고 합시다. UTC로 계산하면 첫 실행은 같은 금요일 09:00 UTC, 한국 시간 18:00이고 이후에도 계속 18:00에 실행됩니다.

한국 시간에 맞추려면 9시간을 뺍니다.

목표(KST) UTC 표현식 설명
월요일부터 금요일 09:00 0 0 * * 1-5 00:00 UTC는 같은 날 09:00
월요일부터 금요일 08:00 0 23 * * 0-4 23:00 UTC는 전날이므로 요일도 하루 당겨야 함
월요일부터 금요일 08:00 0 23 * * 1-5 잘못: 화요일부터 토요일 08:00에 실행됨

많이 놓치는 것이 둘째·셋째 줄입니다. 변환한 시각이 자정을 넘어가면 요일과 일 필드도 함께 옮겨야 합니다. 아예 바꿀 수 없는 일정도 있습니다. 「매월 1일 00:00 KST」는 전달 마지막 날 15:00 UTC인데, 5필드 cron에는 「마지막 날」을 쓰는 방법이 없습니다.

시간대를 직접 지정하면 이런 계산이 필요 없습니다. 문서의 문법대로 쓰면 다음과 같습니다.

# GitHub Actions
on:
  schedule:
    - cron: "0 9 * * 1-5"
      timezone: "Asia/Seoul"
# Kubernetes CronJob
spec:
  schedule: "0 9 * * 1-5"
  timeZone: "Asia/Seoul"

Kubernetes에서는 지금 잘 동작하더라도 지정해 두는 편이 좋습니다. 관리형 클러스터에서는 kube-controller-manager의 시간대를 알기 어렵기 때문입니다. 서머타임이 있는 지역은 UTC로 쓴 일정이 현지 기준으로 1년에 두 번 한 시간씩 움직입니다. GitHub 문서는 timezone을 지정한 일정이 서머타임 시작으로 건너뛰는 시간대에 걸리면 다음 유효한 시각으로 옮겨진다고 설명합니다(예: 오전 2:30 일정은 3:00).

일과 요일을 함께 쓰면 OR

POSIX는 일(또는 월)과 요일을 둘 다 지정하면 어느 한쪽이라도 맞는 날을 일치로 본다고 정합니다. AND가 아니라 OR입니다.

그래서 0 0 13 * 5는 「13일의 금요일」이 아닙니다. Asia/Seoul 기준 2026-10-02(금) 10:00부터 계산하면 10-09(금), 10-13(화), 10-16(금) 00:00에 실행됩니다. 매주 금요일과 매월 13일 모두입니다.

GitHub 문서는 POSIX cron 문법을 쓴다고 밝히고 있습니다. Kubernetes 문서가 형식 설명으로 연결하는 Go 라이브러리 robfig/cron도 두 필드가 모두 별표가 아니면 어느 한쪽만 맞아도 실행하도록 구현되어 있습니다. 「13일이면서 금요일」이 필요하면 한 조건만 일정으로 걸고 나머지는 작업 안에서 날짜를 확인하세요. Cron 표현식 해석 도구는 두 필드를 함께 쓰면 이 규칙을 안내합니다.

그 밖에 알아 둘 동작

GitHub Actions

  • 부하가 높을 때 예약 실행이 늦어질 수 있고, 문서는 매시 정각을 부하가 높은 때로 꼽습니다. 부하가 매우 높으면 대기 중인 작업이 빠질 수도 있습니다. 17 0 * * *처럼 0분이 아닌 분을 고르세요.
  • 예약 워크플로는 기본 브랜치의 최신 커밋에서 실행되며, 워크플로 파일이 기본 브랜치에 있어야 합니다.
  • 공개 저장소는 60일 동안 저장소 활동이 없으면 예약 워크플로가 자동으로 비활성화됩니다.

Kubernetes

  • CronJob은 일정마다 Job을 「대략 한 번」 만듭니다. 문서는 상황에 따라 Job이 두 개 만들어지거나 만들어지지 않을 수 있으므로 Job을 멱등하게 만들라고 안내합니다.
  • concurrencyPolicy는 이전 Job이 아직 실행 중일 때의 동작을 정합니다: Allow(기본), Forbid, Replace.
  • startingDeadlineSeconds는 놓친 Job을 얼마나 늦게까지 시작할지 정합니다. 놓친 일정이 100개를 넘으면 컨트롤러는 Job을 시작하지 않고 오류를 기록합니다.

ZEKILO Dev로 확인하기

  1. Cron 표현식 해석에 표현식을 붙여 넣습니다. 형식은 필드 수로 자동 판별합니다.
  2. 시간대를 UTC로 두면 GitHub Actions의 기본 동작을, Asia/Seoul로 두면 의도한 한국 시간을 볼 수 있습니다.
  3. 풀이 문장과 다음 실행 5회를 기대한 일정과 비교합니다.

표현식은 브라우저 안에서 해석하며 서버로 보내지 않습니다.

정리

  • Cron에는 시간대가 없습니다. GitHub Actions는 UTC, Kubernetes는 컨트롤러의 현지 시간대가 기본입니다.
  • UTC로 바꿀 때는 자정을 넘으면 요일·일 필드도 옮기고, 가능하면 timezone(GitHub)이나 .spec.timeZone(Kubernetes)을 지정하세요.
  • 일과 요일을 둘 다 지정하면 어느 한쪽만 맞아도 실행됩니다.
  • GitHub Actions에서는 0분을 피하고, Kubernetes Job은 멱등하게 만드세요.

이 글과 관련된 도구

출처와 기준

다른 가이드