HỌC BẰNG THỰC HÀNH
← Lộ trình học
01 · Linux Administration

Lập lịch bằng systemd timer và cron

Thực hiện trên server của bạn, rồi kiểm tra từng tiêu chí.

Cốt lõi

Vì sao cần học

Backup, xoay vòng log, gia hạn certificate đều là việc định kỳ. Cron làm được nhưng thiếu nhiều thứ: lỗi không ai biết, output thất lạc, máy tắt đúng giờ chạy thì bỏ lỡ luôn. systemd timer giải quyết các điểm đó và dùng cùng công cụ log, giới hạn quyền như service. RHCSA trên RHEL 10 yêu cầu cả cron và timer.

Mục tiêu

  • Tách việc cần chạy (service oneshot) khỏi lịch chạy (timer).
  • Viết biểu thức OnCalendar và kiểm tra bằng systemd-analyze calendar.
  • Dùng Persistent=true, RandomizedDelaySec và StateDirectory.
  • Theo dõi lần chạy bằng systemctl list-timers và journalctl.

Điều kiện tiên quyết

  • Bài Vận hành web service bằng systemd.

Mental model

cronsystemd timer
LogGửi mail hoặc mấtjournalctl -u <service>
Máy tắt đúng giờ chạyBỏ lỡPersistent=true chạy bù khi boot
Hai lần chạy chồng nhauCó thểKhông: service đang chạy thì timer không khởi động thêm
Chạy thử bằng tayCopy lệnh ra terminal, môi trường khácsystemctl start <service>, cùng môi trường
Giới hạn quyềnKhôngMọi chỉ thị của systemd.exec

Timer kdc-backup.timer mặc định kích hoạt service cùng tên kdc-backup.service. Service kiểu oneshot chạy xong rồi thoát; trạng thái inactive (dead) sau khi chạy xong là bình thường.

StateDirectory=kdc-backup yêu cầu systemd tạo /var/lib/kdc-backup với owner và quyền bạn khai báo, rồi truyền đường dẫn qua biến $STATE_DIRECTORY.

Thực hành (Guided Lab)

1. Dữ liệu cần backup và script

sudo install -d -m 755 /srv/kdc-notes
echo "Ghi chú tạo lúc $(date)" | sudo tee /srv/kdc-notes/today.md

sudo tee /usr/local/bin/kdc-backup.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
dest="${STATE_DIRECTORY:?chạy script này qua kdc-backup.service}"
stamp="$(date +%Y%m%d-%H%M%S)"
tar -czf "$dest/notes-$stamp.tar.gz" -C /srv/kdc-notes .
find "$dest" -name 'notes-*.tar.gz' -mtime +7 -delete
date --iso-8601=seconds > "$dest/last-success"
echo "Backup xong: notes-$stamp.tar.gz"
EOF
sudo chmod 755 /usr/local/bin/kdc-backup.sh
Giải thích lệnh và tham số
Thành phầnÝ nghĩa
${STATE_DIRECTORY:?...}Dừng và báo lỗi nếu biến chưa có giá trị; systemd cấp biến khi service có StateDirectory=.
date +%Y%m%d-%H%M%SIn năm-tháng-ngày và giờ-phút-giây để đặt tên backup. Dấu + mở đầu định dạng, không phải phép cộng.
tar -czf "$dest/...tar.gz"-c tạo archive, -z nén gzip, -f chọn file archive theo sau.
-C /srv/kdc-notes . của tarĐổi thư mục nguồn trước khi lấy nội dung . (thư mục đó), để archive không chứa đường dẫn tuyệt đối dài.
find "$dest" -name 'notes-*.tar.gz'Tìm các tên khớp mẫu trong thư mục backup; nháy đơn giữ * để find xử lý.
-mtime +7 -deleteChọn file có tuổi sửa đổi theo ngày đã làm tròn lớn hơn 7 (ít nhất 8 khoảng 24 giờ), rồi xóa. -delete thực sự xóa file.
date --iso-8601=secondsIn thời điểm dạng ISO với độ chính xác giây và múi giờ.

Chạy find với điều kiện tương tự không có -delete nếu cần xem danh sách trước khi xóa. Lệnh tar này tạo backup, chưa kiểm tra restore.

set -euo pipefail khiến script dừng ngay khi một lệnh lỗi, nên last-success chỉ được ghi khi backup thật sự thành công.

2. Service và timer

sudo tee /etc/systemd/system/kdc-backup.service <<'EOF'
[Unit]
Description=Backup /srv/kdc-notes

[Service]
Type=oneshot
StateDirectory=kdc-backup
StateDirectoryMode=0700
ExecStart=/usr/local/bin/kdc-backup.sh
EOF

sudo tee /etc/systemd/system/kdc-backup.timer <<'EOF'
[Unit]
Description=Backup kdc-notes mỗi 15 phút

[Timer]
OnCalendar=*:0/15
Persistent=true
RandomizedDelaySec=60

[Install]
WantedBy=timers.target
EOF

systemd-analyze calendar '*:0/15'
sudo systemctl daemon-reload
Giải thích lệnh và tham số

systemd-analyze calendar '*:0/15' phân tích biểu thức lịch và in thời điểm chạy tiếp theo. Nháy đơn ngăn shell mở rộng dấu *. Trong cấu hình, OnCalendar chọn lịch, Persistent=true chạy bù một lần khi đã bỏ lỡ lịch, RandomizedDelaySec=60 thêm trễ ngẫu nhiên tối đa 60 giây. Đây là thuộc tính cấu hình, không phải tùy chọn shell.

Timer có [Install], service thì không: ta enable timer, không enable service.

3. Chạy thử, rồi bật lịch

sudo systemctl start kdc-backup.service
journalctl -u kdc-backup.service --no-pager -n 5
sudo ls -l /var/lib/kdc-backup

sudo systemctl enable --now kdc-backup.timer
systemctl list-timers kdc-backup.timer
Giải thích lệnh và tham số

systemctl start kdc-backup.service chạy backup ngay một lần. systemctl enable --now kdc-backup.timer bật timer để lập lịch, không enable service oneshot. list-timers <timer> in lịch với cột NEXT (lần tới), LAST (lần trước). journalctl -n 5 giới hạn ở 5 dòng log.

list-timers cho biết lần chạy kế tiếp (NEXT) và lần gần nhất (LAST).

4. Cron cho việc đơn giản

Cron vẫn có mặt trên hầu hết server và có trong đề RHCSA. Một dòng cron gồm năm trường thời gian (phút, giờ, ngày, tháng, thứ) rồi tới lệnh. File trong /etc/cron.d/ có thêm trường user trước lệnh.

sudo dnf install -y cronie
sudo systemctl enable --now crond
echo '30 2 * * * root find /srv/kdc-notes -name "*.tmp" -mtime +1 -delete' | sudo tee /etc/cron.d/kdc-cleanup
sudo chmod 644 /etc/cron.d/kdc-cleanup
Giải thích lệnh và tham số

Dòng trong /etc/cron.d/kdc-cleanup có 5 trường lịch: 30 phút, 2 giờ, * mọi ngày trong tháng, * mọi tháng, * mọi thứ trong tuần; root là user chạy lệnh. Phần sau mới là lệnh find. -name "*.tmp" chọn file tạm theo tên, -mtime +1 chọn file đã sửa ít nhất 2 khoảng 24 giờ trước, -delete xóa chúng. Với crontab -e, -e mở trình sửa; crontab -l liệt kê lịch của user và không có trường root trong mỗi dòng.

Job chạy lúc 02:30 hằng ngày, xóa file .tmp cũ hơn một ngày. Crontab của từng user sửa bằng crontab -e và xem bằng crontab -l; lịch sử chạy nằm trong journalctl -u crond.

Lịch backup ở trên viết bằng cron sẽ là */15 * * * * root /usr/local/bin/kdc-backup.sh. Hãy nghĩ xem $STATE_DIRECTORY có tồn tại khi cron chạy script không, và lỗi sẽ được ghi vào đâu.

Tự kiểm tra (Verification)

systemctl is-active kdc-backup.timer
systemctl is-enabled kdc-backup.timer
sudo stat -c '%A %U %n' /var/lib/kdc-backup
sudo cat /var/lib/kdc-backup/last-success
cat /etc/cron.d/kdc-cleanup
systemctl is-active crond
Giải thích lệnh và tham số

stat -c '%A %U %n' in quyền dạng chữ, owner và đường dẫn; thư mục backup cần có quyền riêng cho root. Muốn xem danh sách file trong archive, tar -tzf <file.tar.gz> dùng -t để liệt kê (thay cho -c tạo), -z đọc gzip, -f chọn archive. Ví dụ dùng ls -t là sắp xếp file theo thời gian sửa mới nhất trước; head -1 chọn bản mới nhất.

Chọn server và bấm Kiểm tra kết quả.

Lỗi thường gặp

  • Enable service thay vì timer: systemctl enable báo unit không có [Install].
  • Sửa OnCalendar mà quên daemon-reload: list-timers vẫn hiện lịch cũ.
  • Script chạy tay được nhưng lỗi trong service: môi trường khác nhau (PATH, thư mục hiện tại, biến môi trường). Đọc journalctl -u kdc-backup.service.
  • OnCalendar=15m: không hợp lệ. Khoảng thời gian tương đối dùng OnUnitActiveSec=15min.

Ghi chú production

  • Backup chỉ có giá trị khi đã thử restore. Thử liệt kê bản mới nhất: sudo sh -c 'tar -tzf "$(ls -t /var/lib/kdc-backup/notes-*.tar.gz | head -1)"'. Cần sh -c vì user thường không mở được thư mục quyền 700 để mở rộng dấu *.
  • Backup cùng ổ với dữ liệu không bảo vệ được khi hỏng ổ. Module 04 và 19 sẽ đưa backup ra nơi khác.
  • Theo dõi tuổi của last-success để cảnh báo khi backup ngừng chạy; Module 17 sẽ biến nó thành alert.

Ghi chú Ubuntu

Cron có sẵn trong package cron, dịch vụ tên cron.service nên tiêu chí crond.service chỉ đạt trên RHEL-family. Phần systemd timer giống hệt.

Dọn dẹp

sudo systemctl disable --now kdc-backup.timer
sudo rm /etc/systemd/system/kdc-backup.{service,timer} /usr/local/bin/kdc-backup.sh /etc/cron.d/kdc-cleanup
sudo systemctl daemon-reload
sudo rm -rf /var/lib/kdc-backup /srv/kdc-notes
Giải thích lệnh và tham số

kdc-backup.{service,timer} là brace expansion của Bash: shell mở rộng thành hai tên kdc-backup.service và kdc-backup.timer trước khi gọi rm. Không phải cú pháp do rm tự hiểu.

Tài liệu chính thức