แซนด์บ็อกซ์

รายงานปัญหา ดูแหล่งที่มา ตอนกลางคืน · 7.4 ที่ใช้เวลาเพียง 2 นาที 7.3 · 7.2 · 7.1 · 7.0 · 6.5

บทความนี้กล่าวถึงแซนด์บ็อกซ์ใน 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

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

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

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

  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

เรียกใช้กฎไม่สำเร็จ

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