Một máy chủ đáng tiền vì nó làm việc trong lúc bạn ngủ: sao lưu, xoay vòng log, gia hạn chứng chỉ, báo cáo lúc chín giờ. Linux có hai bộ lập lịch cho việc đó. Cron đã bốn mươi tuổi và chỉ cần một dòng. Timer của systemd cần hai file nhỏ, đổi lại có log, chạy bù sau khi máy tắt và thời gian chính xác. Hướng dẫn này nói về cả hai trên Ubuntu 24.04, mọi hành vi đều được kiểm tra trên một máy chủ mới từ image của chúng tôi, kể cả ba lỗi khiến tác vụ cron hỏng mà không báo một lời.
Bạn cần một người dùng có sudo; hướng dẫn thiết lập Ubuntu sẽ tạo một người dùng như vậy.
1. Cron trong năm phút
Cron đã được cài và đang chạy trên image Ubuntu và Debian của chúng tôi. Mỗi người dùng có một bảng tác vụ; chỉnh bảng của bạn bằng:
crontab -e
Mỗi dòng gồm năm trường thời gian và một lệnh:
# 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
Tức là: 03:30 mỗi đêm, mỗi 5 phút, 09:00 các ngày trong tuần và một lần sau mỗi lần khởi động. */5 nghĩa là cứ năm giá trị một lần, 1-5 là một khoảng, 1,15 là một danh sách. Múi giờ của máy chủ được áp dụng, là UTC trên image của chúng tôi; đặt múi giờ của bạn một lần theo hướng dẫn hostname và múi giờ và cron sẽ theo.
Xem những gì đã chạy bằng journalctl -u cron. Mỗi lần chạy ghi lại người dùng và lệnh, và đó là nơi ba cái bẫy lộ ra.
Bẫy 1: đầu ra biến mất. Cron gửi đầu ra của tác vụ qua email cho người dùng. Image của chúng tôi không có máy chủ thư, nên journal ghi (CRON) info (No MTA installed, discarding output) và đầu ra mất luôn. Hãy tự chuyển hướng nó, như ví dụ đầu tiên với >> /var/log/backup.log 2>&1.
Bẫy 2: dấu phần trăm. Trong crontab, % kết thúc lệnh và biến phần còn lại thành đầu vào chuẩn. Chúng tôi đã lên lịch date +%F > /tmp/today. Journal cho thấy cron thực sự chạy gì: CMD (date +). Không file nào được ghi và không lỗi nào đến tay chúng tôi. Hãy viết \%, hoặc đặt lệnh vào một script rồi lên lịch cho script.
Bẫy 3: môi trường khác. Cron chạy tác vụ bằng /bin/sh chứ không phải bash, trong thư mục home của bạn và với môi trường tối giản. Trên Ubuntu 24.04, PATH tốt hơn tiếng xấu của nó: đường dẫn hệ thống đầy đủ gồm cả /usr/local/bin và /snap/bin, cho cả root lẫn người dùng thường. Thứ vẫn thiếu là mọi thứ trong thư mục home: ~/.local/bin, node của nvm, pipx, cargo. Dùng đường dẫn đầy đủ trong tác vụ hoặc bắt đầu dòng bằng . $HOME/.profile;.
Tác vụ thuộc về hệ thống chứ không phải người dùng thì đặt trong /etc/cron.d/ dưới dạng file với thêm một trường là người dùng:
30 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Ubuntu cũng chạy mọi thứ trong /etc/cron.hourly, cron.daily, cron.weekly và cron.monthly, vào phút 17 mỗi giờ, lúc 06:25, 06:47 vào Chủ nhật và 06:52 ngày mùng 1. Đặt một script có quyền thực thi vào đó và nó sẽ chạy cùng các script khác.
2. Timer của systemd
Một timer gồm hai unit: một service làm việc và một timer nói khi nào. Tạo script trước, rồi tạo các unit.
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
Bật timer, không phải service:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
list-timers hiển thị lần chạy kế tiếp, còn bao lâu và lần chạy gần nhất. Log không cần thiết lập: journalctl -u backup.service có mọi lần bắt đầu, kết thúc và từng dòng đầu ra kèm thời gian. Để chạy tác vụ ngay, dùng sudo systemctl start backup.service; đó cũng là cách thử script trước khi tin vào lịch.
Cú pháp lịch. OnCalendar đọc là thứ năm-tháng-ngày giờ:phút:giây, với * cho mọi giá trị. Thử một biểu thức trước khi dùng:
systemd-analyze calendar "Mon..Fri *-*-* 03:00" --iterations 2
Lệnh in ra dạng chuẩn hóa và các ngày kế tiếp. Một số biểu thức chúng tôi đã kiểm tra:
| OnCalendar | Ý nghĩa |
|---|---|
*-*-* 03:30 | Mỗi ngày lúc 03:30 |
Mon..Fri *-*-* 09:00 | Các ngày trong tuần lúc 09:00 |
*:0/15 | Mỗi 15 phút |
weekly | Thứ Hai lúc 00:00 |
*-*-01 04:00 | Ngày 1 mỗi tháng lúc 04:00 |
*-*-* 03:00 Europe/Kyiv | 03:00 giờ Kyiv; chạy lúc 01:00 UTC trong thử nghiệm của chúng tôi |
Ba thiết lập nên biết. Persistent=true lưu lần chạy gần nhất lên đĩa và chạy bù lần bị lỡ khi máy chủ tắt hoặc timer bị dừng. Chúng tôi dừng timer hai phút một lần, chờ qua một lần chạy theo lịch rồi bật lại: lần bị lỡ chạy ngay trong cùng giây đó. Không có Persistent, nó chỉ chờ đến lượt kế tiếp.
AccuracySec là điều bất ngờ. Mặc định systemd gom timer trong cửa sổ một phút để giảm số lần đánh thức, nên lần chạy đầu của chúng tôi đến lúc 07:42:18 chứ không phải 07:42:00. Với AccuracySec=1s, các lần sau rơi đúng giây vào 07:46:00 và 07:48:00. Hãy đặt khi phút là quan trọng; để mặc định cho bản sao lưu ban đêm.
RandomizedDelaySec=10m cố ý làm ngược lại: rải thời điểm bắt đầu trong một cửa sổ để mười máy chủ không cùng đập vào một kho sao lưu trong cùng một giây.
Với tác vụ chạy một lần, không cần file nào:
sudo systemd-run --on-active=30m --unit=cleanup-once /usr/local/bin/cleanup.sh
Lệnh này tạo một timer tạm thời chạy một lần rồi biến mất; trước lúc đó systemctl list-timers sẽ hiển thị nó.
3. Nên dùng cái nào
| Cron | Timer systemd | |
|---|---|---|
| Thiết lập | 1 dòng | 2 file |
| Log | Chỉ khi bạn chuyển hướng đầu ra | journalctl -u name.service |
| Lần chạy bị lỡ khi máy chủ tắt | Mất | Chạy khi khởi động với Persistent=true |
| Tác vụ vẫn đang chạy ở nhịp kế tiếp | Một bản sao thứ hai khởi động | Bỏ qua đến khi bản đầu xong |
| Thời gian chính xác | Đến phút | Đến giây với AccuracySec=1s |
| Trạng thái | Không có | list-timers, systemctl status |
Dùng cron cho một dòng nhanh mà một năm sau bạn vẫn nhận ra. Dùng timer cho mọi thứ mà bạn cần thấy khi nó hỏng, không được chồng lấn, hoặc vẫn phải chạy sau một lần khởi động lại bị lỡ: sao lưu, gia hạn chứng chỉ, dọn dẹp cơ sở dữ liệu. Nếu tác vụ cron có thể chồng lấn, hãy bọc nó: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, và bản sao thứ hai sẽ thoát ngay.
Cả hai bộ lập lịch đều chạy một tác vụ rồi dừng. Với chương trình phải chạy suốt ngày đêm và tự lên lại sau sự cố, bạn cần một service chứ không phải lịch; xem cách tạo service systemd và với Windows là cách chạy script 24/7 trên Windows Server. Một timer đầu tiên tốt là timer trong hướng dẫn sao lưu bằng restic của chúng tôi; cập nhật bảo mật tự động là timer Ubuntu đã có sẵn, apt-daily-upgrade.timer, một trong 17 timer chạy trên máy chủ mới.
Bình luận
Chưa có bình luận nào. Hãy là người đầu tiên.