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

TypeFileKhi nào
.servicefoo.servicedaemon hoặc oneshot script
.socketfoo.socketsocket activation
.timerfoo.timerlịch chạy (cron-like)
.mount, .swapfilesystem/swap
.pathfoo.pathinotify 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

# 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, OnUnitActiveSec mô 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 policyresource 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èm RemainAfterExit=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.