• Nitro คือ ตัวควบคุมดูแลโปรเซสและระบบ init ขนาดจิ๋วมาก ที่ใช้งานได้กับทั้งระบบฝังตัว เซิร์ฟเวอร์ เดสก์ท็อป และคอนเทนเนอร์
  • เก็บสถานะของระบบไว้ใน RAM เท่านั้น จึงทำงานได้อย่างราบรื่นแม้บนระบบไฟล์แบบอ่านอย่างเดียว พร้อมมอบ สถาปัตยกรรมแบบ event-driven ที่รวดเร็วและมีประสิทธิภาพ
  • รูปแบบการตั้งค่าคือโครงสร้างไดเรกทอรีสคริปต์ที่เรียบง่าย จึงจัดการบริการได้โดยไม่ต้องมีไฟล์ตั้งค่าที่ซับซ้อนหรือขั้นตอน build เพิ่มเติม
  • รองรับ บริการแบบพารามิเตอร์ การรีสตาร์ตที่ทนทาน และความสามารถด้าน logging ที่เชื่อถือได้สำหรับแต่ละบริการ รวมถึง ฟีเจอร์ที่เหมาะกับคอนเทนเนอร์และสภาพแวดล้อมแบบฝังตัว
  • รับประกัน ความยืดหยุ่นและการควบคุมระดับสูง ด้วย การควบคุมจากระยะไกลผ่านเครื่องมือ nitroctl และการควบคุมการทำงานด้วยสัญญาณ

ภาพรวม

Nitro คือ ตัวควบคุมดูแลโปรเซสขนาดจิ๋วมาก ที่สามารถใช้เป็น pid 1 บน Linux ได้

ขอบเขตการใช้งานหลักมีดังนี้

  • init สำหรับเครื่อง Linux หลากหลายประเภท เช่น ระบบฝังตัว เดสก์ท็อป และเซิร์ฟเวอร์
  • init ของ Linux initramfs
  • init สำหรับสภาพแวดล้อมคอนเทนเนอร์ เช่น Docker/Podman/LXC/Kubernetes
  • เดมอน supervision ที่ทำงานได้โดยไม่ต้องใช้สิทธิ์บนระบบ POSIX

การตั้งค่าใช้โครงสร้างสคริปต์แบบอิงไดเรกทอรี โดยตำแหน่งเริ่มต้นคือ /etc/nitro

ข้อกำหนด

  • ต้องการการรองรับ Unix socket ของเคอร์เนล
  • ต้องมี tmpfs หรือ ไดเรกทอรี /run ที่เขียนได้

ข้อดีเมื่อเทียบกับระบบอื่น

  • ข้อมูลสถานะทั้งหมด ถูกเก็บไว้ใน RAM เท่านั้น จึงทำงานได้บน root filesystem แบบอ่านอย่างเดียวโดยไม่ต้องใช้เทคนิคพิเศษ
  • ให้ประสิทธิภาพด้วย รูปแบบการทำงานแบบ event-driven ที่ไม่มีการ polling
  • ไม่มีการจัดสรรหน่วยความจำแบบไดนามิก ระหว่างรันไทม์
  • ไม่มีการใช้ file descriptor เพิ่มขึ้นอย่างไม่จำกัด
  • ต้องการเพียง ไบนารีแบบ self-contained ตัวเดียว (อาจมีไบนารีควบคุมเพิ่มเป็นตัวเลือก)
  • ไม่ต้องแปลงหรือคอมไพล์ไฟล์ตั้งค่า บริการเป็นเพียง ไดเรกทอรีธรรมดาที่มีสคริปต์อยู่ภายใน
  • รองรับ การรีสตาร์ตบริการและสายโซ่ logging
  • ทำงานได้ตามปกติแม้นาฬิการะบบจะไม่แม่นยำ
  • สามารถรันผ่าน /etc/ttys บน FreeBSD ได้
  • สามารถสร้าง static binary ขนาดเล็กมากได้เมื่อใช้ musl libc

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

  • แต่ละไดเรกทอรีบริการ (ค่าเริ่มต้นอยู่ภายใน /etc/nitro) อาจมีไฟล์ต่อไปนี้

    • setup: สคริปต์ (ทางเลือก) ที่รันก่อนเริ่มบริการ จะเริ่มบริการได้ก็ต่อเมื่อจบแบบปกติ (0) เท่านั้น
    • run: สคริปต์สำหรับการทำงานของบริการ ตราบใดที่ยังไม่จบจะถือว่าบริการยังทำงานอยู่ หากยังไม่ถูกติดตั้งจะถือเป็นบริการแบบ one-shot
    • finish: สคริปต์ (ทางเลือก) ที่รันหลัง run จบลง โดยส่งสถานะการจบและค่าสัญญาณเป็นอาร์กิวเมนต์
    • log: symbolic link ที่ชี้ไปยังไดเรกทอรีบริการอื่น โดยจะ pipe เอาต์พุตของ run ไปเป็นอินพุตของบริการนั้น (ใช้ทำ logging chain ได้)
    • down: หากไฟล์นี้มีอยู่ nitro จะไม่ยกบริการนี้ขึ้นโดยค่าเริ่มต้น
    • หากชื่อไดเรกทอรีลงท้ายด้วย '@' จะถูกมองข้ามและนำไปใช้เป็นบริการแบบพารามิเตอร์ได้
    • ชื่อบริการต้องยาวน้อยกว่า 64 ตัวอักษร และห้ามมีอักขระ /, ,, ขึ้นบรรทัดใหม่
  • ยูทิลิตี chpst ของ runit มีประโยชน์ในการเขียนสคริปต์ run

บริการพิเศษ

  • LOG: บริการค่าเริ่มต้นสำหรับบันทึก log ของทุกบริการที่ไม่มีลิงก์ log
  • SYS: SYS/setup จะถูกรันก่อนเริ่มทุกบริการ จึงใช้สร้างลำดับการเริ่มบริการได้
    • SYS/finish: รันก่อนเข้าสู่ขั้นตอนปิดระบบทั้งหมด
    • SYS/final: รันหลังจากทุกโปรเซสถูกปิดแล้ว
    • SYS/fatal: รันแทนการปิดเมื่อเกิดข้อผิดพลาดร้ายแรง (ถ้ามี)
    • SYS/reincarnate: รันแทน shutdown และอาจใช้สำหรับการสร้าง initramfs ขึ้นใหม่ เป็นต้น

บริการแบบพารามิเตอร์

  • ไดเรกทอรีบริการที่ลงท้ายด้วย '@' จะถูก nitro มองข้าม แต่สามารถระบุใช้งานได้โดยตรงผ่าน symbolic link หรือคำสั่ง nitroctl
  • พารามิเตอร์ที่ต่อท้ายหลัง '@' จะถูกส่งเป็นอาร์กิวเมนต์ตัวแรกให้แต่ละสคริปต์
    • ตัวอย่าง: หากมี symbolic link agetty@/run และ agetty@tty1 จะมีการรัน agetty@/run tty1
    • เมื่อป้อน nitroctl up agetty@tty2 ก็สามารถรัน agetty@/run tty2 ได้ (ไม่ขึ้นกับว่ามีไดเรกทอรีอยู่หรือไม่)

โหมดการทำงาน

  • วงจรชีวิตทั้งหมดประกอบด้วย 3 ขั้นตอนคือ บูต รันบริการ (supervision) และปิดระบบ
    • บูต: หากมีบริการพิเศษ SYS จะรันตั้งแต่ setup ก่อน แล้วจึงรันทุกบริการที่ไม่ใช่ down
    • หากบริการจบลงจะถูกรีสตาร์ตใหม่ แต่ถ้าเพิ่งรีสตาร์ตไปไม่นานจะรอ 2 วินาที
    • สามารถส่งสัญญาณปิดระบบได้ด้วย nitroctl Reboot หรือ Shutdown
      • ในกรณีนี้จะเป็นลำดับ SYS/finish → ส่ง SIGTERM ให้ทุกบริการ (รอได้สูงสุด 7 วินาที) → SIGKILL → SYS/final → ลำดับการปิด
    • หากใช้กับคอนเทนเนอร์หรือ supervisor ที่ไม่ใช้สิทธิ์ จะปิดเฉพาะโปรเซสเท่านั้น

การควบคุมด้วย nitroctl

  • เครื่องมือ CLI nitroctl ใช้ควบคุม nitro จากระยะไกลได้

ตัวอย่างคำสั่ง:

  • list: แสดงรายการบริการ สถานะ PID uptime และสถานะการจบล่าสุด
  • up/down/start/stop/restart: ควบคุมการเริ่ม·หยุด·รีสตาร์ตบริการ เป็นต้น
  • การส่งสัญญาณ: p(SIGSTOP), c(SIGCONT), h(SIGHUP), a(SIGALRM), i(SIGINT), q(SIGQUIT), 1(SIGUSR1), 2(SIGUSR2), t(SIGTERM), k(SIGKILL)
  • pidof: แสดง PID ของบริการที่ระบุ
  • rescan: อ่านไดเรกทอรีบริการใหม่ และสะท้อนบริการที่ถูกเพิ่มหรือลบ
  • Shutdown/Reboot: ปิดหรือรีบูตทั้งระบบ

การควบคุมผ่านสัญญาณ

  • สามารถควบคุมได้ด้วยการส่งสัญญาณตรงไปยังโปรเซส nitro
    • SIGHUP: สแกนบริการใหม่ (rescan)
    • SIGINT: รีบูต
    • SIGTERM: ปิดระบบ (หาก nitro ไม่ใช่ pid 1)

Nitro ในฐานะ init บน Linux

  • Nitro เป็นไบนารีแบบบรรจุครบในตัวและสามารถบูตเป็น Linux pid 1 ได้โดยตรง
  • จะเมานต์ /dev, /run เมื่อต้องการ และให้จัดการการทำงานอื่น ๆ ใน SYS/setup
  • อีเวนต์ Ctrl-Alt-Del จะทริกเกอร์การรีบูตอย่างเป็นระเบียบ

การใช้ Nitro เป็น init ในคอนเทนเนอร์ Docker

  • Nitro สามารถ build แบบ static และใส่ลงในคอนเทนเนอร์ได้อย่างง่ายดาย
  • ต้องมี /run อยู่ในคอนเทนเนอร์เพื่อใช้พาธซ็อกเก็ตเริ่มต้น
  • หากทำ bind mount ให้ control socket ก็จะควบคุมจากภายนอกด้วย nitroctl จากระยะไกลได้

Nitro บน FreeBSD

  • สามารถให้ FreeBSD init ดูแล nitro ได้ด้วยการเพิ่มบรรทัดต่อไปนี้ใน /etc/ttys
    /etc/nitro "/usr/local/sbin/nitro" "" on
    

ผู้เขียน

คำขอบคุณ

  • พัฒนาขึ้นจากการวิเคราะห์อย่างละเอียดของ ระบบควบคุมดูแลโปรเซส ที่มีอยู่เดิม เช่น daemontools, freedt, runit, perp, s6 เป็นต้น

สัญญาอนุญาต

  • สัญญาอนุญาต 0BSD (ดูรายละเอียดในไฟล์ LICENSE)

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น