แซนด์บ็อกซ์

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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

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

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

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

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

เหตุผลในการแซนด์บ็อกซ์

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

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

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

กลยุทธ์แซนด์บ็อกซ์ที่จะใช้

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

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

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

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

ข้อเสียของการใช้แซนด์บ็อกซ์

  • การแซนด์บ็อกซ์ทำให้มีค่าใช้จ่ายในการตั้งค่าและค่าใช้จ่ายในการเลิกใช้งานเพิ่มเติม ค่าใช้จ่ายนี้จะมากน้อยเพียงใด ขึ้นอยู่กับหลายปัจจัย ซึ่งรวมถึงรูปร่างของการสร้างและ ประสิทธิภาพของระบบปฏิบัติการโฮสต์ สำหรับ Linux บิลด์ที่อยู่ในแซนด์บ็อกซ์จะช้ากว่าปกติไม่เกิน ไม่กี่เปอร์เซ็นต์ การตั้งค่า --reuse_sandbox_directories จะช่วยลดต้นทุนในการตั้งค่าและยกเลิกการตั้งค่า

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

  • Multiplex Worker ต้องได้รับการสนับสนุนจาก Worker อย่างชัดเจน จึงจะอยู่ในแซนด์บ็อกซ์ได้ Worker ที่ไม่รองรับแซนด์บ็อกซ์แบบมัลติเพล็กซ์จะทำงานเป็น Worker แบบซิงเกิลเพล็กซ์ภายใต้การดำเนินการแบบไดนามิก ซึ่งอาจใช้หน่วยความจำเพิ่มเติม

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

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

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

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