Cron vs systemd Timer เลือกใช้อะไรบน Ubuntu Server 26.04

Cron vs systemd Timer เลือกใช้อะไรบน Ubuntu Server 26.04

งานประจำของผู้ดูแลระบบมักเต็มไปด้วยคำสั่งที่ต้องทำซ้ำ เช่น สำรองข้อมูลทุกคืน ลบ Log เก่า ตรวจสอบพื้นที่ Disk หรือเรียก Script เพื่อส่งรายงานสถานะ Server

เครื่องมือที่ผู้ใช้ Linux คุ้นเคยที่สุดคือ Cron เพราะตั้งค่าง่ายและใช้กันมานาน แต่บน Linux รุ่นใหม่ที่ใช้ systemd เรามีอีกทางเลือกคือ systemd Timer ซึ่งทำงานร่วมกับ Service, Journal, Dependency และระบบ Security ของ systemd ได้โดยตรง

คำถามสำคัญจึงไม่ใช่เพียงว่า “ตัวไหนดีกว่า” แต่คือ งานประเภทใดควรใช้ Cron และงานประเภทใดควรใช้ systemd Timer

บทความนี้จะเปรียบเทียบทั้งสองระบบ พร้อมทดลองตั้งเวลา Backup ไดเรกทอรี /etc บน Ubuntu Server 26.04 LTS ด้วยวิธีที่นำไปใช้งานจริงได้ทันที


สภาพแวดล้อมที่ใช้ในบทความ

บทความนี้อ้างอิงจากระบบต่อไปนี้

  • OS: Ubuntu Server 26.04 LTS

  • systemd: 259.5

  • cron: 3.0pl1-200ubuntu1

  • Shell: Bash

  • สิทธิ์ผู้ใช้งาน: ผู้ใช้ทั่วไปที่สามารถใช้ sudo

Ubuntu 26.04 LTS มีแพ็กเกจ systemd รุ่น 259.5 และแพ็กเกจ cron รุ่น 3.0pl1-200ubuntu1 อยู่ใน Repository อย่างเป็นทางการ ณ วันที่จัดทำบทความ

ตรวจสอบเวอร์ชันของระบบด้วยคำสั่ง

# ตรวจสอบเวอร์ชัน Ubuntu
lsb_release -a

# ตรวจสอบเวอร์ชัน systemd
systemctl --version

# ตรวจสอบแพ็กเกจ cron
apt policy cron


Cron คืออะไร

Cron คือระบบตั้งเวลาสำหรับเรียก Command หรือ Script ตามวันและเวลาที่กำหนด โดย Cron daemon จะอ่านตารางเวลาที่เรียกว่า crontab

ผู้ใช้แต่ละคนสามารถมี crontab ของตัวเองได้ และคำสั่งใน crontab จะทำงานด้วยสิทธิ์ของผู้ใช้เจ้าของ crontab นั้น

รูปแบบพื้นฐานของ Cron มี 5 ช่องเวลา ตามด้วยคำสั่ง

นาที ชั่วโมง วันที่ เดือน วันในสัปดาห์ คำสั่ง

ตัวอย่าง

30 2 * * * /usr/local/sbin/backup-etc.sh

หมายถึงเรียก Script ทุกวันเวลา 02:30 น.

ตารางค่าที่ใช้งานได้มีดังนี้

ตำแหน่ง ความหมาย ค่าที่กำหนดได้
1 นาที 0–59
2 ชั่วโมง 0–23
3 วันที่ของเดือน 1–31
4 เดือน 1–12
5 วันในสัปดาห์ 0–7 โดย 0 และ 7 คือวันอาทิตย์

Cron รองรับเครื่องหมาย * สำหรับทุกค่า เครื่องหมาย , สำหรับระบุหลายค่า เครื่องหมาย - สำหรับช่วง และ / สำหรับกำหนด Step เช่น */5 หมายถึงทุก 5 หน่วย

ข้อควรระวังคือ หากกำหนดทั้งวันที่ของเดือนและวันในสัปดาห์ Cron จะเรียกงานเมื่อ ช่องใดช่องหนึ่งตรงเงื่อนไข ไม่ได้รอให้ทั้งสองช่องตรงพร้อมกัน


systemd Timer คืออะไร

systemd Timer คือ Unit ประเภทหนึ่งของ systemd ใช้สำหรับกำหนดเวลาที่จะเรียก Service อีก Unit หนึ่ง

โดยทั่วไปจะประกอบด้วยไฟล์สองไฟล์

ชื่อบริการ.service
ชื่อบริการ.timer

ไฟล์ .service กำหนดว่าให้ทำงานอะไร ส่วนไฟล์ .timer กำหนดว่าให้ทำงานเมื่อใด

systemd Timer รองรับทั้งเวลาตามปฏิทินผ่าน OnCalendar= และเวลาที่อ้างอิงจากเหตุการณ์ เช่น หลัง Boot หรือหลัง Service ทำงานครั้งล่าสุด

ตัวอย่างรูปแบบเวลา

OnCalendar=*-*-* 02:30:00

หมายถึงทำงานทุกวันเวลา 02:30 น.

systemd รองรับ Calendar Expression ที่ยืดหยุ่นกว่า Cron เช่น

# ทุกวันจันทร์ถึงศุกร์ เวลา 08:30
OnCalendar=Mon..Fri *-*-* 08:30:00

# วันที่ 1 ของทุกเดือน เวลาเที่ยงคืน
OnCalendar=*-*-01 00:00:00

# ทุก ๆ ชั่วโมง
OnCalendar=hourly

# ทุกวัน
OnCalendar=daily

สามารถใช้คำสั่ง systemd-analyze calendar เพื่อตรวจสอบ Expression และดูเวลาที่จะทำงานครั้งต่อไปได้


เปรียบเทียบ Cron กับ systemd Timer

คุณสมบัติ Cron systemd Timer
ความง่ายในการตั้งค่า ง่ายมาก ใช้เพียงบรรทัดเดียว ต้องสร้าง .service และ .timer
ความคุ้นเคย ใช้งานแพร่หลายมานาน เหมาะกับ Linux ที่ใช้ systemd
การดู Log ต้อง Redirect หรือดู Log ของ cron ดูผ่าน journalctl ได้โดยตรง
งานที่พลาดตอนปิดเครื่อง ปกติจะไม่ย้อนกลับมาทำ ใช้ Persistent=true ได้
Dependency ต้องเขียนตรวจสอบเอง ใช้ After=, Wants= และ Requires=
จำกัดสิทธิ์และ Resource ต้องใช้เครื่องมือเพิ่มเติม รองรับ Security และ Resource Control
ป้องกันงานซ้อน ต้องใช้ flock หรือเขียน Lock เอง systemd ติดตามสถานะ Service ให้
ทดสอบตารางเวลา ต้องวิเคราะห์ Cron Expression ใช้ systemd-analyze calendar
Portability ใช้ได้กับ Unix/Linux หลายระบบ ใช้ได้บนระบบที่ใช้ systemd
เหมาะกับ งานง่ายและ Script ขนาดเล็ก งานระดับระบบและ Production

เตรียม Script สำหรับทดสอบ

เราจะสร้าง Script สำหรับสำรองข้อมูล /etc ไปยัง /var/backups/syswriter และลบ Backup ที่เก่ากว่า 7 วัน

⚠️ ข้อควรระวัง: ตัวอย่างนี้อ่านข้อมูลจาก /etc และเขียนไฟล์ลง /var/backups จึงต้องใช้สิทธิ์ระดับ Administrator ควรตรวจสอบพื้นที่ Disk ก่อนนำไปใช้กับ Server จริง

สร้างไดเรกทอรีสำหรับเก็บ Backup

# สร้างไดเรกทอรีและอนุญาตให้ root เข้าถึงเท่านั้น
sudo install -d -m 0700 /var/backups/syswriter

สร้าง Script

sudo nano /usr/local/sbin/backup-etc.sh

เพิ่มเนื้อหาต่อไปนี้

#!/usr/bin/env bash

# หยุดทันทีเมื่อเกิดข้อผิดพลาด ตัวแปรไม่มีค่า หรือ Pipeline ล้มเหลว
set -Eeuo pipefail

# ไฟล์ Backup ที่สร้างใหม่จะไม่เปิดสิทธิ์ให้ผู้ใช้อื่นอ่าน
umask 077

BACKUP_DIR="/var/backups/syswriter"
TIMESTAMP="$(/usr/bin/date +'%Y%m%d-%H%M%S')"
ARCHIVE="${BACKUP_DIR}/etc-${TIMESTAMP}.tar.gz"

# ตรวจสอบและสร้างไดเรกทอรี Backup
/usr/bin/install -d -m 0700 "${BACKUP_DIR}"

# สำรองข้อมูลไดเรกทอรี /etc
/usr/bin/tar \
    --one-file-system \
    --create \
    --gzip \
    --file="${ARCHIVE}" \
    /etc

# ลบไฟล์ Backup ที่เก่ากว่า 7 วัน
/usr/bin/find "${BACKUP_DIR}" \
    -type f \
    -name 'etc-*.tar.gz' \
    -mtime +7 \
    -delete

echo "Backup completed: ${ARCHIVE}"

กำหนด Permission

# เจ้าของไฟล์อ่าน เขียน และรันได้ ส่วนผู้ใช้อื่นไม่มีสิทธิ์
sudo chmod 0700 /usr/local/sbin/backup-etc.sh
sudo chown root:root /usr/local/sbin/backup-etc.sh

ทดลองเรียก Script ด้วยตนเอง

sudo /usr/local/sbin/backup-etc.sh

ตรวจสอบไฟล์ที่สร้างขึ้น

sudo ls -lh /var/backups/syswriter/

ตรวจสอบว่าไฟล์ Archive เปิดอ่านได้

# แสดง 20 รายการแรกภายในไฟล์ Backup
sudo tar -tzf /var/backups/syswriter/etc-*.tar.gz | head -n 20

ภาพหน้าจอที่แนะนำ: ไฟล์ Backup ภายใน /var/backups/syswriter


วิธีที่ 1 ตั้งเวลาด้วย Cron

ติดตั้งและตรวจสอบ Cron

ตรวจสอบสถานะ Cron

sudo systemctl status cron --no-pager

หากยังไม่มีแพ็กเกจ Cron ให้ติดตั้งด้วยคำสั่ง

sudo apt update
sudo apt install -y cron

เปิดใช้งาน Service

sudo systemctl enable --now cron

เพิ่ม Cron Job

เนื่องจาก Script ต้องอ่านไฟล์ระบบใน /etc เราจะเพิ่มงานลงใน crontab ของ root ผ่าน sudo โดยไม่ Login เป็น root โดยตรง

sudo crontab -e

เพิ่มบรรทัดต่อไปนี้

# สำรองข้อมูลทุกวันเวลา 02:30 น.
# ใช้ flock ป้องกันไม่ให้มีงานมากกว่าหนึ่งชุดทำงานพร้อมกัน
30 2 * * * /usr/bin/flock -n /run/syswriter-backup.lock /usr/local/sbin/backup-etc.sh >> /var/log/syswriter-backup.log 2>&1

ส่วนประกอบของคำสั่งมีดังนี้

  • 30 2 * * * เรียกงานทุกวันเวลา 02:30 น.

  • /usr/bin/flock -n ป้องกันการทำงานซ้อนกัน

  • /run/syswriter-backup.lock เป็น Lock file

  • >> เพิ่มผลลัพธ์ต่อท้ายไฟล์ Log

  • 2>&1 ส่ง Error ไปเก็บรวมกับ Standard Output

ตรวจสอบรายการ Cron Job

sudo crontab -l

ตรวจสอบ Log ของ Script

sudo tail -n 50 /var/log/syswriter-backup.log

ตรวจสอบ Log ของ Cron daemon

sudo journalctl -u cron --since today

ภาพหน้าจอที่แนะนำ: ผลลัพธ์ sudo crontab -l และ journalctl -u cron


ข้อผิดพลาดที่พบบ่อยเมื่อใช้ Cron

Cron หา Command ไม่พบ

Cron มี Environment และค่า PATH ที่จำกัดกว่าตอนใช้งานผ่าน Terminal จึงควรใช้ Absolute path เช่น

/usr/bin/tar
/usr/bin/date
/usr/bin/find

แทนการเขียนเพียง

tar
date
find

Script ทำงานเองได้ แต่ Cron ไม่ทำงาน

ตรวจสอบ Permission ของ Script

sudo ls -l /usr/local/sbin/backup-etc.sh

ตรวจสอบ Shebang บรรทัดแรก

#!/usr/bin/env bash

และตรวจสอบว่าไฟล์ใช้ Line Ending แบบ Linux ไม่ใช่ Windows CRLF

file /usr/local/sbin/backup-etc.sh

งานทำงานซ้อนกัน

Cron ไม่ทราบโดยตรงว่างานครั้งก่อนยังทำงานอยู่หรือไม่ จึงควรใช้ flock กับงาน Backup, Sync หรือ Import ข้อมูลที่อาจใช้เวลานาน


วิธีที่ 2 ตั้งเวลาด้วย systemd Timer

systemd Timer จะแยกส่วนการทำงานออกจากส่วนกำหนดเวลาอย่างชัดเจน

สร้าง Service Unit

สร้างไฟล์ Service

sudo nano /etc/systemd/system/syswriter-backup.service

เพิ่มเนื้อหาต่อไปนี้

[Unit]
Description=Backup the /etc directory
Documentation=man:systemd.service(5)

[Service]
# เหมาะสำหรับงานที่ทำครั้งเดียวแล้วจบ
Type=oneshot

# ต้องใช้ root เพื่ออ่านไฟล์ระบบบางส่วนใน /etc
User=root
Group=root

# เรียก Script โดยใช้ Absolute path
ExecStart=/usr/local/sbin/backup-etc.sh

# จำกัดเวลาทำงานสูงสุด ป้องกัน Process ค้าง
RuntimeMaxSec=30min

# ไฟล์ที่สร้างใหม่ให้เฉพาะ root อ่านได้
UMask=0077

# ลดสิทธิ์และจำกัดพื้นที่ที่ Service เขียนข้อมูลได้
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/backups/syswriter

Type=oneshot เหมาะสำหรับงานที่เรียก Command ทำงานให้เสร็จแล้วหยุด เช่น Backup, Cleanup หรือ Generate Report โดย systemd จะรอจน Process จบก่อนพิจารณาว่า Service ทำงานสำเร็จหรือไม่

สร้าง Timer Unit

สร้างไฟล์ Timer

sudo nano /etc/systemd/system/syswriter-backup.timer

เพิ่มเนื้อหาต่อไปนี้

[Unit]
Description=Run /etc backup every day

[Timer]
# เรียกทุกวันเวลา 02:30 น.
OnCalendar=*-*-* 02:30:00

# หากเครื่องปิดอยู่ในเวลาที่กำหนด ให้ทำงานหลังเปิดเครื่อง
Persistent=true

# สุ่มหน่วงเวลาไม่เกิน 10 นาที ลดการทำงานพร้อมกันหลายเครื่อง
RandomizedDelaySec=10min

# อนุญาตให้ systemd รวมเวลาการทำงานภายในช่วง 1 นาที
AccuracySec=1min

# ระบุ Service ที่ Timer ต้องเรียก
Unit=syswriter-backup.service

[Install]
WantedBy=timers.target

Persistent=true ช่วยให้ Timer ตรวจสอบว่ามีรอบการทำงานที่พลาดไประหว่างเครื่องปิดหรือ Timer ไม่ได้ทำงานหรือไม่ หากพบว่าพลาดอย่างน้อยหนึ่งรอบ Service จะถูกเรียกหลัง Timer กลับมาทำงานอีกครั้ง

RandomizedDelaySec= เหมาะกับกรณีที่มี Server หลายเครื่อง เพราะช่วยลดปัญหาทุกเครื่องเริ่ม Backup หรือเชื่อมต่อ Storage พร้อมกัน

ตรวจสอบ Calendar Expression

ก่อนเปิดใช้งานควรตรวจสอบว่า Expression ถูกต้อง

systemd-analyze calendar '*-*-* 02:30:00'

ดูเวลาทำงาน 5 รอบถัดไป

systemd-analyze calendar \
    --iterations=5 \
    '*-*-* 02:30:00'

ตรวจสอบความถูกต้องของ Unit

sudo systemd-analyze verify \
    /etc/systemd/system/syswriter-backup.service \
    /etc/systemd/system/syswriter-backup.timer

หากไม่มีข้อความ Error แสดงว่า Syntax ถูกต้อง

เปิดใช้งาน Timer

แจ้งให้ systemd โหลด Unit ใหม่

sudo systemctl daemon-reload

เปิดใช้งาน Timer และให้เริ่มทำงานทันที

sudo systemctl enable --now syswriter-backup.timer

ตรวจสอบสถานะ

sudo systemctl status syswriter-backup.timer --no-pager

ดู Timer ทั้งหมด

systemctl list-timers --all

ผลลัพธ์จะแสดงข้อมูลสำคัญ เช่น

  • NEXT เวลาที่จะทำงานครั้งถัดไป

  • LEFT เวลาที่เหลือ

  • LAST เวลาที่ทำงานครั้งล่าสุด

  • UNIT ชื่อ Timer

  • ACTIVATES ชื่อ Service ที่จะถูกเรียก

ภาพหน้าจอที่แนะนำ: ผลลัพธ์ systemctl list-timers --all


ทดสอบ systemd Service โดยไม่ต้องรอเวลา

เราสามารถสั่งเรียก Service โดยตรงเพื่อทดสอบได้

sudo systemctl start syswriter-backup.service

ตรวจสอบสถานะล่าสุด

sudo systemctl status syswriter-backup.service --no-pager

ดู Log ของ Service

sudo journalctl \
    -u syswriter-backup.service \
    --since today \
    --no-pager

ติดตาม Log แบบ Real-time

sudo journalctl -fu syswriter-backup.service

ตรวจสอบไฟล์ Backup

sudo ls -lh /var/backups/syswriter/

ข้อดีของวิธีนี้คือไม่ต้องเขียน Redirect ไปยังไฟล์ Log เอง เพราะ Standard Output และ Standard Error จะถูกเก็บใน systemd Journal โดยอัตโนมัติ


การหยุดและลบ Timer

หยุดและปิดการเริ่มอัตโนมัติ

sudo systemctl disable --now syswriter-backup.timer

ลบไฟล์ Unit

sudo rm \
    /etc/systemd/system/syswriter-backup.service \
    /etc/systemd/system/syswriter-backup.timer

โหลด Configuration ใหม่

sudo systemctl daemon-reload
sudo systemctl reset-failed

⚠️ อย่าเปิดใช้งานทั้ง Cron Job และ systemd Timer สำหรับ Script เดียวกันพร้อมกัน เพราะจะทำให้ Backup ถูกเรียกซ้ำสองครั้งในช่วงเวลาเดียวกัน แม้จะมี flock ช่วยป้องกันบางกรณีก็ตาม


ควรเลือก Cron เมื่อใด

Cron เหมาะกับงานต่อไปนี้

  • งานมีเพียง Command หรือ Script สั้น ๆ

  • ไม่ต้องกำหนด Dependency กับ Service อื่น

  • ต้องการ Configuration ที่อ่านและแก้ไขได้รวดเร็ว

  • ต้องนำ Script ไปใช้กับ Unix หรือ Linux หลายตระกูล

  • เป็นงานระดับผู้ใช้ทั่วไป

  • ไม่ต้องการ Security Isolation หรือ Resource Control ขั้นสูง

ตัวอย่างงานที่เหมาะกับ Cron

# ลบไฟล์ชั่วคราวของผู้ใช้ทุกคืน
0 1 * * * /usr/bin/find /home/user/tmp -type f -mtime +7 -delete

ควรเลือก systemd Timer เมื่อใด

systemd Timer เหมาะกับงานต่อไปนี้

  • งานระดับระบบหรือ Production

  • ต้องการดู Log ด้วย journalctl

  • ต้องทำงานหลัง Network, Database หรือ Storage พร้อม

  • ต้องการทำงานชดเชยเมื่อ Server ถูกปิดในเวลาที่กำหนด

  • ต้องการจำกัด Runtime, CPU, Memory หรือสิทธิ์เข้าถึงระบบ

  • ต้องการตรวจสอบสถานะด้วย Monitoring

  • ต้องดู Exit status และจัดการ Failure อย่างเป็นระบบ

  • ต้องการกระจายเวลาทำงานของ Server หลายเครื่อง

ตัวอย่างเช่น งาน Backup ไปยัง NAS อาจเพิ่ม Dependency ได้ดังนี้

[Unit]
Description=Backup data to remote storage

# รอให้ระบบ Network พร้อมก่อนเริ่มงาน
Wants=network-online.target
After=network-online.target

อย่างไรก็ตาม network-online.target หมายถึงระบบ Network ผ่านขั้นตอนเตรียมพร้อมตามที่ Network manager รายงาน ไม่ได้ยืนยันว่า Internet หรือ Remote Server ปลายทางจะตอบสนองเสมอ ดังนั้น Script ควรตรวจสอบการเชื่อมต่อและจัดการ Error เพิ่มเติมด้วย


แนวทางเลือกใช้สำหรับ SysAdmin

หากเป็นงานง่ายและต้องการตั้งค่าให้เสร็จภายในไม่กี่นาที Cron ยังคงเป็นเครื่องมือที่เหมาะสมและไม่มีความจำเป็นต้องเปลี่ยนทุกงานไปเป็น systemd Timer

แต่หากงานนั้นสำคัญต่อระบบ เช่น Backup, Database Maintenance, Certificate Renewal, Log Processing หรือการส่งข้อมูลไปยังระบบภายนอก การใช้ systemd Timer จะช่วยให้ตรวจสอบสถานะ ดู Log กำหนด Dependency และควบคุม Security ได้ชัดเจนกว่า

แนวทางที่แนะนำคือ

งานส่วนตัวหรืองานขนาดเล็ก       → Cron
งานระบบที่ต้องดูแลระยะยาว       → systemd Timer
งานที่ต้องรองรับหลาย Unix        → Cron
งานที่ต้องการ Log และ Dependency → systemd Timer

สรุป

Cron และ systemd Timer มีเป้าหมายเดียวกัน คือเรียก Command หรือ Script ตามเวลาที่กำหนด แต่มีแนวทางการออกแบบต่างกัน

Cron เด่นเรื่องความเรียบง่าย ใช้เพียงหนึ่งบรรทัดและเหมาะกับงานทั่วไป ส่วน systemd Timer ต้องสร้างไฟล์มากกว่า แต่ให้ความสามารถด้าน Logging, Dependency, Failure Tracking, Security และการทำงานชดเชยหลังเครื่องเปิดกลับมา

สำหรับ Ubuntu Server 26.04 งานง่ายสามารถใช้ Cron ต่อไปได้โดยไม่มีปัญหา แต่สำหรับงาน Production ที่ต้องตรวจสอบและดูแลระยะยาว systemd Timer มักเป็นตัวเลือกที่เหมาะสมกว่า



Write by Dr.Arnut Ruttanatirakul
(c) SysAdmin Knowledge
https://www.sysadmin.in.th
August  6, 2026