← 전체 글로 돌아가기

Next.js

systemd timer로 바꿨더니 cron보다 로그 추적이 쉬웠다

매일 도는 작은 작업을 cron에서 systemd timer로 옮기며 느낀 장단점을 기록했다.

바꾸게 된 배경

간단한 정리 스크립트를 cron에 넣어 두었는데, 어느 날 실행이 안 된 것처럼 보였다. 문제는 실제로 안 돈 건지, 돌았는데 출력만 못 본 건지 구분이 잘 안 됐다는 점이다. /var/log/syslog를 뒤져도 내가 남긴 로그와 시스템 로그가 섞여 있었다.

그래서 매일 도는 작업 하나를 systemd timer로 옮겨 봤다. 대단한 서비스는 아니고, 결과를 journal에서 바로 보고 싶어서였다.

service 파일

먼저 실제로 실행할 작업을 service로 만들었다.

[Unit]
Description=Run small cleanup job

[Service]
Type=oneshot
WorkingDirectory=/home/deploy/app
ExecStart=/usr/bin/bash /home/deploy/app/scripts/cleanup.sh
User=deploy

여기서 내가 한 번 놓친 부분은 WorkingDirectory였다. 스크립트 안에서 상대 경로를 쓰고 있었는데, cron에서 돌릴 때도 애매했고 systemd에서도 명확히 적지 않으면 기대한 위치가 아니었다.

timer 파일

다음은 실행 시간을 정하는 timer다.

[Unit]
Description=Run cleanup job every morning

[Timer]
OnCalendar=*-*-* 09:00:00
Persistent=true
Unit=cleanup.service

[Install]
WantedBy=timers.target

Persistent=true는 서버가 꺼져 있던 시간에 실행 시각을 놓쳤을 때 부팅 후 한 번 실행하게 해 준다. 매일 꼭 한 번은 돌았으면 하는 작업이라 이 옵션을 켰다.

확인 명령이 마음에 들었다

등록 후에는 아래 순서로 확인했다.

sudo systemctl daemon-reload
sudo systemctl enable --now cleanup.timer
systemctl list-timers --all | grep cleanup
journalctl -u cleanup.service -n 50 --no-pager

cron에서는 “이 줄이 맞나?”를 계속 봤다면, systemd timer에서는 다음 실행 시각과 마지막 실행 결과를 명령으로 바로 볼 수 있었다. 실패했을 때도 exit code가 service 단위로 남아서 원인 찾기가 쉬웠다.

cron을 버릴 필요는 없었다

아주 단순한 한 줄 작업은 cron이 여전히 편하다. 반대로 실행 사용자, 작업 디렉터리, 실패 로그, 다음 실행 시각을 계속 확인해야 하는 작업은 timer가 더 잘 맞았다. 나는 배포 서버에서 중요한 정기 작업만 timer로 옮기고, 실험용 작업은 cron에 남겨 두는 식으로 기준을 나눴다.

정리

이번에 얻은 가장 큰 이득은 화려한 기능이 아니라 관찰 가능성이었다. 작업이 돌았는지 애매하면 운영할 때 계속 불안하다. 작은 자동화라도 나중에 확인할 명령이 있는 방식으로 두는 게 마음 편했다.