บทความนี้กล่าวถึงแซนด์บ็อกซ์ใน Bazel, การติดตั้ง sandboxfs
และการแก้ไขข้อบกพร่อง
สภาพแวดล้อมแซนด์บ็อกซ์ของคุณ
แซนด์บ็อกซ์เป็นกลยุทธ์การจํากัดสิทธิ์ที่แยกกระบวนการออกจากกันหรือแยกออกจากทรัพยากรในระบบ สำหรับ Bazel นี่หมายถึงการจำกัดไฟล์ การเข้าถึงระบบ
แซนด์บ็อกซ์ระบบไฟล์ของ Bazel เรียกใช้กระบวนการในไดเรกทอรีที่ทำงานซึ่ง มีอินพุตที่รู้จักซึ่งคอมไพเลอร์และเครื่องมืออื่นๆ จะไม่เห็นแหล่งที่มา ไฟล์ที่ผู้ใช้ไม่ควรเข้าถึง เว้นแต่จะทราบเส้นทางที่แน่นอนที่เข้าถึง
Sandboxing ไม่ได้ซ่อนสภาพแวดล้อมของโฮสต์ไม่ว่าในทางใดก็ตาม กระบวนการเข้าถึงไฟล์ทั้งหมดในระบบไฟล์ได้อย่างอิสระ อย่างไรก็ตาม บนแพลตฟอร์มที่รองรับผู้ใช้ เนมสเปซ กระบวนการจะแก้ไขไฟล์นอกไดเรกทอรีที่ใช้งานอยู่ไม่ได้ ซึ่งทำให้มั่นใจได้ว่ากราฟบิลด์จะไม่มีทรัพยากรภายนอกที่ซ่อนอยู่ซึ่งอาจส่งผลต่อความสามารถในการสร้างบิลด์ซ้ำ
กล่าวอย่างเจาะจงคือ Bazel จะสร้างไดเรกทอรี execroot/
สำหรับการดำเนินการแต่ละรายการ ซึ่งทำหน้าที่เป็นไดเรกทอรีทํางานของการดำเนินการ ณ เวลาเรียกใช้ execroot/
เก็บไฟล์อินพุตสำหรับการดำเนินการทั้งหมด และทำหน้าที่เป็นคอนเทนเนอร์สำหรับ
ที่สร้างขึ้น จากนั้น Bazel ใช้เทคนิคที่ระบบปฏิบัติการมีให้
คอนเทนเนอร์บน Linux และ sandbox-exec
ใน macOS เพื่อจำกัดการดำเนินการภายใน
execroot/
เหตุผลในการใช้แซนด์บ็อกซ์
หากไม่มีการดำเนินการแซนด์บ็อกซ์ Bazel จะไม่ทราบหากเครื่องมือใช้เครื่องมือ ไฟล์อินพุต (ไฟล์ที่ไม่ได้แสดงไว้อย่างชัดเจนในทรัพยากร Dependency ของ การดำเนินการ) เมื่อไฟล์อินพุตที่ไม่มีการประกาศไฟล์ใดไฟล์หนึ่งมีการเปลี่ยนแปลง Bazel จะยังคงเชื่อว่าบิลด์เป็นเวอร์ชันล่าสุดและจะไม่สร้างการดำเนินการอีกครั้ง สิ่งนี้สามารถ ส่งผลให้เกิดบิลด์ที่เพิ่มขึ้นที่ไม่ถูกต้อง
การนำรายการแคชมาใช้ซ้ำที่ไม่ถูกต้องจะสร้างปัญหาระหว่างการแคชระยะไกล รายการแคชที่ไม่ถูกต้องในแคชที่แชร์จะส่งผลต่อนักพัฒนาแอปทุกคนในโปรเจ็กต์ และการล้างแคชระยะไกลทั้งหมดไม่ใช่วิธีแก้ปัญหาที่ทำได้จริง
Sandboxing จะเลียนแบบลักษณะการทํางานของการดำเนินการจากระยะไกล หากบิลด์ทํางานได้ดีกับ Sandboxing ก็น่าจะทํางานกับการดำเนินการจากระยะไกลด้วย การทำให้การดําเนินการจากระยะไกลอัปโหลดไฟล์ที่จําเป็นทั้งหมด (รวมถึงเครื่องมือในเครื่อง) จะช่วยให้คุณลดค่าใช้จ่ายในการบำรุงรักษาคลัสเตอร์การคอมไพล์ได้อย่างมากเมื่อเทียบกับการต้องติดตั้งเครื่องมือในเครื่องทุกเครื่องในคลัสเตอร์ทุกครั้งที่ต้องการลองใช้คอมไพเลอร์ใหม่หรือทําการเปลี่ยนแปลงเครื่องมือที่มีอยู่
กลยุทธ์แซนด์บ็อกซ์ที่ควรใช้
คุณสามารถเลือกได้ว่าจะใช้แซนด์บ็อกซ์ประเภทใด (หากมี) ด้วย
แฟล็กกลยุทธ์ การใช้ sandboxed
ทำให้ Bazel เลือกใช้
แซนด์บ็อกซ์ตามรายการด้านล่างนี้
เลือกใช้แซนด์บ็อกซ์เฉพาะระบบปฏิบัติการมากกว่าแซนด์บ็อกซ์ที่มีคุณลักษณะทั่วไปน้อยกว่า
Worker แบบถาวรจะทำงานในแซนด์บ็อกซ์ทั่วไปหากคุณส่งผ่าน Flag --worker_sandboxing
กลยุทธ์ local
(หรือที่เรียกว่า standalone
) จะไม่ใช้แซนด์บ็อกซ์ประเภทใดๆ
การดำเนินการนี้จะเรียกใช้บรรทัดคำสั่งของการดำเนินการโดยตั้งค่าไดเรกทอรีที่ทำงานเป็น execroot ของพื้นที่ทำงาน
processwrapper-sandbox
เป็นกลยุทธ์แซนด์บ็อกซ์ที่
"ขั้นสูง" ควรใช้งานกับระบบ POSIX ได้ตั้งแต่แกะกล่อง โดยจะสร้างไดเรกทอรีแซนด์บ็อกซ์ที่ประกอบด้วยลิงก์สัญลักษณ์ซึ่งชี้ไปยังไฟล์ต้นฉบับ เรียกใช้บรรทัดคำสั่งของการดำเนินการโดยตั้งค่าไดเรกทอรีที่ทำงานเป็นไดเรกทอรีนี้แทน execroot จากนั้นย้ายอาร์ติแฟกต์เอาต์พุตที่รู้จักออกจากแซนด์บ็อกซ์ไปยัง execroot และลบแซนด์บ็อกซ์ ซึ่งจะช่วยป้องกันไม่ให้การดำเนินการใช้ไฟล์อินพุตที่ไม่ได้ประกาศโดยไม่ตั้งใจ และไม่ให้ไฟล์เอาต์พุตที่ไม่รู้จักกระจายอยู่ใน execroot
linux-sandbox
ก้าวไปอีกขั้นและต่อยอดมาจาก
processwrapper-sandbox
โดย Docker จะใช้การทำงานขั้นสูง
เนมสเปซของ Linux (เนมสเปซผู้ใช้, ต่อเชื่อม, PID, เครือข่าย และ IPC) เพื่อแยก
จากโฮสต์ กล่าวคือ จะทำให้ทั้งระบบไฟล์เป็นแบบอ่านอย่างเดียว ยกเว้นไดเรกทอรีแซนด์บ็อกซ์ เพื่อให้การดำเนินการดังกล่าวแก้ไขข้อมูลในระบบไฟล์ของโฮสต์โดยไม่ตั้งใจไม่ได้ เพื่อป้องกันสถานการณ์ เช่น การทดสอบข้อบกพร่องโดยไม่ตั้งใจ
-กำลังเปิดไดเรกทอรี $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
สามารถ ลดต้นทุนในการตั้งค่าและการทำลายSandboxing จะปิดใช้แคชทั้งหมดที่เครื่องมืออาจมีได้อย่างมีประสิทธิภาพ คุณสามารถ ลดปัญหานี้ด้วยการใช้ผู้ปฏิบัติงานถาวร ต้นทุนของการรับประกันแซนด์บ็อกซ์ที่มีประสิทธิภาพน้อยกว่า
ผู้ปฏิบัติงานแบบหลายรายการต้องได้รับการรองรับผู้ปฏิบัติงานอย่างชัดเจนจึงจะใช้แซนด์บ็อกซ์ได้ ผู้ปฏิบัติงานที่ไม่รองรับการทำแซนด์บ็อกซ์แบบมัลติเพล็กซ์จะเรียกใช้ในฐานะ Singleplex อยู่ระหว่างการดำเนินการแบบไดนามิก ซึ่งอาจทำให้ต้องใช้หน่วยความจำเพิ่มเติม
Sandboxfs
sandboxfs
เป็นระบบไฟล์ FUSE ที่แสดงมุมมองของระบบไฟล์ที่อยู่เบื้องหลังแบบกำหนดเองโดยไม่เสียเวลา Bazel ใช้ sandboxfs
เพื่อสร้าง execroot/
ทันทีสําหรับการดําเนินการแต่ละรายการ ซึ่งจะช่วยประหยัดค่าใช้จ่ายในการเรียกใช้ระบบหลายพันครั้ง โปรดทราบว่า I/O เพิ่มเติมภายใน execroot/
อาจ
ช้าลงเนื่องจากโอเวอร์เฮดของ FUSE
ติดตั้ง sandboxfs
ใช้ขั้นตอนต่อไปนี้เพื่อติดตั้ง sandboxfs
และสร้าง Bazel ด้วย
ดังนี้
ดาวน์โหลด
ดาวน์โหลดและติดตั้ง
sandboxfs
เพื่อให้ไบนารี sandboxfs
ลงท้ายด้วย PATH
เรียกใช้ sandboxfs
- (macOS เท่านั้น) ติดตั้ง OSXFUSE
(macOS เท่านั้น) เรียกใช้
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
คุณจะต้องดำเนินการนี้หลังจากการติดตั้งและหลังจากรีบูตทุกครั้งเพื่อให้บริการระบบหลักของ macOS ทำงานผ่าน sandboxfs ได้
เรียกใช้บิลด์ 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
เรียกใช้กฎไม่สำเร็จ
Sandbox อาจไม่สามารถเรียกใช้กฎได้เนื่องจากการตั้งค่าระบบ หากเห็นข้อความอย่าง namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory
ให้ลองปิดใช้งานแซนด์บ็อกซ์ด้วย --strategy=Genrule=local
สำหรับ genrules และ --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 /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
เว้นแต่คุณจะกำลังแก้ไขข้อบกพร่องอยู่ เนื่องจากจะทําให้ดิสก์เต็มเมื่อเวลาผ่านไป