บทความนี้กล่าวถึงแซนด์บ็อกซ์ใน Bazel และการแก้ไขข้อบกพร่องในสภาพแวดล้อมแซนด์บ็อกซ์
แซนด์บ็อกซ์เป็นกลยุทธ์การจำกัดสิทธิ์ที่แยกกระบวนการออกจากกันหรือแยกออกจากทรัพยากรในระบบ สำหรับ 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 บิลด์ที่ใช้แซนด์บ็อกซ์มักจะช้าลงไม่เกิน 2-3% การตั้งค่า
--reuse_sandbox_directoriesจะช่วยลดค่าใช้จ่ายในการตั้งค่าและล้างข้อมูลได้แซนด์บ็อกซ์จะปิดใช้แคชที่เครื่องมืออาจมีอยู่ คุณสามารถ ลดปัญหานี้ได้โดยใช้ เวิร์กเกอร์แบบถาวร แต่ จะทำให้การรับประกันแซนด์บ็อกซ์มีความเข้มงวดน้อยลง
เวิร์กเกอร์แบบมัลติเพล็กซ์ต้องมีการรองรับเวิร์กเกอร์อย่างชัดแจ้ง จึงจะใช้แซนด์บ็อกซ์ได้ เวิร์กเกอร์ที่ไม่รองรับแซนด์บ็อกซ์แบบมัลติเพล็กซ์จะทำงานเป็นเวิร์กเกอร์แบบซิงเกิลเพล็กซ์ภายใต้การดำเนินการแบบไดนามิก ซึ่งอาจทำให้ใช้หน่วยความจำเพิ่มขึ้น
การแก้ไขข้อบกพร่อง
ทำตามกลยุทธ์ด้านล่างเพื่อแก้ไขข้อบกพร่องของปัญหาเกี่ยวกับแซนด์บ็อกซ์
เนมสเปซที่ปิดใช้งาน
ในบางแพลตฟอร์ม เช่น
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 /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 เว้นแต่จะกำลังแก้ไขข้อบกพร่องอยู่ เนื่องจากแฟล็กนี้จะทำให้ดิสก์เต็มเมื่อเวลาผ่านไป