infra
Platform

모듈 맵

[Linux] Cron과 systemd timer 자동화

0 / 20 완료

펼치기

리눅스 서버 운영 · 17 / 20

[Linux] Cron과 systemd timer 자동화

crontab과 systemd timer로 반복 작업을 자동화하고, 실행 로그를 확인하여 자동화 누락을 방지합니다

🚨INCIDENT ALERT
HIGH

3개월 전에 설정해둔 DB 백업 cron이 어느 시점부터 조용히 실패하고 있었습니다. 장애가 나서 복구하려는데 백업 파일이 없습니다. 로그를 보니 cron은 실행을 시도했지만 스크립트가 에러를 냈고, 아무도 몰랐습니다. 자동화는 실행만 되면 끝이 아닙니다 — 실패했을 때 알 수 있어야 하고, 로그가 남아야 하고, 다음에 재시도할 수 있어야 진짜 자동화입니다.

Cron과 systemd timer 자동화

백업 스크립트를 매일 돌리고, 인증서를 자동 갱신하고, 오래된 로그를 정리하는 것 — 전부 사람이 기억해서 하면 언젠가 빠뜨립니다. 자동화의 첫걸음은 작업 스케줄러를 제대로 쓰는 것입니다.


이번 챕터에서 배울 것

crontab은 간단하고 빠릅니다. systemd timer는 로그와 실패 감지가 필요할 때 씁니다. 둘 다 알아두면 상황에 맞게 선택할 수 있습니다.

  • 1crontab 문법을 읽고 자주 쓰는 스케줄 패턴을 작성할 수 있다
  • 2cron 환경 문제(PATH·환경변수)를 진단하고 로그로 실행을 확인할 수 있다
  • 3systemd timer를 .timer + .service 유닛으로 구성할 수 있다
  • 4OnCalendar·OnBootSec·Persistent 옵션으로 스케줄을 제어할 수 있다
  • 5백업·인증서 갱신·정리 작업을 상황에 맞는 도구로 자동화할 수 있다

cron과 systemd timer를 비교해 언제 무엇을 쓰는지 정리한 다이어그램확대

실습 환경 준비

💡개념

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는 두 파일로 구성됩니다:

  1. .service — 실제 실행할 명령
  2. .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 표현식이 실행 시각으로 풀리는 과정과 Persistent 동작 타임라인확대

로컬 터미널
# 자주 쓰는 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                  # 시스템이 꺼져있어 놓친 실행을 부팅 후 즉시 실행
실습 단계
1

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 없음 또는 기존 작업 목록)
2

간단한 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
3

1분 대기 후 cron 실행 결과 확인

sleep 65 && cat /tmp/cron-test.log

예상 출력

cron test Sun Jun 14 14:01:00 UTC 2026
(cron이 정상 실행되면 1분 간격으로 로그 추가됨)
4

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 목록과 다음 실행 예정 시각)
5

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 가상화 기초 — 리눅스 서버에서 가상 머신을 생성하고 관리하는 방법을 다룹니다.

지식 확인

퀴즈 — 4문제

Q1

회사 ERP 시스템 보고서를 평일 업무 시간 시작 전인 새벽 2시에만 생성해야 합니다. crontab에 등록할 스케줄 표현식으로 올바른 것은?

Q2

3개월 전 crontab으로 등록한 DB 백업 스크립트가 조용히 실패하고 있었습니다. 이런 상황을 방지하기 위해 systemd timer로 전환하려 합니다. crontab 대비 systemd timer의 핵심 이점은?

Q3

배포 자동화 스크립트가 수동으로 실행하면 정상 동작하는데 cron에서 실행하면 'command not found' 오류가 납니다. 가장 가능성이 높은 원인은?

Q4

systemd timer에 OnCalendar=weekly를 설정했습니다. 팀원이 '이 타이머는 매주 일요일에 실행되겠네'라고 말합니다. 올바른 정보는?

0 / 4 답변

이것도 배워보세요