예약 작업: cron과 systemd 타이머
예약 작업을 실행하는 방법, 수동으로는 작동하지만 cron에서는 조용한 이유, 그리고 언제 systemd 타이머로 전환해야 하는지 알아봐요.
업데이트 2026년 8월 23일
백업, 인증서 갱신, 임시 파일 정리, 야간 리포트 — 이들은 모두 예약된 작업이에요. Linux에서는 이를 두 가지 방식으로 해결해요: 고전적인 cron과 systemd 타이머예요.
Cron: 빠른 시작
사용자의 스케줄은 이렇게 편집해요:
crontab -e
crontab -l
줄 형식은 다섯 개의 필드와 명령이에요:
# min hour day month day-of-week command
0 4 * * * /usr/local/bin/backup.sh
*/15 * * * * /usr/local/bin/check.sh
30 3 * * 0 /usr/bin/systemctl restart myapp
유용한 단축키: @daily, @hourly, @reboot. 작업이 실제로 실행되었는지 확인하려면:
grep CRON /var/log/syslog | tail -30
journalctl -u cron --since "1 hour ago"
스크립트가 손으로는 되는데 cron에서는 안 되는 이유
이것은 가장 흔한 문제이고, 원인은 거의 항상 세 가지 중 하나예요.
다른 환경. Cron은 최소한의 PATH를 가지고 있고 .bashrc의 변수도 전혀 없어요. 프로그램의 전체 경로를 사용하고, 스크립트 상단이나 crontab에서 변수를 명시적으로 설정하세요:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
다른 디렉터리. 작업은 사용자의 홈 디렉터리에서 시작하므로 상대 경로는 다른 곳을 가리켜요. 항상 절대 경로를 사용하세요.
출력이 아무 데도 가지 않음. 오류가 발생했지만 아무도 보지 못했어요. 로그를 작성하세요:
0 4 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
두 가지 사소한 점이 더 있어요: cron 줄의 % 문자는 \%로 이스케이프해야 하고, crontab 파일은 개행으로 끝나야 해요 — 그렇지 않으면 마지막 작업이 무시돼요.
작업이 실행되었는지 외부에서 확인해야 해요. 조용한 cron은 성공한 것과 똑같아 보여요. Uptime Kuma에서 푸시 검사를 설정하세요: 스크립트가 끝날 때 주소로 핑을 보내고, 하루 동안 핑이 없으면 알림을 받아요.
systemd 타이머
작업이 단일 명령보다 복잡할 때는 타이머가 더 편리해요: journal, 의존성, 리소스 제한, 그리고 두 개의 복사본이 동시에 실행되는 것에 대한 보호 기능이 있어요.
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run nightly backup
[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true
RandomizedDelaySec=15m
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers
journalctl -u backup.service -n 50
Persistent=true는 머신이 꺼져 있었을 때 놓친 실행을 따라잡아요 — cron은 그렇게 할 수 없어요. RandomizedDelaySec는 부하를 분산시켜서 십여 개의 작업이 같은 초에 시작되지 않도록 해요.
염두에 둘 점
- 머신의 시간은 기본적으로 UTC예요. "오전 4시"를 설정하기 전에
timedatectl을 확인하세요. - 무거운 작업(아카이브, 백업 검증)은 디스크에 부하를 줘요. 디스크 속도를 참고하고 밤 시간대로 예약하세요.
- 5분마다 실행되는 긴 작업은 자기 자신과 겹쳐요. systemd에서는
Type=oneshot이 도움이 되고, cron에서는flock을 통한 잠금을 사용하세요:
*/5 * * * * /usr/bin/flock -n /tmp/job.lock /usr/local/bin/job.sh