Cron 표현식 완벽 가이드 — 스케줄 자동화의 기본
Cron 표현식 문법, 예제, 자주 쓰는 패턴을 정리했다. 리눅스 crontab부터 GitHub Actions까지.
서버에서 매일 새벽 3시에 DB 백업을 돌리거나, 매시간 캐시를 갱신하거나, 매주 월요일에 리포트를 보내야 할 때. 이런 반복 작업을 예약하는 데 cron이 쓰인다. 리눅스 시스템 관리의 기본이면서, GitHub Actions, Kubernetes CronJob, AWS EventBridge 등에서도 동일한 표현식을 사용한다.
Cron 표현식 구조
기본 형태는 5개 필드다:
┌───────────── 분 (0-59)
│ ┌───────────── 시 (0-23)
│ │ ┌───────────── 일 (1-31)
│ │ │ ┌───────────── 월 (1-12)
│ │ │ │ ┌───────────── 요일 (0-6, 0=일요일)
│ │ │ │ │
* * * * *
각 필드에 올 수 있는 값:
| 기호 | 의미 | 예시 |
|---|---|---|
* | 모든 값 | * * * * * = 매분 |
| 숫자 | 특정 값 | 30 9 * * * = 매일 9시 30분 |
, | 여러 값 | 0,30 * * * * = 매시 0분과 30분 |
- | 범위 | 1-5 = 1~5 |
/ | 간격 | */10 * * * * = 10분마다 |
자주 쓰는 패턴
시간 기반
* * * * * 매분
*/5 * * * * 5분마다
0 * * * * 매시 정각
0 */2 * * * 2시간마다
30 9 * * * 매일 오전 9시 30분
0 0 * * * 매일 자정
0 9,18 * * * 매일 오전 9시, 오후 6시
요일 기반
0 9 * * 1 매주 월요일 오전 9시
0 9 * * 1-5 평일 오전 9시
0 0 * * 0 매주 일요일 자정
0 18 * * 5 매주 금요일 오후 6시
날짜 기반
0 0 1 * * 매월 1일 자정
0 0 1,15 * * 매월 1일, 15일 자정
0 9 1 1 * 매년 1월 1일 오전 9시
0 0 * * 1#1 매월 첫 번째 월요일 (일부 시스템)
crontab 사용법
리눅스에서 cron 작업을 관리하려면 crontab 명령어를 쓴다.
# 현재 사용자의 cron 작업 목록 보기
crontab -l
# cron 작업 편집
crontab -e
# 특정 사용자의 cron 작업 보기 (root 권한 필요)
sudo crontab -u www-data -l
crontab -e로 열리는 파일에 한 줄에 하나씩 작성한다:
# 매일 새벽 3시에 DB 백업
0 3 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
# 10분마다 헬스체크
*/10 * * * * curl -s https://mysite.com/health > /dev/null
>> /var/log/backup.log 2>&1 부분은 출력과 에러를 로그 파일에 기록하라는 뜻이다. 이걸 안 하면 cron이 보내는 메일로 출력이 갈 수 있다.
주의할 점
시간대(timezone). 시스템 시간대를 확인해야 한다. UTC로 설정된 서버에서 0 9 * * *은 한국 시간 오후 6시가 된다.
timedatectl # 현재 시스템 시간대 확인
환경변수. cron은 사용자의 쉘 환경을 그대로 로드하지 않는다. PATH, HOME 등이 다를 수 있어서, 스크립트에서 절대 경로를 쓰는 게 안전하다.
# crontab 파일 상단에 환경변수 지정 가능
PATH=/usr/local/bin:/usr/bin:/bin
겹침 방지. 작업이 실행 시간보다 오래 걸리면 다음 실행과 겹칠 수 있다. flock으로 잠금을 거는 게 일반적인 해결책이다:
*/5 * * * * flock -n /tmp/myjob.lock /home/user/scripts/slow-job.sh
GitHub Actions에서 cron
GitHub Actions의 schedule 트리거도 cron 표현식을 쓴다.
on:
schedule:
- cron: '0 9 * * 1' # 매주 월요일 9시 (UTC)
주의: GitHub Actions의 시간대는 항상 UTC이고, 정확한 시각에 실행된다는 보장이 없다. 부하가 많을 때는 몇 분~수십 분 딜레이가 발생할 수 있다.
Kubernetes CronJob
쿠버네티스에서도 동일한 표현식을 사용한다:
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
spec:
schedule: "0 3 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: my-backup-image
restartPolicy: OnFailure
concurrencyPolicy 설정으로 이전 작업이 아직 실행 중일 때의 동작을 제어할 수 있다: Allow(동시 실행 허용), Forbid(새 작업 건너뜀), Replace(이전 작업 종료 후 새로 시작).
AWS EventBridge (CloudWatch Events)
AWS는 cron 표현식에 6개 필드를 쓴다 (연도 추가):
cron(분 시 일 월 요일 연도)
cron(0 9 ? * MON-FRI *) # 평일 9시 UTC
?는 "지정 안 함"이라는 뜻으로, 일과 요일 중 하나에 반드시 써야 한다. 표준 cron과 살짝 문법이 다르니 AWS 문서를 꼭 참고해야 한다.
디버깅
cron 작업이 안 돌 때 확인할 것들:
# cron 서비스가 돌고 있는지
systemctl status cron
# cron 실행 로그
grep CRON /var/log/syslog
# 스크립트 권한 확인 (실행 권한 있어야 함)
chmod +x /home/user/scripts/backup.sh
권한 문제가 제일 많다. 스크립트를 직접 실행하면 되는데 cron에서만 안 되는 경우, 대부분 PATH나 파일 권한 문제다.
표현식이 내가 원하는 대로 동작하는지 미리 확인하고 싶으면 Cron 표현식 생성기를 써보자. 각 필드를 GUI로 설정하면 다음 실행 시간을 미리 보여준다. */15 3-6 * * 1-5 같은 복잡한 표현식도 한눈에 확인할 수 있다.