แซนด์บ็อกซ์

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

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

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

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

แซนด์บ็อกซ์ไม่ได้ซ่อนสภาพแวดล้อมของโฮสต์ไม่ว่าในลักษณะใดก็ตาม กระบวนการสามารถเข้าถึง ไฟล์ทั้งหมดในระบบไฟล์ได้อย่างอิสระ อย่างไรก็ตาม ในแพลตฟอร์มที่รองรับเนมสเปซ กระบวนการจะแก้ไขไฟล์นอกไดเรกทอรีการทำงานไม่ได้ วิธีนี้ช่วยให้กราฟของบิลด์ไม่มีทรัพยากร Dependency ที่ซ่อนอยู่ซึ่งอาจส่งผลต่อความสามารถในการทำซ้ำของบิลด์

กล่าวอย่างเจาะจงก็คือ Bazel จะสร้างไดเรกทอรี execroot/ สำหรับการดำเนินการแต่ละรายการ ซึ่งทำหน้าที่เป็นไดเรกทอรีงานของการดำเนินการ ณ เวลาดำเนินการ execroot/ มีไฟล์อินพุตทั้งหมดสำหรับการทำงาน และทำหน้าที่เป็นคอนเทนเนอร์สำหรับ เอาต์พุตที่สร้างขึ้น จากนั้น Bazel ใช้เทคนิคที่ระบบปฏิบัติการมีให้ ซึ่งก็คือคอนเทนเนอร์ใน Linux และ sandbox-exec ใน macOS เพื่อจำกัดการดำเนินการภายใน execroot/

เหตุผลที่ควรใช้แซนด์บ็อกซ์

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

  • การนำรายการแคชมาใช้ซ้ำที่ไม่ถูกต้องจะสร้างปัญหาระหว่างการแคชระยะไกล รายการแคชที่ไม่ดีในแคชที่แชร์จะส่งผลต่อนักพัฒนาซอฟต์แวร์ทุกคนในโปรเจ็กต์ และการล้างข้อมูลแคชระยะไกลทั้งหมดก็ไม่ใช่วิธีแก้ปัญหาที่สามารถทำได้

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

กลยุทธ์แซนด์บ็อกซ์ที่ควรใช้

คุณเลือกประเภทแซนด์บ็อกซ์ที่ต้องการใช้ (หากมี) ได้ด้วยแฟล็กกลยุทธ์ การใช้กลยุทธ์ sandboxed ทำให้ Bazel เลือกใช้แซนด์บ็อกซ์อย่างใดอย่างหนึ่งตามรายการด้านล่าง โดยแนะนำให้ใช้แซนด์บ็อกซ์เฉพาะระบบปฏิบัติการกับเวอร์ชันทั่วไปที่ไม่ค่อยซับซ้อน ผู้ปฏิบัติงานถาวรจะทำงานในแซนด์บ็อกซ์ทั่วไปหากคุณผ่าน Flag --worker_sandboxing

กลยุทธ์ local (หรือที่เรียกว่า standalone) ไม่ได้ใช้แซนด์บ็อกซ์ใดๆ ทั้งสิ้น โดยจะเรียกใช้บรรทัดคำสั่งของการดำเนินการโดยตั้งค่าไดเรกทอรีการทำงานเป็นผู้บริหารพื้นที่ทำงาน

processwrapper-sandbox เป็นกลยุทธ์แซนด์บ็อกซ์ที่ไม่ต้องอาศัยฟีเจอร์ "ขั้นสูง" แต่ควรใช้งานกับระบบ POSIX ได้ทั้งหมดตั้งแต่แกะกล่อง โดยจะสร้างไดเรกทอรีแซนด์บ็อกซ์ซึ่งประกอบด้วยลิงก์สัญลักษณ์ที่ชี้ไปยังไฟล์ต้นฉบับต้นฉบับ เรียกใช้บรรทัดคำสั่งของการทำงานที่ตั้งค่าไดเรกทอรีที่ใช้งานอยู่ไปยังไดเรกทอรีนี้แทนที่จะเป็น execroot จากนั้นย้ายอาร์ติแฟกต์เอาต์พุตที่รู้จัก ออกจากแซนด์บ็อกซ์ไปยังไฟล์ปฏิบัติการและลบแซนด์บ็อกซ์ เพื่อป้องกันไม่ให้การดำเนินการใช้ไฟล์อินพุตที่ไม่ได้ประกาศโดยไม่ตั้งใจ และไม่ให้ไฟล์เอาต์พุตที่ไม่รู้จักฝังไว้ในไฟล์ปฏิบัติการ

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

Sandboxfs

sandboxfs เป็นระบบไฟล์ FUSE ที่แสดงมุมมองที่กำหนดเองของระบบไฟล์พื้นฐานโดยไม่มีค่าปรับเวลา Bazel ใช้ sandboxfs เพื่อสร้าง execroot/ สำหรับการดำเนินการแต่ละรายการทันที ทำให้ไม่ต้องเสียค่าใช้จ่ายในการออกการเรียกใช้ระบบหลายพันครั้ง โปรดทราบว่า I/O เพิ่มเติมภายใน execroot/ อาจช้าลงเนื่องจากโอเวอร์เฮดของ FUSE

ติดตั้ง sandboxfs

ทําตามขั้นตอนต่อไปนี้เพื่อติดตั้ง sandboxfs และสร้าง Bazel ด้วย

ดาวน์โหลด

ดาวน์โหลดและติดตั้ง sandboxfs เพื่อให้ไบนารี sandboxfs อยู่ใน PATH ของคุณ

เรียกใช้ sandboxfs

  1. (macOS เท่านั้น) ติดตั้ง OSXFUSE
  2. (macOS เท่านั้น) เรียกใช้:

    sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
    

    คุณจะต้องดำเนินการนี้หลังการติดตั้งและหลังการรีบูตทุกครั้งเพื่อให้แน่ใจว่าบริการหลักของระบบ macOS ทำงานผ่าน sandboxf

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