서버는 여러분이 자는 동안 일할 때 제값을 합니다. 백업, 로그 로테이션, 인증서 갱신, 9시 보고서. Linux에는 이를 위한 스케줄러가 두 가지 있습니다. cron은 40년 된 도구이고 한 줄이면 됩니다. systemd 타이머는 작은 파일 두 개가 필요하지만, 그 대가로 로그, 중단 후 보충, 정확한 시각을 줍니다. 이 가이드는 Ubuntu 24.04에서 둘 다 다루며, 모든 동작을 당사 이미지로 만든 새 서버에서 확인했습니다. cron 작업이 한마디 없이 실패하게 만드는 실수 세 가지도 포함합니다.
sudo 권한이 있는 사용자가 필요합니다. Ubuntu 설정 가이드에서 만들 수 있습니다.
1. 5분 만에 배우는 cron
cron은 당사 Ubuntu와 Debian 이미지에 설치되어 실행 중입니다. 사용자마다 작업 표가 있으며, 자신의 표는 다음으로 편집합니다.
crontab -e
각 줄은 시간 필드 다섯 개와 명령 하나입니다.
# min hour day month weekday command
30 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
*/5 * * * * /usr/local/bin/check.sh
0 9 * * 1-5 /usr/local/bin/report.sh
@reboot /usr/local/bin/start-tunnel.sh
즉, 매일 밤 03:30, 5분마다, 평일 09:00, 그리고 부팅할 때마다 한 번입니다. */5는 다섯 번째 값마다, 1-5는 범위, 1,15는 목록입니다. 서버의 시간대가 적용되며 당사 이미지에서는 UTC입니다. 호스트 이름과 시간대 가이드로 한 번 설정하면 cron이 따릅니다.
무엇이 실행되었는지는 journalctl -u cron으로 확인합니다. 실행마다 사용자와 명령이 기록되며, 세 가지 함정도 거기서 드러납니다.
함정 1: 출력이 사라진다. cron은 작업 출력을 사용자에게 메일로 보냅니다. 당사 이미지에는 메일 서버가 없어서 journal에 (CRON) info (No MTA installed, discarding output)가 남고 출력은 사라졌습니다. 첫 번째 예처럼 >> /var/log/backup.log 2>&1로 직접 리디렉션하세요.
함정 2: 퍼센트 기호. crontab에서 %는 명령을 끝내고 나머지를 표준 입력으로 바꿉니다. date +%F > /tmp/today를 예약했더니 journal에는 cron이 실제로 실행한 CMD (date +)가 남았습니다. 파일은 생기지 않았고 오류도 전달되지 않았습니다. \%로 쓰거나 명령을 스크립트로 만들어 스크립트를 예약하세요.
함정 3: 다른 환경. cron은 작업을 bash가 아니라 /bin/sh로, 홈 디렉터리에서, 최소한의 환경으로 실행합니다. Ubuntu 24.04의 PATH는 평판보다 나았습니다. root든 일반 사용자든 /usr/local/bin과 /snap/bin을 포함한 전체 시스템 경로였습니다. 여전히 빠진 것은 홈 디렉터리 아래의 모든 것으로, ~/.local/bin, nvm의 node, pipx, cargo입니다. 작업에는 전체 경로를 쓰거나 줄을 . $HOME/.profile;로 시작하세요.
사용자가 아니라 시스템에 속한 작업은 사용자 필드를 하나 더한 파일로 /etc/cron.d/에 둡니다.
30 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Ubuntu는 /etc/cron.hourly, cron.daily, cron.weekly, cron.monthly 안의 모든 것도 실행합니다. 매시 17분, 06:25, 일요일 06:47, 매월 1일 06:52입니다. 실행 가능한 스크립트를 넣으면 나머지와 함께 실행됩니다.
2. systemd 타이머
타이머는 두 유닛으로 이루어집니다. 일을 하는 서비스와 언제 할지 정하는 타이머입니다. 먼저 스크립트를 만들고 그다음 유닛을 만듭니다.
sudo nano /usr/local/bin/backup.sh
sudo chmod +x /usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run the backup every night at 03:30
[Timer]
OnCalendar=*-*-* 03:30
Persistent=true
AccuracySec=1m
[Install]
WantedBy=timers.target
활성화할 것은 서비스가 아니라 타이머입니다.
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
list-timers는 다음 실행, 남은 시간, 마지막 실행을 보여 줍니다. 로그는 따로 설정할 필요가 없습니다. journalctl -u backup.service에 시작, 종료, 출력의 모든 줄이 타임스탬프와 함께 남습니다. 작업을 지금 바로 실행하려면 sudo systemctl start backup.service를 쓰세요. 일정을 믿기 전에 스크립트를 테스트할 때도 이렇게 합니다.
캘린더 문법. OnCalendar는 요일 연-월-일 시:분:초로 읽으며 *는 아무 값이나 뜻합니다. 쓰기 전에 표현식을 확인하세요.
systemd-analyze calendar "Mon..Fri *-*-* 03:00" --iterations 2
정규화된 형태와 다음 날짜를 출력합니다. 확인한 표현식 몇 가지입니다.
| OnCalendar | 의미 |
|---|---|
*-*-* 03:30 | 매일 03:30 |
Mon..Fri *-*-* 09:00 | 평일 09:00 |
*:0/15 | 15분마다 |
weekly | 월요일 00:00 |
*-*-01 04:00 | 매월 1일 04:00 |
*-*-* 03:00 Europe/Kyiv | 키이우 시간 03:00, 테스트에서 01:00 UTC에 실행 |
알아 둘 설정 세 가지. Persistent=true는 마지막 실행을 디스크에 기록하고, 서버가 꺼져 있거나 타이머가 멈춰 있던 동안 놓친 실행을 보충합니다. 2분마다 도는 타이머를 멈추고 예정된 실행이 지나기를 기다린 뒤 다시 켰더니, 놓친 실행이 같은 초 안에 시작되었습니다. Persistent가 없으면 다음 일정을 기다릴 뿐입니다.
놀라운 점은 AccuracySec입니다. systemd는 기본적으로 깨우는 횟수를 줄이려고 타이머를 1분 범위로 묶기 때문에, 첫 실행이 07:42:00이 아니라 07:42:18에 왔습니다. AccuracySec=1s로 하자 이후 실행은 07:46:00과 07:48:00에 초 단위로 정확히 맞았습니다. 분이 중요할 때 설정하고, 야간 백업이라면 기본값으로 두세요.
RandomizedDelaySec=10m는 일부러 반대로 합니다. 시작 시각을 일정 범위에 흩어, 서버 열 대가 같은 초에 같은 백업 저장소로 몰리지 않게 합니다.
한 번만 실행할 작업에는 파일이 필요 없습니다.
sudo systemd-run --on-active=30m --unit=cleanup-once /usr/local/bin/cleanup.sh
한 번 실행되고 사라지는 임시 타이머가 만들어지며, 그때까지 systemctl list-timers에 표시됩니다.
3. 무엇을 쓸까
| cron | systemd 타이머 | |
|---|---|---|
| 설정 | 1줄 | 파일 2개 |
| 로그 | 출력을 리디렉션할 때만 | journalctl -u name.service |
| 서버가 꺼져 있던 동안 놓친 실행 | 사라짐 | Persistent=true면 부팅 시 실행 |
| 다음 시각에 작업이 아직 실행 중 | 두 번째 복사본 시작 | 첫 번째가 끝날 때까지 건너뜀 |
| 정확한 시각 | 분 단위 | AccuracySec=1s로 초 단위 |
| 상태 | 없음 | list-timers, systemctl status |
1년 뒤에 봐도 알아볼 간단한 한 줄이라면 cron을 쓰세요. 실패를 알아야 하는 것, 겹치면 안 되는 것, 재부팅으로 놓쳐도 실행해야 하는 것에는 타이머를 쓰세요. 백업, 인증서 갱신, 데이터베이스 정리 같은 것입니다. cron 작업이 겹칠 수 있다면 flock -n /tmp/backup.lock /usr/local/bin/backup.sh로 감싸면 두 번째 복사본이 바로 종료됩니다.
두 스케줄러 모두 작업을 실행하고 끝납니다. 계속 실행되어야 하고 충돌 후 복구되어야 하는 프로그램에는 일정이 아니라 서비스가 필요합니다. systemd 서비스 만드는 법과 Windows라면 Windows Server에서 스크립트를 24시간 실행하는 법을 참고하세요. 첫 타이머로는 restic 백업 가이드의 타이머가 좋습니다. 자동 보안 업데이트는 Ubuntu에 이미 들어 있는 타이머 apt-daily-upgrade.timer로, 새 서버에서 도는 17개 중 하나입니다.
댓글
아직 댓글이 없습니다. 첫 번째가 되세요.