Sổ tay kỹ thuật

Cron và logrotate – lập lịch job và xoay vòng log

how-to#linux#cron#logrotate· cập nhật 2026-11-06

Dùng khi cần đặt job định kỳ bằng crontab, debug job cron không chạy, hoặc cấu hình logrotate cho log ứng dụng và thử bằng logrotate -d.

Sửa trang này
Mục lục

Tóm tắt: Cron chạy job với môi trường tối giản (SHELL=/bin/sh, PATH=/usr/bin:/bin, không đọc .bashrc) nên lỗi phổ biến nhất là "chạy tay được, cron thì không". Logrotate trên Ubuntu 22.04 được gọi mỗi ngày bởi logrotate.timer (systemd), đọc /etc/logrotate.conf + /etc/logrotate.d/*. Luôn thử config mới bằng logrotate -d (không thay đổi gì). Job mới cần log, retry, phụ thuộc service thì cân nhắc systemd timer.

Luồng hoạt động

flowchart LR A["crontab -e (user)"] --> C["cron daemon"] B["/etc/cron.d/* (có cột user)"] --> C C -->|"mỗi phút so lịch"| D["/bin/sh -c 'lệnh'"] D --> E["output: mail hoặc file log"] T["logrotate.timer (daily)"] --> L["logrotate /etc/logrotate.conf"] L --> R["/etc/logrotate.d/myapp"] R --> S["rotate, compress, postrotate"]

Cấu hình

Cú pháp crontab

# phút giờ ngày-tháng tháng thứ(0-7, 0 và 7 = CN)   lệnh
*/5   *   *   *   *     /opt/scripts/check.sh
0     2   *   *   *     /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
30    7   *   *   1-5   /opt/scripts/report.sh
0     0   1   *   *     /opt/scripts/monthly.sh
@reboot                 /opt/scripts/on-boot.sh
Mục đích Lệnh
Sửa crontab của mình crontab -e
Xem crontab crontab -l
Xem crontab user khác sudo crontab -u deploy -l
Job hệ thống (file, có cột user) /etc/cron.d/<tên>
Script chạy theo ngày/tuần/tháng đặt file thực thi vào /etc/cron.daily/ ...
Xem script nào trong cron.daily sẽ chạy run-parts --test /etc/cron.daily
Log cron chạy job grep CRON /var/log/syslog hoặc journalctl -u cron

Job an toàn

/etc/cron.d/netbackup
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
# m h dom mon dow user   command
15 1 * * * netops  flock -n /tmp/netbackup.lock /opt/netbackup/run.sh >> /var/log/netbackup/run.log 2>&1
  • flock -n: lần chạy trước chưa xong thì bỏ qua, tránh chồng job.
  • Redirect >> ... 2>&1: không có thì output gửi mail (thường mất nếu không có MTA).
  • Ký tự % trong lệnh cron là xuống dòng; phải viết \%, ví dụ date +\%F.
  • File trong /etc/cron.d/ và /etc/cron.daily/: tên chỉ dùng chữ, số, -, _ (có dấu . như backup.sh sẽ bị run-parts bỏ qua), file cron.d phải thuộc root và không cho group/other ghi.
  • Biến từ .env thì load trong script, không dựa vào môi trường shell của bạn.

Logrotate cho log ứng dụng

/etc/logrotate.d/myapp
/var/log/myapp/*.log {
    daily
    rotate 14
    maxsize 100M
    missingok
    notifempty
    compress
    delaycompress
    dateext
    su myapp myapp
    create 0640 myapp adm
    sharedscripts
    postrotate
        systemctl kill -s HUP myapp.service >/dev/null 2>&1 || true
    endscript
}
Directive Ý nghĩa
daily / weekly / size 100M Điều kiện xoay (size thay cho lịch; maxsize = theo lịch hoặc vượt cỡ)
rotate 14 Giữ 14 bản cũ
compress + delaycompress Nén gzip, chừa bản gần nhất chưa nén (app có thể còn ghi)
create 0640 user group Tạo file mới sau khi đổi tên file cũ
copytruncate Copy rồi truncate file gốc, cho app không biết mở lại file (có thể mất vài dòng)
su user group Chạy với quyền này, cần khi thư mục log không thuộc root
sharedscripts postrotate chạy một lần cho cả pattern, không phải mỗi file
postrotate ... endscript Báo app mở lại file (HUP, nginx -s reopen...)

Thử và chạy

sudo logrotate -d /etc/logrotate.d/myapp       # dry-run: in ra sẽ làm gì, không đổi file
sudo logrotate -v -f /etc/logrotate.d/myapp    # ép xoay ngay, in chi tiết
cat /var/lib/logrotate/status | grep myapp     # lần xoay cuối
systemctl list-timers logrotate.timer          # lần chạy kế tiếp

-d cũng không cập nhật state, nên kết quả kiểu log does not need rotating là do state hoặc điều kiện lịch, không phải lỗi cú pháp.

Lỗi thường gặp

Triệu chứng Nguyên nhân Cách xử lý
Chạy tay được, cron thì command not found PATH của cron chỉ có /usr/bin:/bin Dùng đường dẫn tuyệt đối hoặc đặt PATH= đầu crontab
Job không chạy, syslog không có dòng CRON Sai cú pháp (thiếu cột user trong /etc/cron.d) hoặc file thiếu newline cuối Kiểm tra cột, thêm dòng trống cuối file
Lệnh có date +%F bị cắt % là ký tự đặc biệt trong crontab Escape \%
Script trong /etc/cron.daily/ không chạy Tên có dấu . hoặc không có quyền thực thi Đổi tên bỏ đuôi .sh, chmod +x; kiểm bằng run-parts --test
Job chạy chồng nhau, load tăng Lần trước chưa xong flock -n
Giờ chạy lệch Cron theo timezone hệ thống timedatectl; đổi TZ rồi systemctl restart cron
logrotate: skipping ... because parent directory has insecure permissions Thư mục log group/world-writable Thêm su <user> <group> hoặc sửa quyền thư mục
Đã xoay nhưng app vẫn ghi vào file .1 App giữ file descriptor cũ postrotate gửi HUP/reopen, hoặc copytruncate
Log không bao giờ được xoay Lỗi ở file khác làm logrotate dừng, hoặc state sai journalctl -u logrotate, logrotate -d /etc/logrotate.conf

Tham khảo