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.