บทความนี้กล่าวถึงแซนด์บ็อกซ์ใน Bazel, การติดตั้ง sandboxfs
และการแก้ไขข้อบกพร่องในสภาพแวดล้อมแซนด์บ็อกซ์
แซนด์บ็อกซ์เป็นกลยุทธ์จำกัดสิทธิ์ที่แยกกระบวนการออกจากกันหรือออกจากทรัพยากรในระบบ สำหรับ Bazel นี่หมายถึงการจำกัดการเข้าถึงระบบไฟล์
แซนด์บ็อกซ์ระบบไฟล์ของ Bazel เรียกใช้กระบวนการในไดเรกทอรีการทำงานที่มีเฉพาะอินพุตที่รู้จักเท่านั้น ซึ่งทำให้คอมไพเลอร์และเครื่องมืออื่นๆ ไม่เห็นไฟล์ต้นฉบับที่ไม่ควรเข้าถึง เว้นแต่ผู้ใช้จะรู้เส้นทางสัมบูรณ์ไปยังไฟล์
แซนด์บ็อกซ์จะไม่ซ่อนสภาพแวดล้อมของโฮสต์ไม่ว่าในลักษณะใดก็ตาม กระบวนการสามารถเข้าถึง ไฟล์ทั้งหมดในระบบไฟล์ได้อย่างอิสระ อย่างไรก็ตาม ในแพลตฟอร์มที่รองรับ User Namespace กระบวนการจะแก้ไขไฟล์นอกไดเรกทอรีการทำงานไม่ได้ วิธีนี้ช่วยให้กราฟบิลด์ไม่มีทรัพยากร Dependency ที่ซ่อนอยู่ซึ่งอาจส่งผลกระทบต่อความสามารถในการทำซ้ำของบิลด์
กล่าวอย่างเจาะจงคือ Bazel จะสร้างไดเรกทอรี execroot/
สําหรับการดําเนินการแต่ละรายการ ซึ่งทําหน้าที่เป็นไดเรกทอรีงานของการดําเนินการ ณ เวลาที่ดําเนินการ execroot/
มีไฟล์อินพุตทั้งหมดไปยังการดำเนินการและทำหน้าที่เป็นคอนเทนเนอร์สำหรับเอาต์พุตที่สร้างขึ้น จากนั้น Bazel จะใช้เทคนิคที่ได้รับจากระบบปฏิบัติการ คอนเทนเนอร์บน Linux และ sandbox-exec
ใน macOS เพื่อจำกัดการดำเนินการภายใน execroot/
เหตุผลในการใช้แซนด์บ็อกซ์
หากไม่มีการทำแซนด์บ็อกซ์การดำเนินการ Bazel จะไม่ทราบว่าเครื่องมือหนึ่งใช้ไฟล์อินพุตที่ไม่ได้ประกาศหรือไม่ (ไฟล์ที่ไม่ได้ระบุไว้อย่างชัดเจนในทรัพยากร Dependency ของการดำเนินการ) เมื่อไฟล์อินพุตที่ไม่ได้ประกาศไฟล์หนึ่งมีการเปลี่ยนแปลง Bazel ยังคงเชื่อว่าบิลด์นั้นอัปเดตแล้ว และจะไม่สร้างการดำเนินการอีกครั้ง ซึ่งอาจส่งผลให้บิลด์เพิ่มขึ้นอย่างไม่ถูกต้อง
การใช้รายการแคชซ้ำอย่างไม่ถูกต้องจะสร้างปัญหาระหว่างการแคชจากระยะไกล รายการแคชที่ไม่ดีในแคชที่ใช้ร่วมกันจะส่งผลต่อนักพัฒนาซอฟต์แวร์ทุกคนในโปรเจ็กต์ และการล้างแคชระยะไกลทั้งหมดไม่ใช่วิธีแก้ปัญหาที่ทำได้
แซนด์บ็อกซ์จะเลียนแบบลักษณะการทำงานของการดำเนินการระยะไกล หากบิลด์ทำงานได้ดีกับแซนด์บ็อกซ์ ก็มีแนวโน้มที่จะทำงานร่วมกับการดำเนินการระยะไกลด้วย เมื่อการดำเนินการระยะไกลอัปโหลดไฟล์ที่จำเป็นทั้งหมด (รวมถึงเครื่องมือในเครื่อง) คุณจะลดค่าใช้จ่ายในการบำรุงรักษาสำหรับคลัสเตอร์คอมไพล์ได้อย่างมากเมื่อเทียบกับการติดตั้งเครื่องมือบนทุกเครื่องในคลัสเตอร์ทุกครั้งที่คุณต้องการลองใช้คอมไพเลอร์ใหม่หรือทำการเปลี่ยนแปลงเครื่องมือที่มีอยู่
กลยุทธ์แซนด์บ็อกซ์ที่ควรใช้
คุณเลือกประเภทแซนด์บ็อกซ์ที่จะใช้ (หากมี) ได้ด้วยแฟล็กกลยุทธ์ การใช้กลยุทธ์ sandboxed
ทำให้ Bazel เลือกการใช้งานแซนด์บ็อกซ์รายการใดรายการหนึ่งที่แสดงด้านล่าง โดยเลือกใช้แซนด์บ็อกซ์สำหรับระบบปฏิบัติการที่เฉพาะเจาะจงมากกว่าแซนด์บ็อกซ์ทั่วไปที่ไม่สม่ำเสมอ
ผู้ปฏิบัติงานถาวรจะทำงานในแซนด์บ็อกซ์ทั่วไปหากคุณผ่านแฟล็ก --worker_sandboxing
กลยุทธ์ local
(หรือ standalone
) ไม่ได้ทำแซนด์บ็อกซ์ประเภทใดๆ
ซึ่งจะดำเนินการเพียงบรรทัดคำสั่งของการดำเนินการโดยตั้งค่าไดเรกทอรีการทำงานไว้เป็นไฟล์ผู้บริหารของพื้นที่ทำงาน
processwrapper-sandbox
เป็นกลยุทธ์แซนด์บ็อกซ์ที่ไม่จำเป็นต้องใช้ฟีเจอร์ "ขั้นสูง" และควรใช้งานได้กับระบบ POSIX ทั้งหมดตั้งแต่แรก ซึ่งจะสร้างไดเรกทอรีแซนด์บ็อกซ์ที่ประกอบด้วยลิงก์สัญลักษณ์ที่ชี้ไปยังไฟล์ต้นฉบับ เรียกใช้บรรทัดคำสั่งของการดำเนินการโดยตั้งค่าไดเรกทอรีการทำงานไปยังไดเรกทอรีนี้แทนไฟล์ปฏิบัติการ จากนั้นย้ายอาร์ติแฟกต์เอาต์พุตที่รู้จักออกจากแซนด์บ็อกซ์ลงในไฟล์ execroot และลบแซนด์บ็อกซ์ วิธีนี้จะช่วยป้องกันไม่ให้การดำเนินการใช้ไฟล์อินพุตที่ไม่ได้ประกาศโดยไม่ได้ตั้งใจและไม่ทำให้ไฟล์เอาต์พุตที่ไม่รู้จักเสียหายจากผู้บริหารโดยไม่ได้ตั้งใจ
linux-sandbox
ได้ก้าวไปอีกขั้นและต่อยอดมาจาก processwrapper-sandbox
โดยจะใช้เนมสเปซของ Linux (User, Mount, PID, Network และ IPC Namespace) เพื่อแยกการดำเนินการออกจากโฮสต์ เช่นเดียวกับที่ Docker ทำในส่วนขั้นสูง กล่าวคือ จะทำให้ทั้งระบบไฟล์เป็นแบบอ่านอย่างเดียว ยกเว้นไดเรกทอรีแซนด์บ็อกซ์ ดังนั้นการดำเนินการนี้จะไม่สามารถแก้ไขได้โดยไม่ตั้งใจในระบบไฟล์ของโฮสต์ ซึ่งเป็นการป้องกันสถานการณ์ต่างๆ เช่น การทดสอบข้อบกพร่องโดยไม่ได้ตั้งใจ
-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 บิลด์ที่แซนด์บ็อกซ์มักช้ากว่า 2-3 เปอร์เซ็นต์ การตั้งค่า
--reuse_sandbox_directories
จะช่วยลดค่าใช้จ่ายในการตั้งค่าและการหยุดให้บริการได้แซนด์บ็อกซ์จะปิดใช้แคชที่เครื่องมืออาจมีได้อย่างมีประสิทธิภาพ คุณลดความเสี่ยงนี้ได้โดยใช้ผู้ปฏิบัติงานถาวร ซึ่งมีต้นทุนสำหรับการรับประกันแซนด์บ็อกซ์ที่ไม่รัดกุม
ผู้ปฏิบัติงาน Multiplex ต้องใช้แซนด์บ็อกซ์กับการรองรับผู้ปฏิบัติงานอย่างชัดแจ้ง ผู้ปฏิบัติงานที่ไม่รองรับแซนด์บ็อกซ์แบบมัลติเพล็กซ์จะทำงานเป็นผู้ปฏิบัติงาน Singleplex ภายใต้การดำเนินการแบบไดนามิก ซึ่งจะทำให้ต้องใช้หน่วยความจำมากขึ้น
Sandboxf
sandboxfs
เป็นระบบไฟล์ FUSE ที่แสดงมุมมองที่กำหนดเองของระบบไฟล์ที่เกี่ยวข้อง โดยไม่มีการปรับเวลา Bazel ใช้ sandboxfs
เพื่อสร้าง execroot/
ทันทีสำหรับการดำเนินการแต่ละรายการ ซึ่งจะช่วยให้ไม่ต้องเสียค่าใช้จ่ายในการสร้างการเรียกใช้ระบบนับพันรายการ โปรดทราบว่า I/O เพิ่มเติมภายใน execroot/
อาจช้ากว่า
เนื่องจากโอเวอร์เฮดของ FUSE
ติดตั้ง sandboxf
ใช้ขั้นตอนต่อไปนี้เพื่อติดตั้ง sandboxfs
และสร้างบิลด์ Bazel ด้วย
ดาวน์โหลด
ดาวน์โหลดและติดตั้ง
sandboxfs
เพื่อให้ไบนารี sandboxfs
อยู่ใน PATH
เรียกใช้ sandboxfs
- (macOS เท่านั้น) Install OSXFUSE
(macOS เท่านั้น) เรียกใช้:
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
คุณจะต้องทำขั้นตอนนี้หลังจากติดตั้งและหลังจากรีบูตทุกครั้งเพื่อให้แน่ใจว่าบริการหลักของระบบ macOS จะทำงานผ่าน sandboxf
เรียกใช้บิลด์ Bazel ด้วย
--experimental_use_sandboxfs
bazel 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
เพื่อทำให้ Bayl แสดงคำสั่งที่เรียกใช้เมื่อบิลด์ล้มเหลว รวมถึงส่วนที่ตั้งค่าไว้แซนด์บ็อกซ์ด้วย
ตัวอย่างข้อความแสดงข้อผิดพลาด
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 /some/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
หากไม่ได้ตั้งใจแก้ไขข้อบกพร่องอยู่เลย เนื่องจากจะทำให้ดิสก์เต็มเมื่อเวลาผ่านไป