3개월 전에 설정해둔 DB 백업 cron이 어느 시점부터 조용히 실패하고 있었습니다. 장애가 나서 복구하려는데 백업 파일이 없습니다. 로그를 보니 cron은 실행을 시도했지만 스크립트가 에러를 냈고, 아무도 몰랐습니다. 자동화는 실행만 되면 끝이 아닙니다 — 실패했을 때 알 수 있어야 하고, 로그가 남아야 하고, 다음에 재시도할 수 있어야 진짜 자동화입니다.
Cron과 systemd timer 자동화
백업 스크립트를 매일 돌리고, 인증서를 자동 갱신하고, 오래된 로그를 정리하는 것 — 전부 사람이 기억해서 하면 언젠가 빠뜨립니다. 자동화의 첫걸음은 작업 스케줄러를 제대로 쓰는 것입니다.
crontab은 간단하고 빠릅니다. systemd timer는 로그와 실패 감지가 필요할 때 씁니다. 둘 다 알아두면 상황에 맞게 선택할 수 있습니다.
- 1crontab 문법을 읽고 자주 쓰는 스케줄 패턴을 작성할 수 있다
- 2cron 환경 문제(PATH·환경변수)를 진단하고 로그로 실행을 확인할 수 있다
- 3systemd timer를 .timer + .service 유닛으로 구성할 수 있다
- 4OnCalendar·OnBootSec·Persistent 옵션으로 스케줄을 제어할 수 있다
- 5백업·인증서 갱신·정리 작업을 상황에 맞는 도구로 자동화할 수 있다
확대
crontab 문법 — 핵심 패턴
분 시 일 월 요일 명령
* * * * * /path/to/command
특수 문자:
* — 모든 값
, — 여러 값 (1,3,5)
- — 범위 (1-5)
/ — 간격 (*/10 = 10마다)
# crontab 편집
crontab -e
# 자주 쓰는 패턴
0 2 * * * # 매일 새벽 2시
0 2 * * 0 # 매주 일요일 새벽 2시
0 2 1 * * # 매월 1일 새벽 2시
*/10 * * * * # 10분마다
0 9-18 * * 1-5 # 월~금, 9~18시 매 정시
0 2 * * * /usr/local/bin/daily-backup.sh >> /var/log/backup.log 2>&1
# 특수 문자열 (단축어)
@reboot # 부팅 시 1회
@daily # = 0 0 * * *
@weekly # = 0 0 * * 0
@monthly # = 0 0 1 * *
@reboot /usr/local/bin/startup-init.sh
# cron 실행 로그 확인
grep CRON /var/log/syslog | tail -20
# 또는
journalctl -u cron --since today
systemd timer — .timer + .service 구성
systemd timer는 두 파일로 구성됩니다:
.service— 실제 실행할 명령.timer— 스케줄 정의
# /etc/systemd/system/daily-backup.service
[Unit]
Description=Daily Backup Job
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/daily-backup.sh
User=root
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/daily-backup.timer
[Unit]
Description=Run daily-backup.service every day at 02:00
[Timer]
OnCalendar=*-*-* 02:00:00 # 매일 02:00
Persistent=true # 실행 누락 시 부팅 후 즉시 실행
AccuracySec=1min # 1분 오차 허용 (기본 1분)
[Install]
WantedBy=timers.target
# 활성화 및 시작
sudo systemctl daemon-reload
sudo systemctl enable --now daily-backup.timer
# 상태 확인
systemctl status daily-backup.timer
systemctl list-timers # 전체 timer 목록과 다음 실행 시각
# 로그 확인
journalctl -u daily-backup.service # 실행 이력
journalctl -u daily-backup.service -n 20 --no-pager
OnCalendar 시간 표현식
확대
# 자주 쓰는 OnCalendar 표현
OnCalendar=daily # 매일 00:00:00
OnCalendar=weekly # 매주 월요일 00:00:00
OnCalendar=monthly # 매월 1일 00:00:00
OnCalendar=hourly # 매 정시
OnCalendar=*-*-* 02:00:00 # 매일 02:00
OnCalendar=Mon *-*-* 03:00:00 # 매주 월요일 03:00
OnCalendar=*-*-01 00:00:00 # 매월 1일 자정
OnCalendar=Sat,Sun 10:00:00 # 주말 10시
# 표현식 검증 (실행 전 확인 필수)
systemd-analyze calendar '*-*-* 02:00:00'
# Original form: *-*-* 02:00:00
# Normalized form: *-*-* 02:00:00
# Next elapse: Wed 2026-04-15 02:00:00 KST
# (in UTC): Tue 2026-04-14 17:00:00 UTC
# From now: 11h left
# 특수 옵션
OnBootSec=5min # 부팅 후 5분 뒤 1회 실행
OnUnitActiveSec=1h # 마지막 실행 후 1시간마다
Persistent=true # 시스템이 꺼져있어 놓친 실행을 부팅 후 즉시 실행
cron 데몬 상태 및 현재 crontab 확인
systemctl is-active cron 2>/dev/null || systemctl is-active crond 2>/dev/null || echo 'cron 데몬 이름 확인 필요' && crontab -l 2>/dev/null || echo '(등록된 crontab 없음)'예상 출력
active (등록된 crontab 없음 또는 기존 작업 목록)
간단한 cron 작업 등록 (매분 실행 테스트)
(crontab -l 2>/dev/null; echo '* * * * * echo "cron test $(date)" >> /tmp/cron-test.log 2>&1') | crontab - && echo 'crontab 등록 완료' && crontab -l예상 출력
crontab 등록 완료 * * * * * echo "cron test $(date)" >> /tmp/cron-test.log 2>&1
1분 대기 후 cron 실행 결과 확인
sleep 65 && cat /tmp/cron-test.log예상 출력
cron test Sun Jun 14 14:01:00 UTC 2026 (cron이 정상 실행되면 1분 간격으로 로그 추가됨)
systemd timer 목록과 다음 실행 시각 확인
systemctl list-timers --all 2>/dev/null | head -10예상 출력
NEXT LEFT LAST PASSED UNIT Sun 2026-06-14 15:00:00 UTC 58min Sun 2026-06-14 14:00:00 UTC 1min ago certbot.timer (등록된 timer 목록과 다음 실행 예정 시각)
OnCalendar 표현식 다음 실행 시각 검증
systemd-analyze calendar '*-*-* 02:00:00' 2>/dev/null | grep -E 'Next|From now'예상 출력
Next elapse: Mon 2026-06-15 02:00:00 KST
From now: 11h left- systemctl list-timers 출력에서 먼저 NEXT(다음 실행 예정 시각)를 보고, 그 다음 LAST(마지막 실행 시각)와 PASSED(경과 시간)를 확인 — LAST가 예상 주기보다 훨씬 오래됐으면 timer가 중지된 것
- cron 실행 빈도 기준: /tmp/cron-test.log에 1분 간격으로 항목이 쌓이면 정상, 항목이 없으면 cron 데몬 중지 또는 스크립트 PATH 오류 — grep CRON /var/log/syslog로 실행 시도 자체 여부 확인
- crontab 등록은 됐는데 스크립트 실행 실패이면 → cron 로그에 CMD는 보이지만 결과물 없음(PATH 차이, 절대경로 사용 필요), systemd timer 실패 시 → journalctl -u 서비스명 -n 20으로 오류 메시지 즉시 확인 가능을 의미
# 수동 실행: OK
$ /usr/local/bin/daily-backup.sh
백업 완료
# cron 실행 후 로그 확인
$ grep CRON /var/log/syslog
Apr 14 02:00:01 server CRON[12345]: (root) CMD (/usr/local/bin/daily-backup.sh)
# 하지만 백업 파일이 없음...
원인 1: PATH 차이
# 스크립트 상단에 PATH 명시
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# 또는 crontab 상단에 추가
$ crontab -e
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 2 * * * /usr/local/bin/daily-backup.sh
원인 2: 환경변수 누락 (AWS CLI, DB 패스워드 등)
# 스크립트에서 직접 환경변수 파일 로드
#!/bin/bash
source /etc/environment
source /home/ubuntu/.env.backup
# 이제 $AWS_ACCESS_KEY_ID 등 사용 가능
원인 3: 출력 리다이렉션 없어서 에러를 못 봄
# 표준출력 + 에러 모두 로그로
0 2 * * * /usr/local/bin/daily-backup.sh >> /var/log/backup.log 2>&1
실무 자동화 패턴
패턴 1: Let's Encrypt 자동 갱신 (certbot timer 확인)
# Ubuntu에서 certbot 설치 시 자동 생성됨
systemctl status certbot.timer
systemctl list-timers | grep certbot
# 없으면 직접 생성
# /etc/systemd/system/certbot-renew.service
[Unit]
Description=Certbot Renewal
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
# /etc/systemd/system/certbot-renew.timer
[Unit]
Description=Certbot Renewal Timer
[Timer]
OnCalendar=*-*-* 03:00:00
OnCalendar=*-*-* 15:00:00 # 하루 2회 (Let's Encrypt 권장)
Persistent=true
RandomizedDelaySec=1h # 서버 몰림 방지
[Install]
WantedBy=timers.target
패턴 2: 오래된 파일 정리 (임시파일, 로그)
# /etc/systemd/system/cleanup-tmp.service
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'find /tmp -mtime +7 -delete && find /var/log/app -name "*.log.*" -mtime +30 -delete'
패턴 3: DB 덤프 자동화
# /etc/systemd/system/mysql-backup.service
[Service]
Type=oneshot
User=backup
EnvironmentFile=/etc/backup.env # MYSQL_PASS 등 환경변수
ExecStart=/usr/local/bin/mysql-backup.sh
# timer: 매일 새벽 1시
OnCalendar=*-*-* 01:00:00
언제 crontab, 언제 systemd timer?
| 상황 | 추천 |
|---|---|
| 간단한 1줄 명령, 빠르게 추가 | crontab |
| 실행 실패 감지가 중요 | systemd timer |
| journalctl로 이력 조회 필요 | systemd timer |
| 부팅 후 누락 실행 보장 필요 | systemd timer (Persistent=true) |
| 기존 systemd 서비스와 연동 | systemd timer |
다음 모듈에서는 KVM 가상화 기초 — 리눅스 서버에서 가상 머신을 생성하고 관리하는 방법을 다룹니다.