Sau bài này bạn làm được: đọc trạng thái dịch vụ qua systemctl; tìm log đúng chỗ với journalctl (unit, time range, priority); viết drop-in override thay vì sửa file package; dùng timer thay cron khi cần dependency và logging thống nhất; tránh footgun daemon-reload khi quên.
systemd không chỉ là “init = PID 1”
systemd là:
- Supervisor cho daemon (restart policy, limit tài nguyên — móc tới bài 6).
- Dependency graph (
After=,Requires=,Wants=). - Logging tích hợp (journald).
- Socket activation (ít dùng trực tiếp trên app server thường, nhưng quan trọng với một số distro service).
Nếu bạn yêu Unix “tối giản”, systemd có thể gây cảm xúc — nhưng trên máy chủ hiện đại, khả năng đồng nhất cách quan sát và khởi động là lợi thế vận hành lớn.
systemctl: bộ lệnh tối thiểu
# Trạng thái + vài dòng log gần nhất
systemctl status nginx.service --no-pager
# Liệt kê unit failed
systemctl --failed --no-pager
# Bật/tắt khởi động cùng máy
systemctl is-enabled ssh.service
sudo systemctl enable --now nginx.service
# Reload cấu hình (không restart process nếu unit hỗ trợ reload)
sudo systemctl reload nginx.service
enable --now: tiện — vừa tạo symlink wanted-by vừa start ngay.
Unit types bạn gặp hằng ngày
| Type | File | Khi nào |
|---|---|---|
.service | foo.service | daemon hoặc oneshot script |
.socket | foo.socket | socket activation |
.timer | foo.timer | lịch chạy (cron-like) |
.mount, .swap | … | filesystem/swap |
.path | foo.path | inotify path trigger |
systemctl list-unit-files --type=service --state=enabled | head
Drop-in override: đừng sửa /lib/systemd/system/foo.service
Package manager có thể ghi đè file unit khi upgrade. Best practice:
sudo systemctl edit nginx.service
# Mở editor, tạo file trong /etc/systemd/system/nginx.service.d/override.conf
Ví dụ override phổ biến:
[Service]
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
LimitNOFILE=65535
Sau khi sửa:
sudo systemctl daemon-reload
sudo systemctl restart nginx.service
Footgun: quên daemon-reload sau khi sửa unit file trên disk — systemd vẫn giữ representation cũ trong memory cho đến khi reload.
journalctl: đọc log như một kỹ sư, không như tail -f mù
# Theo unit, từ boot hiện tại
journalctl -u nginx.service -b --no-pager
# Khoảng thời gian ISO
journalctl -u ssh.service --since "2026-04-10 09:00:00" --until "2026-04-10 10:00:00"
# Mức độ ưu tiên (0=emerg … 7=debug)
journalctl -p err..alert
# Output JSON cho pipeline (jq)
journalctl -u myapp.service -o json --no-pager | head
# Disk journal đang dùng bao nhiêu
journalctl --disk-usage
Gợi ý incident: bắt đầu từ -b (boot hiện tại) để loại nhiễu từ reboot trước; sau đó mở rộng time range.
Timer vs cron: khi nào chọn timer?
Timer hữu ích khi:
- Bạn muốn log vào journal cùng namespace với service khác.
- Bạn cần
OnBootSec,OnUnitActiveSecmô tả dependency rõ hơn một dòng cron kiểu phút-giờ-ngày (ví dụ chạy mỗi giờ vào phút thứ 5). - Bạn muốn
Persistent=trueđể “bù” lần chạy nếu máy tắt qua mốc.
Cron vẫn ổn cho job đơn giản toàn cục — nhưng timer + service tách biệt giúp restart policy và resource limit áp vào job dễ hơn.
systemctl list-timers --all
Type= trong service: oneshot vs simple vs notify
simple(default): systemd coi service “đã start” ngay khi fork — phù hợp nhiều daemon fork-background sai cách (legacy).notify: daemon báo READY qua sd_notify — chính xác hơn cho dependency ordering.oneshot: chạy xong là exit; dùng cho migration script; thường kèmRemainAfterExit=yes.
Sai Type= có thể làm dependent unit start quá sớm — bug “race on boot” khó bắt.
systemd-analyze — blame boot chậm
systemd-analyze
systemd-analyze blame | head
systemd-analyze critical-chain
Liên hệ bài trước / sau
Câu hỏi hay gặp
1. “systemctl restart làm mất connection đang tới không?”
Có — với stateful service cần drain (LB health) hoặc reload nếu hỗ trợ.
2. “Tôi thấy (code=exited, status=203/EXEC)?”
Shebang sai, binary không tồn tại, hoặc không executable — kiểm tra ExecStart= path.
3. “Journal mất sau reboot?”Storage=volatile hoặc /var/log/journal chưa tạo — xem journald.conf (bài 11 nối thêm retention).
Bài tiếp theo trong loạt
→ Phần 6: Process, ulimit và cgroup — vì sao container “512Mi limit” lại liên quan cgroup trên Linux.