โครงการนี้แสดงให้เห็นถึงวิธีการสร้างระบบปฏิบัติการ Linux ที่มีขนาดกะทัดรัดและทำงานได้อย่างรวดเร็ว ที่อยู่โครงการคือ https://github.com/superconvert/smart-os

ทำไมเราถึงเลือกเวอร์ชันเซิร์ฟเวอร์สำหรับการผลิต
เวอร์ชันเซิร์ฟเวอร์ไม่มีแพ็คเกจส่วนใหญ่ที่ระบบหน้าต่างขึ้นอยู่กับ หากระบบมาพร้อมกับแพ็คเกจเหล่านี้จะมีปัญหากับแพ็คเกจหลายเวอร์ชันปัญหาการรวบรวมปัญหาการพึ่งพาปัญหาการเชื่อมโยงและปัญหารันไทม์ซึ่งจะทำให้เกิดการรบกวนงานของเราเป็นจำนวนมาก ยิ่งกว่านั้นการแก้ปัญหาเหล่านี้ไม่มีความหมายเราต้องการแพ็คเกจการพึ่งพา
ทำไมระบบหน้าต่างจึงมีขนาดใหญ่มาก?
แพ็คเกจทั้งหมด (ยกเว้นเครื่องมือ) ที่เราติดตั้งโดยใช้ APT ในทางทฤษฎีจำเป็นต้องรวบรวมโดยซอร์สโค้ดรวมถึงการพึ่งพาแพ็คเกจและการยึดเกาะซึ่งจำเป็นต้องได้รับการแก้ไข นี่เป็นภาระงานที่ใหญ่มาก ไม่มีทางไม่มีอะไรในระบบใหม่และสภาพแวดล้อมที่จำเป็นต้องได้รับจากเรา โครงการ A ขึ้นอยู่กับแพ็คเกจ B, แพ็คเกจ B ขึ้นอยู่กับแพ็คเกจ C, แพ็คเกจ C และแพ็คเกจ C ขึ้นอยู่กับแพ็คเกจ D สิ่งที่เราต้องทำคือรวบรวมแพ็คเกจทั้งหมด!
สคริปต์นี้สร้างขึ้นบน Ubuntu 18.04 ระบบอื่น ๆ ไม่ควรเปลี่ยนแปลงมากนัก เพื่อนที่ต้องการมันสามารถแก้ไขได้ด้วยตัวเอง
เตรียมสภาพแวดล้อมของระบบ เนื่องจากต้องรวบรวมเคอร์เนลคุณต้องติดตั้งสภาพแวดล้อมที่จำเป็นสำหรับการรวบรวมเคอร์เนล เนื่องจากต้องมีการรวบรวม BusyBox คุณสามารถติดตั้งสภาพแวดล้อมที่จำเป็นด้วยตัวเองตามต้องการ
./00_build_env.shรวบรวมซอร์สโค้ด (เคอร์เนล, Glibc, BusyBox, GCC, Binutils)
./01_build_src.shสร้างดิสก์ระบบ (สำคัญขั้นตอนนี้ติดตั้งระบบลงในไฟล์ระบบ)
./02_build_img.shเรียกใช้ระบบ Smart-OS
./03_run_qemu.sh 或 ./04_run_docker.shง่ายต่อการสร้างระบบปฏิบัติการหรือไม่? พื้นที่ดิสก์สามารถขยายได้โดยพลการสามารถเข้าถึงได้ทางออนไลน์และสามารถขยายได้ตามต้องการ ฉันลองใช้งานได้สำเร็จแล้วและเรียกใช้การสตรีมเซิร์ฟเวอร์ SMART_RTMPD ใน Smart-OS
+----------------------------------------------------------------+-----------------------------------------+-----------------------------------------+
| Host | Container 1 | Container 2 |
| | | |
| +------------------------------------------------+ | +-------------------------+ | +-------------------------+ |
| | Newwork Protocol Stack | | | Newwork Protocol Stack | | | Newwork Protocol Stack | |
| +------------------------------------------------+ | +-------------------------+ | +-------------------------+ |
| + + | + | + |
| ............... | .................... | ........................... | ................... | ..................... | .................... | .................... |
| + + | + | + |
| +-------------+ +---------------+ | +---------------+ | +---------------+ |
| | 192.168.0.3 | | 192.168.100.1 | | | 192.168.100.6 | | | 192.168.100.8 | |
| +-------------+ +---------------+ +-------+ | +---------------+ | +---------------+ |
| | eth0 | | br0 | < --- > | tap0 | | | eth0 | | | eth0 | |
| +-------------+ +---------------+ +-------+ | +---------------+ | +---------------+ |
| + + + | + | + |
| | | | | | | | |
| | + +------------------------------+ | | |
| | +-------+ | | | |
| | | tap1 | | | | |
| | +-------+ | | | |
| | + | | | |
| | | | | | |
| | +-------------------------------------------------------------------------------------------+ |
| | | | |
| | | | |
+--------------- | ------------------------------------------------+-----------------------------------------+-----------------------------------------+
+
Physical Network (192.168.0.0/24)เนื่องจาก Smart-OS ติดตั้งไลบรารี Glibc Dynamic สิ่งนี้จึงขึ้นอยู่กับ Library Loader/Linker Ld-Linux-X86-64.SO.2 เนื่องจากแอปพลิเคชันเชื่อมโยงผ่านการรวบรวมแบบไดนามิกเมื่อแอปพลิเคชันที่ต้องการการเชื่อมโยงแบบไดนามิกถูกโหลดโดยระบบปฏิบัติการระบบจะต้องค้นหาและโหลดไฟล์ไลบรารีไดนามิกทั้งหมดที่ต้องการ งานนี้ทำโดย ld-linux.so.2 เมื่อโปรแกรมถูกโหลดระบบปฏิบัติการจะส่งมอบการควบคุมไปยัง LD-Linux.so แทนที่จะเป็นที่อยู่รายการปกติของโปรแกรม LD-LINUX.SO.2 จะค้นหาและโหลดไฟล์ไลบรารีที่จำเป็นทั้งหมดจากนั้นส่งมอบการควบคุมไปยังพอร์ทัลเริ่มต้นของแอปพลิเคชัน LD-LINUX-X86-64.SO.2 เป็นห่วงโซ่นุ่มของ LD-LINUX.SO.2 มันจะต้องมีอยู่ภายใต้ /lib64/ld-linux-x86-64.so.2 มิฉะนั้น BusyBox ที่รวบรวมแบบไดนามิกของเราขึ้นอยู่กับไลบรารี GLIBC การโหลดของไลบรารี GLIBC ต้องการ LD-LINUX-X86-64.SO หากไม่มีอยู่ในไดเรกทอรี /lib64 มันจะทำให้ระบบถูก paniced โดยตรง ปัญหานี้ต้องการความสนใจเป็นพิเศษ! - -
QEMU โดยทั่วไปมีหน้าต่างเล็ก ๆ หลังเริ่มต้น เมื่อเกิดข้อผิดพลาดแล้วจะไม่มีวิธีอ่านบันทึกข้อผิดพลาด จากนั้นคุณต้องเพิ่ม console = ttys0 ลงในรายการเริ่มต้นของด้วง ในเวลาเดียวกัน QEMU-SYSTEM-X86_64 เพิ่มเอาต์พุตพอร์ตอนุกรมให้กับไฟล์ -serial ไฟล์: ./ qemu.log ดังนั้นการดีบักจึงสะดวกกว่ามาก หลังจากการดีบักคุณต้องลบคอนโซล = ttys0 มิฉะนั้นเนื้อหาใน /etc/init.d/rcs อาจไม่แสดง
รุ่นของ GLIBC ที่เรารวบรวมมักจะสูงกว่ารุ่นที่มาพร้อมกับระบบ เราสามารถเขียนโปรแกรมทดสอบ main.c เพื่อทดสอบว่า GLIBC ถูกรวบรวมได้สำเร็จหรือไม่ ตัวอย่างเช่น:
# include < stdio.h >
int main () {
printf ( " Hello glibc n " );
return 0 ;
}เรารวบรวม
gcc -o test main.c -Wl,-rpath=/root/smart-os/work/glibc_install/usr/lib64 เราดำเนินการโปรแกรม./test สำเร็จและเรามักจะรายงานข้อผิดพลาดคล้ายกับ /lib64/libc.so.6: เวอร์ชัน `glibc_2.28 'นี้ไม่พบหรือกลุ่มโปรแกรมโดยตรง ในความเป็นจริงนี่คือเหตุผลที่ไม่มีการระบุตัวโหลดไลบรารีไดนามิก/linker และสภาพแวดล้อมของระบบ โดยปกติเมื่อเรารวบรวมไลบรารี GLIBC ไดเรกทอรีการรวบรวมจะสร้างไฟล์สคริปต์ testRun.sh โดยอัตโนมัติและเราดำเนินการโปรแกรมในไดเรกทอรีการรวบรวม
./testrun.sh ./test สิ่งนี้มักจะทำได้สำเร็จ นอกจากนี้เรายังสามารถบันทึกประโยคต่อไปนี้ลงในสคริปต์และมันก็โอเคที่จะทำการทดสอบ
exec env /root/smart-os/work/glibc_install/lib64/ld-linux-x86-64.so.2 --library-path /root/smart-os/work/glibc_install/lib64 ./testเราจะติดตามไลบรารีใดที่โหลดโดยโปรแกรมปฏิบัติการได้อย่างไร เพียงแค่ใช้ ld_debug = libs ./test เราโหลดไลบรารีล่วงหน้าและบังคับให้โหลดไลบรารีล่วงหน้าเพื่อใช้ LD_PRELOAD เพื่อบังคับให้โหลดไลบรารีล่วงหน้า
เมื่อเรารวบรวมไคโรเรามักจะพบปัญหามากมาย เราควรทำอย่างไรถ้ามีปัญหากับการรวบรวมไคโร? ข้อความแสดงข้อผิดพลาดบางอย่างยากที่จะค้นหาบนอินเทอร์เน็ตเพื่อดูไฟล์ config.log ที่สร้างขึ้นระหว่างการรวบรวม ข้อความแสดงข้อผิดพลาดมีรายละเอียดมาก! คุณสามารถแก้ปัญหาได้ตามข้อมูลที่รวดเร็ว
เกี่ยวกับตัวแปรระบบ init ของ BusyBox แม้ว่าจะใช้พารามิเตอร์เคอร์เนลของ GRUB แต่ก็เป็นไปไม่ได้ที่จะผ่านตัวแปรสภาพแวดล้อม init ของ BusyBox จะสร้างเส้นทางตัวแปรสภาพแวดล้อมเริ่มต้นโดยอัตโนมัติดังนั้นจึงจำเป็นต้องเปลี่ยนซอร์สโค้ดเพื่อรองรับเส้นทางที่กำหนดเอง แน่นอนโหมดการเข้าสู่ระบบของเชลล์จะอ่าน /ฯลฯ /โปรไฟล์ สำหรับโหมดที่ไม่ใช่ Login โหมดนี้ไม่ถูกต้องดังนั้นจึงมีข้อ จำกัด ในการส่งผ่าน /etc /profile
ความรู้นี้เกี่ยวข้องกับความรู้ที่ค่อนข้างใหญ่ มีบทความค่อนข้างน้อยที่แนะนำการรวบรวมและการใช้ XFCE4 ในประเทศจีนโดยเฉพาะรวมถึงต่างประเทศ ฉันยังข้ามแม่น้ำด้วยความรู้สึกหินและพยายามแสดงให้เห็นถึงความรู้นี้อย่างชัดเจน ฉันจะเปิดบทพิเศษเพื่ออธิบายเรื่องนี้ สำหรับการปลูกถ่าย XFCE4 เป็น Smart-OS จะเปิดเผยความลับของระบบกราฟิกไปยังจีน สำหรับรายละเอียดโปรดดู xfce4.md
ภาระงานรวมของระบบกราฟิกทั้งหมดมีขนาดใหญ่มากโดยเฉพาะอย่างยิ่งที่เกี่ยวข้องกับทุกด้านของระบบ มีข้อมูลที่เป็นระบบค่อนข้างน้อยเกี่ยวกับด้านนี้ในต่างประเทศและเกือบจะน้อยกว่าในประเทศจีน เป้าหมายคือ DIY ทุกสภาพแวดล้อมและโครงการโอเพ่นซอร์สส่วนบุคคลเพื่อให้ระบบกราฟิกทั้งหมดทำงานได้เหมือนเดิม Smart-OS ไม่ใช่คนแรก แต่โดยทั่วไปแล้วมันเป็นสามอันดับแรก ฉันยังไม่รู้ กระบวนการบูรณาการทั้งหมดนั้นยาวมากและฉันพบปัญหามากมาย ฉันจะไม่พูดถึงงานซ้ำ ๆ เหล่านี้ผ่านการดีบักและการรวบรวมอย่างต่อเนื่อง ภาระงานมีขนาดใหญ่เป็นพิเศษ ฉันเกือบจะอธิบายงานของฉันอย่างหนัก มันไม่ใช่การพูดเกินจริงอย่างแน่นอนเพื่ออธิบายงานของฉัน ประการที่สองฉันพบคะแนนความรู้มากมายซึ่งหลายแห่งได้เรียนรู้และขายทันที ฉันต้องเข้าใจกลไกการทำงานอย่างรวดเร็วทำให้เกิดปัญหาแล้วแก้ปัญหา มาพูดคุยเกี่ยวกับแนวคิดโดยรวมโดยประมาณซึ่งจะช่วยให้นักวิชาการใหม่เข้าใจความคิดได้อย่างรวดเร็วให้คำแนะนำเกี่ยวกับการบำรุงรักษาระบบและจัดทำแบบจำลองสำหรับการแก้ปัญหาระบบ
ไดเรกทอรี USR ให้รายละเอียดเกี่ยวกับตัวย่อของทรัพยากรระบบ USR = UNIX ห้องสมุด /lib เป็นห้องสมุดระดับเคอร์เนล /usr /lib เป็นไลบรารีระดับระบบและ /usr /local /lib เป็นไลบรารีระดับแอปพลิเคชัน /lib มีไลบรารีจำนวนมากที่ใช้โดยโปรแกรมปฏิบัติการใน /bin && /sbin /usr/lib เกือบทุกไลบรารีที่อ้างอิงโดยโปรแกรมปฏิบัติการระบบได้รับการติดตั้งที่นี่และ/usr/local/bin ไลบรารีจำนวนมากที่อ้างอิงโดยโปรแกรมปฏิบัติการระดับแอปพลิเคชันจะถูกวางไว้ที่นี่
Ramfs:
RAMFS เป็นระบบไฟล์ที่ง่ายมาก มันใช้ประโยชน์โดยตรงจากกลไกแคชที่มีอยู่ของเคอร์เนล Linux (ดังนั้นรหัสการใช้งานจึงมีขนาดเล็กมากด้วยเหตุนี้คุณสมบัติ RAMFS จึงไม่สามารถถูกบล็อกผ่านพารามิเตอร์การกำหนดค่าเคอร์เนลมันเป็นคุณสมบัติตามธรรมชาติของเคอร์เนล) มันใช้หน่วยความจำทางกายภาพของระบบเพื่อสร้างระบบไฟล์ที่ใช้หน่วยความจำด้วยขนาดแบบไดนามิก ระบบจะไม่รีไซเคิลและผู้ใช้รูทเท่านั้นที่ใช้
TMPFS:
TMPFS เป็นอนุพันธ์ของ RAMFs ซึ่งเพิ่มขีดจำกัดความจุและอนุญาตให้เขียนข้อมูลเพื่อแลกเปลี่ยนตาม RAMF เนื่องจากการเพิ่มคุณสมบัติทั้งสองนี้ผู้ใช้ทั่วไปจึงสามารถใช้ TMPFs ได้ TMPF มีหน่วยความจำเสมือนไม่ใช่ RAM ทั้งหมดและประสิทธิภาพของมันอาจไม่สูงเท่ากับ RAMFS
Ramdisk:
Ramdisk เป็นเทคโนโลยีที่ใช้ชิ้นส่วนของพื้นที่ในหน่วยความจำเป็นดิสก์ทางกายภาพ นอกจากนี้ยังสามารถกล่าวได้ว่า Ramdisk เป็นอุปกรณ์บล็อกที่สร้างขึ้นในชิ้นส่วนของหน่วยความจำสำหรับการจัดเก็บระบบไฟล์ สำหรับผู้ใช้ Ramdisk สามารถรักษาได้อย่างเท่าเทียมกันกับพาร์ติชันฮาร์ดดิสก์ปกติ ระบบจะเก็บแคชที่สอดคล้องกันในหน่วยความจำมลพิษแคช CPU ประสิทธิภาพที่ไม่ดีและต้องการการสนับสนุนไดรเวอร์ที่สอดคล้องกัน
รูท:
ROOTFS เป็นอินสแตนซ์ของ RAMF ที่เฉพาะเจาะจง (หรือ TMPFS หากเปิดใช้งาน TMPFs) จะมีอยู่ในระบบ Linux2.6 เสมอ Rootfs ไม่สามารถถอนการติดตั้งได้ (แทนที่จะเพิ่มรหัสพิเศษเพื่อรักษารายการที่เชื่อมโยงเปล่ามันจะดีกว่าที่จะเพิ่มโหนดรูทฟ์ดังนั้นจึงสะดวกสำหรับการบำรุงรักษาเคอร์เนลรูทเป็นอินสแตนซ์ที่ว่างเปล่าของ RAMFs และใช้พื้นที่น้อยมาก) ระบบไฟล์อื่น ๆ ส่วนใหญ่จะถูกติดตั้งบน rootfs แล้วไม่สนใจ มันคือการเริ่มต้นการเริ่มต้นเคอร์เนลของระบบไฟล์รูท
Rootfs แบ่งออกเป็นรูทเสมือนจริงและรูทฟ์จริง
Rootfs เสมือนถูกสร้างและโหลดโดยเคอร์เนลเองและมีอยู่ในหน่วยความจำเท่านั้น (initramfs ที่ตามมาจะถูกนำไปใช้บนพื้นฐานนี้) และระบบไฟล์เป็นประเภท TMPFS หรือประเภท RAMFS
ROUTFS จริงหมายความว่าระบบไฟล์รูทมีอยู่บนอุปกรณ์จัดเก็บข้อมูล ในระหว่างกระบวนการเริ่มต้นเคอร์เนลจะติดตั้งอุปกรณ์จัดเก็บข้อมูลนี้บนรูทเสมือนจริงจากนั้นสลับโหนด / ไดเรกทอรีไปยังอุปกรณ์จัดเก็บข้อมูลนี้ ด้วยวิธีนี้ระบบไฟล์บนอุปกรณ์จัดเก็บข้อมูลจะถูกใช้เป็นระบบรูทไฟล์ (initramdisk ที่ตามมาจะถูกนำไปใช้บนพื้นฐานนี้) และประเภทระบบไฟล์ของมันจะยิ่งสูงขึ้นซึ่งสามารถ ext2, yaffs, yaffs2 ฯลฯ ซึ่งถูกกำหนดโดยประเภทของอุปกรณ์จัดเก็บข้อมูลเฉพาะ
ระบบไฟล์สตาร์ทอัพของเราคือการเตรียมไฟล์สำหรับ rootfs เพื่อให้เคอร์เนลสามารถดำเนินการตามที่เราต้องการ ในระบบต้น Linux โดยทั่วไปจะใช้ฮาร์ดดิสก์หรือดิสก์ฟลอปปี้เป็นอุปกรณ์จัดเก็บข้อมูลสำหรับระบบไฟล์รูท Linux ดังนั้นจึงเป็นเรื่องง่ายที่จะรวมไดรเวอร์ของอุปกรณ์เหล่านี้เข้ากับเคอร์เนล อย่างไรก็ตามในระบบฝังตัวของวันนี้ระบบไฟล์รูทอาจถูกบันทึกลงในอุปกรณ์จัดเก็บข้อมูลต่างๆรวมถึง SCSI, SATA, U-Disk ฯลฯ ดังนั้นจึงไม่สะดวกมากที่จะรวบรวมรหัสไดรเวอร์ทั้งหมดของอุปกรณ์เหล่านี้ลงในเคอร์เนล ในเคอร์เนลโมดูลกลไกการโหลดอัตโนมัติ UDEV เราเห็นว่า UDEVD สามารถตระหนักถึงการโหลดโมดูลเคอร์เนลอัตโนมัติดังนั้นเราหวังว่าหากไดรเวอร์ของอุปกรณ์จัดเก็บข้อมูลที่จัดเก็บระบบไฟล์รูทสามารถตระหนักถึงการโหลดอัตโนมัติ อย่างไรก็ตามมีความขัดแย้งที่นี่ UDEVD เป็นไฟล์ที่เรียกใช้งานได้ เป็นไปไม่ได้ที่จะเรียกใช้งาน UDEVD ก่อนที่ระบบรูทไฟล์จะถูกติดตั้ง อย่างไรก็ตามหาก UDEVD ไม่ได้เริ่มต้นไดรเวอร์ที่เก็บอุปกรณ์ระบบรูทไฟล์ระบบไม่สามารถโหลดได้โดยอัตโนมัติและโหนดอุปกรณ์ที่เกี่ยวข้องไม่สามารถสร้างได้ในไดเรกทอรี /dev เพื่อที่จะแก้ไขความขัดแย้งนี้ได้เริ่มต้น initrd (bootloader ที่เริ่มต้นแล้วดิสก์ RAM ดิสก์) Initrd เป็นไดเรกทอรีรากขนาดเล็กที่อัดแน่น ไดเรกทอรีนี้มีโมดูลไดรเวอร์ที่จำเป็นไฟล์ปฏิบัติการและสคริปต์เริ่มต้นในขั้นตอนการเริ่มต้นและยังรวมถึง UDEVD (ปีศาจที่ใช้กลไก UDEV) เมื่อระบบเริ่มต้น bootloader จะอ่านไฟล์ initrd ลงในหน่วยความจำแล้วส่งที่อยู่เริ่มต้นและขนาดของไฟล์ initrd ในหน่วยความจำไปยังเคอร์เนล ในระหว่างกระบวนการเริ่มต้นเคอร์เนลจะบีบอัดไฟล์ initrd จากนั้นติดตั้ง initrd ที่คลายซิปเป็นไดเรกทอรีรูทแล้วเรียกใช้สคริปต์ /init ในไดเรกทอรีรูท (init ในรูปแบบ CPIO คือ /init ในขณะที่เริ่มต้นในรูปแบบภาพ <หรือที่เรียกว่าเริ่มต้นของอุปกรณ์บล็อกเก่าหรือเริ่มต้น คุณสามารถเรียกใช้ UDEVD ในระบบไฟล์ Initrd ในสคริปต์นี้ให้โหลดไดรเวอร์ Realfs (ระบบไฟล์จริง) โดยอัตโนมัติสำหรับการจัดเก็บอุปกรณ์และสร้างโหนดอุปกรณ์ที่จำเป็นในไดเรกทอรี /dev หลังจาก UDEVD โหลดไดรเวอร์ดิสก์โดยอัตโนมัติคุณสามารถติดตั้งไดเรกทอรีรูทจริงและสลับไปยังไดเรกทอรีรูทนี้