แซนด์บ็อกซ์

รายงานปัญหา ดูแหล่งที่มา

บทความนี้กล่าวถึงแซนด์บ็อกซ์ใน Bazel และการแก้ไขข้อบกพร่องในสภาพแวดล้อมแซนด์บ็อกซ์

แซนด์บ็อกซ์เป็นกลยุทธ์การจำกัดสิทธิ์ที่แยกกระบวนการออกจากกันหรือออกจากทรัพยากรในระบบ สำหรับ Bazel นี่จะเป็นการจำกัดการเข้าถึงระบบไฟล์

แซนด์บ็อกซ์ระบบไฟล์ของ Bazel เรียกใช้กระบวนการในไดเรกทอรีที่ใช้งานได้ซึ่งมีเฉพาะอินพุตที่รู้จักเท่านั้น ซึ่งทำให้คอมไพเลอร์และเครื่องมืออื่นๆ ไม่เห็นไฟล์ต้นฉบับที่ไม่ควรเข้าถึง เว้นแต่พวกเขารู้เส้นทางสัมบูรณ์ของมัน

แซนด์บ็อกซ์ไม่ได้ซ่อนสภาพแวดล้อมโฮสต์ไม่ว่าในลักษณะใดก็ตาม กระบวนการสามารถเข้าถึงไฟล์ทั้งหมด ในระบบไฟล์ได้อย่างอิสระ อย่างไรก็ตาม ในแพลตฟอร์มที่รองรับเนมสเปซของผู้ใช้ กระบวนการจะแก้ไขไฟล์นอกไดเรกทอรีที่ทำงานไม่ได้ วิธีนี้ช่วยให้กราฟบิลด์ไม่มีทรัพยากร 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 เช่นเดียวกับที่ Docker ทำในส่วนเบื้องหลัง โดยใช้เนมสเปซของ Linux (User, Mount, PID, Network และ IPCเนมสเปซ) เพื่อแยกการดำเนินการออกจากโฮสต์ กล่าวคือ จะทำให้ระบบไฟล์เป็นแบบอ่านอย่างเดียวทั้งหมด ยกเว้นไดเรกทอรีแซนด์บ็อกซ์ ดังนั้น การดำเนินการดังกล่าวจะไม่สามารถแก้ไขได้โดยไม่ได้ตั้งใจในระบบไฟล์ของโฮสต์ ซึ่งจะช่วยป้องกันสถานการณ์อย่างเช่น การทดสอบข้อบกพร่องโดยไม่ตั้งใจ RM -rf'ไดเรกทอรี $HOME ของคุณ คุณยังสามารถป้องกันการดำเนินการดังกล่าว ไม่ให้เข้าถึงเครือข่ายได้ด้วย linux-sandbox ใช้เนมสเปซ PID เพื่อป้องกันไม่ให้การดำเนินการมองเห็นกระบวนการอื่นๆ และยุติกระบวนการทั้งหมดอย่างน่าเชื่อถือ (รวมถึง Daemon ที่การดำเนินการนั้นสร้าง) ในตอนท้าย

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 ที่มีการดำเนินการแบบไดนามิก ซึ่งอาจต้องใช้หน่วยความจำเพิ่มขึ้น

การแก้ไขข้อบกพร่อง

ทำตามกลยุทธ์ด้านล่างเพื่อแก้ไขข้อบกพร่องของแซนด์บ็อกซ์

เนมสเปซที่ปิดใช้งาน

ในบางแพลตฟอร์ม เช่น โหนดคลัสเตอร์ 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 สำหรับกฎ Gen และ --spawn_strategy=local สำหรับกฎอื่นๆ

การแก้ไขข้อบกพร่องโดยละเอียดสำหรับความล้มเหลวของบิลด์

หากการสร้างของคุณล้มเหลว ให้ใช้ --verbose_failures และ --sandbox_debug เพื่อทำให้ Blazel แสดงคำสั่งเดียวกับที่เรียกใช้เมื่อการสร้างของคุณล้มเหลว รวมถึงส่วนที่ใช้ตั้งค่าแซนด์บ็อกซ์ด้วย

ตัวอย่างข้อความแสดงข้อผิดพลาด

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 เพราะจะทำให้ดิสก์เต็มเมื่อเวลาผ่านไป เว้นแต่คุณจะกำลังแก้ไขข้อบกพร่องอยู่