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.