บทความนี้กล่าวถึงการทำแซนด์บ็อกซ์ใน Bazel, การติดตั้ง sandboxfs และการแก้ไขข้อบกพร่องในสภาพแวดล้อมแซนด์บ็อกซ์
การทำแซนด์บ็อกซ์เป็นกลยุทธ์การจำกัดสิทธิ์ที่แยกกระบวนการออกจากกันหรือแยกออกจากทรัพยากรในระบบ สำหรับ Bazel หมายถึงการจำกัดการเข้าถึงระบบไฟล์
แซนด์บ็อกซ์ระบบไฟล์ของ Bazel จะเรียกใช้กระบวนการในไดเรกทอรีการทำงานที่มีเฉพาะอินพุตที่รู้จัก เพื่อให้คอมไพเลอร์และเครื่องมืออื่นๆ ไม่เห็นไฟล์ต้นฉบับที่ตนไม่ควรเข้าถึง เว้นแต่จะทราบเส้นทางแบบสัมบูรณ์ไปยังไฟล์เหล่านั้น
การทำแซนด์บ็อกซ์ไม่ได้ซ่อนสภาพแวดล้อมโฮสต์แต่อย่างใด กระบวนการต่างๆ สามารถเข้าถึงไฟล์ทั้งหมดในระบบไฟล์ได้อย่างอิสระ อย่างไรก็ตาม ในแพลตฟอร์มที่รองรับเนมสเปซของผู้ใช้ กระบวนการต่างๆ จะแก้ไขไฟล์ใดๆ นอกไดเรกทอรีการทำงานของตนไม่ได้ ซึ่งจะช่วยให้กราฟบิลด์ไม่มีการขึ้นต่อกันที่ซ่อนอยู่ซึ่งอาจส่งผลต่อความสามารถในการทำซ้ำของบิลด์
โดยเฉพาะอย่างยิ่ง Bazel จะสร้างไดเรกทอรี execroot/ สำหรับการดำเนินการแต่ละรายการ ซึ่งทำหน้าที่เป็นไดเรกทอรีการทำงานของการดำเนินการในเวลารันไทม์ execroot/
มีไฟล์อินพุตทั้งหมดสำหรับการดำเนินการและทำหน้าที่เป็นคอนเทนเนอร์สำหรับเอาต์พุตที่สร้างขึ้น จากนั้น Bazel จะใช้เทคนิคที่ระบบปฏิบัติการมีให้ เช่น คอนเทนเนอร์ใน Linux และ sandbox-exec ใน macOS เพื่อจำกัดการดำเนินการภายใน execroot/
เหตุผลในการทำแซนด์บ็อกซ์
หากไม่มีการทำแซนด์บ็อกซ์การดำเนินการ Bazel จะไม่ทราบว่าเครื่องมือใช้ไฟล์อินพุตที่ไม่ได้ประกาศไว้ (ไฟล์ที่ไม่ได้ระบุไว้อย่างชัดเจนในการขึ้นต่อกันของการดำเนินการ) หรือไม่ เมื่อไฟล์อินพุตที่ไม่ได้ประกาศไว้ไฟล์ใดไฟล์หนึ่งมีการเปลี่ยนแปลง Bazel จะยังคงเชื่อว่าบิลด์เป็นเวอร์ชันล่าสุดและจะไม่สร้างการดำเนินการใหม่ ซึ่งอาจส่งผลให้เกิดบิลด์แบบเพิ่มทีละส่วนที่ไม่ถูกต้อง
การนำรายการแคชกลับมาใช้ซ้ำอย่างไม่ถูกต้องจะทำให้เกิดปัญหาในระหว่างการแคชระยะไกล รายการแคชที่ไม่ดีในแคชที่แชร์จะส่งผลกระทบต่อนักพัฒนาซอฟต์แวร์ทุกคนในโปรเจ็กต์ และการล้างแคชระยะไกลทั้งหมดไม่ใช่โซลูชันที่เหมาะสม
การทำแซนด์บ็อกซ์จะจำลองลักษณะการทำงานของการดำเนินการระยะไกล ซึ่งหมายความว่าหากบิลด์ทำงานได้ดีกับการทำแซนด์บ็อกซ์ บิลด์นั้นก็น่าจะทำงานได้ดีกับการดำเนินการระยะไกลด้วย การทำให้การดำเนินการระยะไกลอัปโหลดไฟล์ที่จำเป็นทั้งหมด (รวมถึงเครื่องมือในเครื่อง) จะช่วยลดค่าใช้จ่ายในการบำรุงรักษาคลัสเตอร์การคอมไพล์ได้อย่างมากเมื่อเทียบกับการต้องติดตั้งเครื่องมือในทุกเครื่องในคลัสเตอร์ทุกครั้งที่ต้องการลองใช้คอมไพเลอร์ใหม่หรือทำการเปลี่ยนแปลงเครื่องมือที่มีอยู่
กลยุทธ์แซนด์บ็อกซ์ที่ควรใช้
คุณสามารถเลือกประเภทการทำแซนด์บ็อกซ์ที่จะใช้ (หากมี) ด้วย
แฟล็กกลยุทธ์ การใช้กลยุทธ์ sandboxed จะทำให้ Bazel เลือกการติดตั้งใช้งานแซนด์บ็อกซ์รายการใดรายการหนึ่งที่ระบุไว้ด้านล่าง โดยจะเลือกแซนด์บ็อกซ์เฉพาะของระบบปฏิบัติการมากกว่าแซนด์บ็อกซ์ทั่วไปที่มีความปลอดภัยน้อยกว่า
เวิร์กเกอร์แบบถาวรจะทำงานในแซนด์บ็อกซ์ทั่วไปหากคุณส่ง
แฟล็ก --worker_sandboxing
กลยุทธ์ local (หรือ standalone) จะไม่ทำการทำแซนด์บ็อกซ์ใดๆ
โดยจะเรียกใช้บรรทัดคำสั่งของการดำเนินการโดยตั้งค่าไดเรกทอรีการทำงานเป็น execroot ของพื้นที่ทำงาน
processwrapper-sandbox เป็นกลยุทธ์การทำแซนด์บ็อกซ์ที่ไม่ต้องใช้ฟีเจอร์ "ขั้นสูง" ใดๆ โดยควรทำงานในระบบ POSIX ทุกระบบได้ทันที กลยุทธ์นี้จะสร้างไดเรกทอรีแซนด์บ็อกซ์ที่ประกอบด้วยลิงก์สัญลักษณ์ที่ชี้ไปยังไฟล์ต้นฉบับ เรียกใช้บรรทัดคำสั่งของการดำเนินการโดยตั้งค่าไดเรกทอรีการทำงานเป็นไดเรกทอรีนี้แทน execroot จากนั้นย้ายอาร์ติแฟกต์เอาต์พุตที่รู้จักออกจากแซนด์บ็อกซ์ไปยัง execroot และลบแซนด์บ็อกซ์ ซึ่งจะป้องกันไม่ให้การดำเนินการใช้ไฟล์อินพุตที่ไม่ได้ประกาศไว้โดยไม่ตั้งใจ และป้องกันไม่ให้ execroot มีไฟล์เอาต์พุตที่ไม่รู้จัก
linux-sandbox จะก้าวไปอีกขั้นและสร้างขึ้นจาก processwrapper-sandbox กลยุทธ์นี้จะใช้เนมสเปซของ Linux (เนมสเปซของผู้ใช้, การต่อเชื่อม, PID, เครือข่าย และ IPC) เพื่อแยกการดำเนินการออกจากโฮสต์ ซึ่งคล้ายกับสิ่งที่ Docker ทำเบื้องหลัง กล่าวคือ กลยุทธ์นี้จะทำให้ระบบไฟล์ทั้งหมดเป็นแบบอ่านอย่างเดียว ยกเว้นไดเรกทอรีแซนด์บ็อกซ์ เพื่อไม่ให้การดำเนินการแก้ไขสิ่งต่างๆ ในระบบไฟล์ของโฮสต์โดยไม่ตั้งใจ ซึ่งจะป้องกันสถานการณ์ต่างๆ เช่น การทดสอบที่มีข้อบกพร่องที่เรียกใช้คำสั่ง rm -rf ในไดเรกทอรี $HOME โดยไม่ตั้งใจ นอกจากนี้ คุณยังป้องกันไม่ให้การดำเนินการเข้าถึงเครือข่ายได้ด้วย (ไม่บังคับ) linux-sandbox ใช้เนมสเปซ PID เพื่อป้องกันไม่ให้การดำเนินการเห็นกระบวนการอื่นๆ และเพื่อหยุดกระบวนการทั้งหมด (แม้แต่เดมอนที่สร้างขึ้นโดยการดำเนินการ) ได้อย่างน่าเชื่อถือในตอนท้าย
darwin-sandbox มีลักษณะคล้ายกัน แต่ใช้สำหรับ macOS กลยุทธ์นี้ใช้เครื่องมือ sandbox-exec ของ Apple เพื่อให้ได้ผลลัพธ์ที่คล้ายกับแซนด์บ็อกซ์ของ Linux
ทั้ง linux-sandbox และ darwin-sandbox จะไม่ทำงานในสถานการณ์ "ซ้อนกัน" เนื่องจากข้อจำกัดในกลไกที่ระบบปฏิบัติการมีให้ เนื่องจาก Docker ใช้เนมสเปซของ Linux สำหรับฟีเจอร์คอนเทนเนอร์ด้วย คุณจึงเรียกใช้ linux-sandbox ภายในคอนเทนเนอร์ Docker ได้ไม่สะดวก เว้นแต่จะใช้ docker run --privileged ใน macOS คุณจะเรียกใช้ sandbox-exec ภายในกระบวนการที่กำลังทำแซนด์บ็อกซ์อยู่ไม่ได้ ดังนั้น ในกรณีเหล่านี้ Bazel จะกลับไปใช้ processwrapper-sandbox โดยอัตโนมัติ
หากต้องการรับข้อผิดพลาดของบิลด์ (เช่น เพื่อไม่ให้สร้างด้วยกลยุทธ์การดำเนินการที่เข้มงวดน้อยกว่าโดยไม่ตั้งใจ) ให้แก้ไขรายการกลยุทธ์การดำเนินการที่ Bazel พยายามใช้โดยชัดแจ้ง (เช่น bazel build
--spawn_strategy=worker,linux-sandbox)
โดยปกติแล้วการดำเนินการแบบไดนามิกจะต้องมีการทำแซนด์บ็อกซ์สำหรับการดำเนินการในเครื่อง หากต้องการเลือกไม่ใช้ ให้ส่งแฟล็ก --experimental_local_lockfree_output การดำเนินการแบบไดนามิกจะทำแซนด์บ็อกซ์
เวิร์กเกอร์แบบถาวรโดยไม่แสดงข้อความใดๆ
ข้อเสียของการทำแซนด์บ็อกซ์
การทำแซนด์บ็อกซ์ทำให้เกิดค่าใช้จ่ายเพิ่มเติมในการตั้งค่าและล้างข้อมูล ค่าใช้จ่ายนี้จะมีขนาดเท่าใดขึ้นอยู่กับหลายปัจจัย รวมถึงรูปร่างของบิลด์และประสิทธิภาพของระบบปฏิบัติการโฮสต์ สำหรับ Linux บิลด์ที่ทำแซนด์บ็อกซ์มักจะช้ากว่าไม่กี่เปอร์เซ็นต์เท่านั้น การตั้งค่า
--reuse_sandbox_directoriesจะช่วยลดค่าใช้จ่ายในการตั้งค่าและล้างข้อมูลได้การทำแซนด์บ็อกซ์จะปิดใช้แคชที่เครื่องมืออาจมีอยู่ คุณสามารถ ลดผลกระทบนี้ได้โดยใช้ เวิร์กเกอร์แบบถาวร แต่ ต้องแลกมาด้วยการรับประกันแซนด์บ็อกซ์ที่อ่อนแอกว่า
เวิร์กเกอร์แบบมัลติเพล็กซ์ต้องมีการรองรับเวิร์กเกอร์อย่างชัดแจ้ง จึงจะทำแซนด์บ็อกซ์ได้ เวิร์กเกอร์ที่ไม่รองรับการทำแซนด์บ็อกซ์แบบมัลติเพล็กซ์จะทำงานเป็นเวิร์กเกอร์แบบซิงเกิลเพล็กซ์ภายใต้การดำเนินการแบบไดนามิก ซึ่งอาจทำให้ใช้หน่วยความจำเพิ่มเติม
sandboxfs
sandboxfs เป็นระบบไฟล์ FUSE ที่แสดงมุมมองที่กำหนดเองของระบบไฟล์พื้นฐานโดยไม่มีค่าใช้จ่ายด้านเวลา Bazel ใช้ sandboxfs เพื่อสร้าง execroot/ ทันทีสำหรับการดำเนินการแต่ละรายการ ซึ่งช่วยหลีกเลี่ยงค่าใช้จ่ายในการออกการเรียกใช้ระบบหลายพันครั้ง โปรดทราบว่า I/O เพิ่มเติมภายใน execroot/ อาจช้าลงเนื่องจากค่าใช้จ่ายของ FUSE
ติดตั้ง sandboxfs
ทำตามขั้นตอนต่อไปนี้เพื่อติดตั้ง sandboxfs และเรียกใช้บิลด์ Bazel ด้วย sandboxfs
ดาวน์โหลด
ดาวน์โหลดและติดตั้ง
sandboxfs เพื่อให้ไบนารี sandboxfs อยู่ใน PATH
เรียกใช้ sandboxfs
- (macOS เท่านั้น) ติดตั้ง OSXFUSE
(macOS เท่านั้น) เรียกใช้
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1คุณจะต้องดำเนินการนี้หลังการติดตั้งและหลังการรีบูตทุกครั้งเพื่อให้แน่ใจว่าบริการระบบหลักของ macOS ทำงานผ่าน sandboxfs
เรียกใช้บิลด์ Bazel ด้วย
--experimental_use_sandboxfsbazel build target --experimental_use_sandboxfs
การแก้ปัญหา
หากเห็น local แทน darwin-sandbox หรือ linux-sandbox เป็นคำอธิบายประกอบสำหรับการดำเนินการที่เรียกใช้ แสดงว่าอาจมีการปิดใช้การทำแซนด์บ็อกซ์ ให้ส่ง --genrule_strategy=sandboxed --spawn_strategy=sandboxed เพื่อเปิดใช้
การแก้ไขข้อบกพร่อง
ทำตามกลยุทธ์ด้านล่างเพื่อแก้ไขข้อบกพร่องของปัญหาเกี่ยวกับการทำแซนด์บ็อกซ์
เนมสเปซที่ปิดใช้งาน
ในบางแพลตฟอร์ม เช่น
Google Kubernetes Engine
โหนดคลัสเตอร์ หรือ Debian เนมสเปซของผู้ใช้จะปิดใช้งานโดยค่าเริ่มต้นเนื่องจาก
ข้อกังวลด้านความปลอดภัย หากไฟล์ /proc/sys/kernel/unprivileged_userns_clone มีอยู่และมีค่าเป็น 0 คุณสามารถเปิดใช้งานเนมสเปซของผู้ใช้ได้โดยเรียกใช้คำสั่งต่อไปนี้
sudo sysctl kernel.unprivileged_userns_clone=1การดำเนินการกฎล้มเหลว
แซนด์บ็อกซ์อาจเรียกใช้กฎไม่สำเร็จเนื่องจากการตั้งค่าระบบ หากเห็นข้อความเช่น namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory ให้ลองปิดใช้งานแซนด์บ็อกซ์ด้วย --strategy=Genrule=local สำหรับกฎการสร้าง และ --spawn_strategy=local สำหรับกฎอื่นๆ
การแก้ไขข้อบกพร่องโดยละเอียดสำหรับการล้มเหลวของบิลด์
หากบิลด์ล้มเหลว ให้ใช้ --verbose_failures และ --sandbox_debug เพื่อให้ Bazel แสดงคำสั่งที่เรียกใช้เมื่อบิลด์ล้มเหลว รวมถึงส่วนที่ตั้งค่าแซนด์บ็อกซ์
ข้อความแสดงข้อผิดพลาดตัวอย่าง
ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:
Sandboxed execution failed, which may be legitimate (such as a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned
namespace-sandbox failed: error executing command
(cd /so&&me/path \
exec env - \
LANG=en_US \
PATH=/some/path/bin:/bin:/usr/bin \
PYTHONPATH=/usr/local/some/path \
/some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
/some/path/to/your/some-compiler --some-params some-target)
ตอนนี้คุณสามารถตรวจสอบไดเรกทอรีแซนด์บ็อกซ์ที่สร้างขึ้นและดูไฟล์ที่ Bazel สร้างขึ้น รวมถึงเรียกใช้คำสั่งอีกครั้งเพื่อดูลักษณะการทำงาน
โปรดทราบว่า Bazel จะไม่ลบไดเรกทอรีแซนด์บ็อกซ์เมื่อคุณใช้ --sandbox_debug คุณควรปิดใช้ --sandbox_debug เว้นแต่จะกำลังแก้ไขข้อบกพร่องอยู่ เนื่องจากแฟล็กนี้จะทำให้ดิสก์เต็มเมื่อเวลาผ่านไป