พื้นฐาน

systemd คืออะไร ทำงานอย่างไร และจัดการบริการใน Linux อย่างไร

อัปเดต: · Skillaria.Top

systemd คือระบบ init และตัวจัดการบริการของ Linux โดย kernel เรียกใช้เป็นโปรเซสแรก (PID 1) จากนั้นเปิดบริการอื่นตามลำดับที่ถูกต้องและคอยติดตาม ทุกอย่างที่ systemd ทำถูกควบคุมผ่าน unit ซึ่งเป็นคำอธิบายแบบข้อความของบริการ ไทเมอร์ จุดเมานต์ โดย systemctl ใช้สั่งเริ่ม หยุด และตั้งให้เปิดอัตโนมัติ ส่วน journalctl แสดง log

systemd คือระบบ init และตัวจัดการบริการที่ใช้ในดิสโทรสมัยใหม่ส่วนใหญ่ของ Linux เช่น Debian, Ubuntu, Fedora, RHEL และตระกูลที่สืบทอดมา หลังจากบูต kernel เรียก systemd เป็นโปรเซสแรกที่มี PID 1 จากนั้น systemd เปิดเครือข่าย เมานต์ดิสก์ เริ่มเว็บเซิร์ฟเวอร์ ฐานข้อมูล และทุกอย่างที่เหลือ กล่าวสั้นๆ systemd คือ "ตัวจัดการ" ที่รู้ว่าบริการใดควรทำงาน ควรเริ่มตามลำดับใด และควรทำอย่างไรเมื่อบริการล้มเหลว

ตรวจสอบว่าระบบของคุณใช้ systemd หรือไม่ทำได้ง่ายๆ:

$ ps -p 1 -o comm=
systemd

ทำไมจึงต้องมี systemd

ก่อนหน้านี้ Linux ใช้ SysV init ซึ่งเป็นชุดของ shell script ใน /etc/init.d/ ที่ถูกรันทีละตัว วิธีนี้เข้าใจง่ายแต่ช้าและเปราะบาง สคริปต์แต่ละตัวต้องเขียนไฟล์ PID เอง ต้องตัดสินใจเองว่าโปรเซสยังทำงานอยู่หรือไม่ และการรีสตาร์ตบริการที่ล้มเหลวต้องเขียนเพิ่มแยกต่างหาก

systemd แก้ปัญหาเหล่านี้แบบรวมศูนย์:

  • การเริ่มแบบขนาน บริการที่ไม่ขึ้นต่อกันจะเริ่มพร้อมกัน ทำให้บูตเร็วขึ้น
  • การพึ่งพาและลำดับ คำอธิบายบริการระบุชัดเจนว่าต้องการอะไร (เช่น เครือข่าย) และต้องเริ่มหลังอะไร
  • การดูแล systemd รู้จักทุกโปรเซสของบริการผ่าน cgroups และรีสตาร์ตได้เมื่อล้มเหลว
  • log รวมศูนย์ journald เก็บเอาต์พุตของทุกบริการ และดู log ได้ด้วยคำสั่งเดียว
  • อินเทอร์เฟซเดียว บริการทุกตัวจัดการแบบเดียวกัน: systemctl start|stop|restart|status

นอกจากตัวจัดการบริการ โครงการ systemd ยังมีส่วนประกอบอื่นด้วย ได้แก่ journald (log) logind (เซสชันผู้ใช้) timesyncd (ซิงก์เวลา) resolved (DNS) และ networkd (เครือข่าย) ไม่ใช่ดิสโทรทุกตัวจะใช้ครบทุกส่วน แต่ systemd ในฐานะ PID 1 และ journald แทบจะมีอยู่ทุกที่

Unit: systemd ประกอบด้วยอะไรบ้าง

ทุกสิ่งที่ systemd จัดการถูกอธิบายด้วย unit unit คือไฟล์ข้อความรูปแบบ INI ชนิดของ unit กำหนดจากนามสกุลไฟล์

ชนิดนามสกุลอธิบายอะไร
service.serviceบริการ — โปรเซส daemon หรือ งานครั้งเดียว
timer.timerรัน unit อื่นตามกำหนดเวลา (แทน cron)
socket.socketsocket ที่เมื่อมีการเชื่อมต่อจะเปิดบริการขึ้นมา
target.targetกลุ่มของ unit หรือ "สถานะของระบบ" (เช่น multi-user.target)
mount.mountจุดเมานต์
path.pathเฝ้าดูไฟล์หรือไดเรกทอรี

ไฟล์ unit อยู่ที่ไหน

ไฟล์ unit เก็บไว้หลายที่ และมีลำดับความสำคัญ:

  • /usr/lib/systemd/system/ (บน Debian และ Ubuntu มี /lib/systemd/system/ ด้วย) — unit ที่ติดตั้งมาจากแพ็กเกจ ไม่ควรแก้โดยตรง เพราะการอัปเดตแพ็กเกจจะเขียนทับ
  • /etc/systemd/system/ — unit และการแทนที่ค่าของผู้ดูแลระบบ มีลำดับความสำคัญสูงสุด
  • /run/systemd/system/ — unit ชั่วคราวที่สร้างขณะระบบทำงาน

หากต้องการดูเนื้อหาสุดท้ายของ unit พร้อมการแทนที่ทั้งหมด ใช้ systemctl cat nginx.service

Target แทน runlevel

runlevel แบบเก่าถูกแทนด้วย target multi-user.target คือโหมดเซิร์ฟเวอร์ทั่วไปที่ไม่มีกราฟิก graphical.target มีเชลล์กราฟิก rescue.target คือโหมดกู้คืนแบบผู้ใช้เดียว ดู target เริ่มต้นได้ด้วย systemctl get-default และเปลี่ยนด้วย systemctl set-default multi-user.target

systemctl: จัดการบริการ

systemctl คือเครื่องมือหลักในการทำงานกับ systemd คำสั่งส่วนใหญ่เปลี่ยนสถานะของระบบและต้องใช้ sudo

คำสั่งทำอะไร
systemctl status nginxสถานะบริการ PID หน่วยความจำ และบรรทัด log ล่าสุด
systemctl start nginxเริ่มทำงานทันที
systemctl stop nginxหยุดทำงาน
systemctl restart nginxเริ่มใหม่ (stop + start)
systemctl reload nginxโหลดการตั้งค่าใหม่โดยไม่หยุด (หากบริการรองรับ)
systemctl enable nginxตั้งให้เปิดอัตโนมัติเมื่อบูต
systemctl disable nginxยกเลิกการเปิดอัตโนมัติ
systemctl enable --now nginxตั้งให้เปิดอัตโนมัติและเริ่มทันที
systemctl is-active nginxแสดง active/inactive — เหมาะกับ script
systemctl list-units --type=serviceบริการที่โหลดอยู่
systemctl --failedunit ที่ล้มเหลว
systemctl daemon-reloadโหลดไฟล์ unit ใหม่หลังแก้ไข

อ่าน systemctl status อย่างไร

$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-10-12 09:14:03 UTC; 2h 5min ago
       Docs: man:nginx(8)
   Main PID: 812 (nginx)
      Tasks: 3 (limit: 2307)
     Memory: 6.1M
        CPU: 154ms
     CGroup: /system.slice/nginx.service
             ├─812 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─813 "nginx: worker process"
             └─814 "nginx: worker process"

บรรทัด Loaded บอกว่าไฟล์ unit มาจากไหน และเปิดอัตโนมัติอยู่หรือไม่ (enabled) บรรทัด Active คือสถานะปัจจุบัน: active (running) inactive (dead) หรือ failed ส่วน CGroup แสดงโปรเซสทั้งหมดของบริการ ซึ่งเป็นวิธีที่ systemd ใช้รู้ว่าโปรเซสใดเป็นของบริการ

enable ต่างจาก start อย่างไร

นี่คือจุดที่มักสับสน start เริ่มบริการทันที แต่หลังรีบูตบริการจะไม่ทำงานอีก ส่วน enable สร้าง symbolic link ในไดเรกทอรีของ target (เช่น /etc/systemd/system/multi-user.target.wants/) ทำให้บริการเริ่มตอนบูต แต่ไม่ได้เริ่มทันที จึงมักต้องทำทั้งสองอย่าง ใช้ enable --now

มีสถานะที่สามคือ mask — systemctl mask service เชื่อม unit กับ /dev/null ทำให้ไม่สามารถรันได้ทั้งด้วยมือและในฐานะ dependency เหมาะเมื่อต้องการให้บริการปิดแน่นอน

journalctl: log ของบริการ

ทุกอย่างที่บริการเขียนไปยัง stdout และ stderr จะถูก systemd-journald เก็บไว้ในไฟล์ log แบบไบนารีพร้อมข้อมูลกำกับ ได้แก่ ชื่อ unit PID ระดับความสำคัญ และเวลา อ่าน log ด้วย journalctl

journalctl -u nginx              # log ของบริการเดียว
journalctl -u nginx -f           # ติดตามแบบเรียลไทม์ เหมือน tail -f
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -n 50        # 50 บรรทัดล่าสุด
journalctl -b                    # ตั้งแต่บูตครั้งปัจจุบัน
journalctl -b -1                 # การบูตครั้งก่อนหน้า
journalctl -p err -b             # เฉพาะข้อผิดพลาดและที่ร้ายแรงกว่า
journalctl -k                    # ข้อความของ kernel
journalctl --disk-usage          # log ใช้พื้นที่เท่าไร

ตัวเลือก -p กรองตามระดับความสำคัญของ syslog: emerg, alert, crit, err, warning, notice, info, debug ระดับที่ระบุจะรวมระดับที่ร้ายแรงกว่าด้วย

log หลังรีบูต

หากไม่มีไดเรกทอรี /var/log/journal และใน /etc/systemd/journald.conf ตั้ง Storage=auto log จะเก็บเฉพาะในหน่วยความจำ (/run/log/journal) และหายไปเมื่อรีบูต หากต้องการให้คงอยู่ ตั้ง Storage=persistent หรือสร้างไดเรกทอรีแล้วรีสตาร์ต journald ขนาดถูกจำกัดด้วย SystemMaxUse= และล้าง log เก่าด้วย journalctl --vacuum-time=2weeks หรือ --vacuum-size=500M

journald มักทำงานคู่กับ rsyslog: journald ส่งข้อความให้ rsyslog ซึ่งเขียนไฟล์ข้อความแบบดั้งเดิมไว้ใน /var/log/ และส่ง log ไปยังเซิร์ฟเวอร์กลางได้

เปิดบริการของคุณเองอัตโนมัติ: ตัวอย่าง unit file

สมมติคุณมีแอปพลิเคชัน (script หรือไบนารี) ที่ต้องทำงานตลอดเวลา เปิดขึ้นเองเมื่อบูต และรีสตาร์ตเมื่อล้มเหลว สร้างไฟล์ /etc/systemd/system/myapp.service:

[Unit]
Description=My web application
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/opt/myapp/bin/server --port 8080
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

อธิบายแต่ละส่วน:

  • [Unit] — คำอธิบายและ dependency After= กำหนดเพียงลำดับ Wants= คือ dependency แบบอ่อน (ดึง unit ขึ้นมา แต่ไม่ล้มถ้า unit นั้นเริ่มไม่ได้) dependency แบบแข็งคือ Requires=
  • [Service] — วิธีรัน Type=simple หมายความว่าโปรเซสใน ExecStart คือตัวบริการเองและไม่แยกไปอยู่เบื้องหลัง User= รันด้วยผู้ใช้ที่ไม่มีสิทธิ์พิเศษ Restart=on-failure รีสตาร์ตบริการหากออกด้วยข้อผิดพลาด หลังจาก RestartSec วินาที
  • [Install] — สิ่งที่ enable จะทำ WantedBy=multi-user.target หมายความว่า "เริ่มเมื่อบูตตามปกติ"

นำไปใช้:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -f

ข้อผิดพลาดที่พบบ่อยใน unit file

  • พาธสัมพัทธ์ใน ExecStart พาธของโปรแกรมต้องเป็นแบบสัมบูรณ์ systemd ไม่ค้นหาคำสั่งใน PATH ของผู้ใช้เหมือนที่ shell ทำ
  • ลืม daemon-reload หลังแก้ไฟล์ systemd ยังใช้ค่าเดิม และจะเตือนใน status
  • daemon แยกไปอยู่เบื้องหลังเอง หากโปรแกรม fork ตัวเองแต่ระบุ Type=simple systemd จะคิดว่าบริการจบแล้ว ให้รันโปรแกรมในโหมด foreground หรือใช้ Type=forking กับ PIDFile=
  • ตัวแปรสภาพแวดล้อมจาก profile บริการไม่อ่าน ~/.bashrc และ /etc/profile ต้องกำหนดตัวแปรด้วย Environment= หรือ EnvironmentFile=

แทนที่ค่าโดยไม่แก้ unit ของแพ็กเกจ

หากต้องการเปลี่ยนพารามิเตอร์ของบริการที่มาจากแพ็กเกจ โดยไม่แตะไฟล์ของมัน ใช้ drop-in:

sudo systemctl edit nginx

โปรแกรมแก้ไขจะเปิดขึ้น และการเปลี่ยนแปลงจะถูกบันทึกใน /etc/systemd/system/nginx.service.d/override.conf เช่น เพิ่ม [Service] และ Restart=always เมื่อออกจากโปรแกรมแก้ไข systemd จะโหลดการตั้งค่าใหม่ให้เอง

Timer ของ systemd แทน cron

Timer คือ unit ที่รันบริการชื่อเดียวกันตามกำหนดเวลา ข้อดีเหนือ cron คือ log ของงานอยู่ใน journal มี dependency ได้ และสามารถรันชดเชยงานที่พลาดไปได้ (Persistent=true) ตัวอย่างการสำรองข้อมูลทุกวัน:

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers

ตรวจสอบรูปแบบ OnCalendar ได้ด้วย systemd-analyze calendar "*-*-* 03:00:00" ซึ่งจะแสดงเวลาที่จะรันครั้งถัดไป

วินิจฉัยการบูต

systemd เก็บเวลาเริ่มทำงานของแต่ละ unit ทำให้หาสาเหตุของการบูตช้าได้ง่าย:

systemd-analyze                  # เวลาบูตรวม
systemd-analyze blame            # unit เรียงตามเวลาเริ่มทำงาน
systemd-analyze critical-chain   # สายงานที่ทำให้การบูตช้า
systemd-analyze verify /etc/systemd/system/myapp.service   # ตรวจ unit file

สรุป

systemd คือ PID 1 และตัวจัดการบริการของ Linux ยุคใหม่ มันอธิบายทุกอย่างด้วย unit ควบคุมด้วย systemctl เก็บ log ลง journal ที่ journalctl อ่าน และสามารถรันงานด้วย timer แทน cron หากต้องการใช้ให้คล่อง เพียงเรียนรู้ status, enable --now, journalctl -u และเขียน unit file ง่ายๆ ที่มี Restart=on-failure ได้ ก็เพียงพอแล้ว systemd, journald และการทำ log ถูกสอนแบบลงมือทำในหลักสูตร Linux

คำถามที่พบบ่อย

จะรู้ได้อย่างไรว่าระบบใช้ systemd?

รัน ps -p 1 -o comm= หากผลลัพธ์เป็น systemd แสดงว่าระบบทำงานภายใต้ systemd นอกจากนี้ไดเรกทอรี /run/systemd/system จะมีอยู่เฉพาะเมื่อบูตด้วย systemd

systemctl restart ต่างจาก reload อย่างไร?

restart หยุดบริการแล้วเริ่มใหม่ การเชื่อมต่อจะขาดหาย ส่วน reload ขอให้บริการโหลดการตั้งค่าใหม่โดยไม่หยุด แต่ทำได้เฉพาะเมื่อ unit มี ExecReload

รันบริการ systemd ด้วยผู้ใช้ธรรมดาโดยไม่ต้องใช้ sudo ได้ไหม?

ได้ systemd มี instance ของผู้ใช้: วาง unit ไว้ใน ~/.config/systemd/user/ และจัดการด้วย systemctl --user หากต้องการให้ทำงานแม้ไม่มีเซสชันล็อกอิน ให้เปิด loginctl enable-linger สำหรับผู้ใช้นั้น

ทำไมบริการจึงอยู่ในสถานะ failed และจะรีเซ็ตอย่างไร?

หาสาเหตุใน journalctl -u ชื่อ -b และบรรทัด Active ของคำสั่ง status หลังแก้ไขแล้วให้เริ่มบริการใหม่ ส่วนการลบเครื่องหมาย failed โดยไม่ต้องรีสตาร์ต ใช้ systemctl reset-failed

log ของ systemd เก็บไว้ที่ไหนบนดิสก์?

หากตั้งให้เก็บถาวรจะอยู่ใน /var/log/journal/ เป็นรูปแบบไบนารี มิฉะนั้นจะอยู่ใน /run/log/journal/ ในหน่วยความจำ อ่านด้วย journalctl ไม่ควรใช้เครื่องมือประมวลผลข้อความทั่วไป

เรียนหัวข้อนี้ผ่านวิดีโอ

หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Linux: с нуля до уверенного администрирования”

ไปที่คอร์ส