การแก้ปัญหาการเรียกใช้ Bazel Remote ด้วย Docker Sandbox

รายงานปัญหา ดูซอร์สโค้ด รุ่น Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

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

ฟีเจอร์แซนด์บ็อกซ์ของ Docker จะจำลองข้อจำกัดของการดำเนินการระยะไกล ดังนี้

  • การดำเนินการสร้างจะดำเนินการในคอนเทนเนอร์เครื่องมือทางเทคนิค คุณสามารถใช้คอนเทนเนอร์ชุดเครื่องมือเดียวกันเพื่อเรียกใช้บิลด์ในเครื่องและจากระยะไกลผ่านบริการที่รองรับการดำเนินการระยะไกลในคอนเทนเนอร์ได้

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

  • การดําเนินการแต่ละรายการจะทํางานในคอนเทนเนอร์ใหม่ ระบบจะสร้างคอนเทนเนอร์ใหม่ที่ไม่ซ้ำกันสําหรับการดําเนินการสร้างที่สร้างขึ้นแต่ละรายการ

คุณสามารถแก้ปัญหาเหล่านี้ได้โดยใช้วิธีใดวิธีหนึ่งต่อไปนี้

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

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

ข้อกำหนดเบื้องต้น

ก่อนเริ่มแก้ปัญหา ให้ทำตามขั้นตอนต่อไปนี้หากยังไม่ได้ดำเนินการ

  • ติดตั้ง Docker และกำหนดค่าสิทธิ์ที่จําเป็นในการใช้งาน
  • ติดตั้ง Bazel 0.14.1 ขึ้นไป เวอร์ชันก่อนหน้าไม่รองรับฟีเจอร์ Docker Sandbox
  • เพิ่มที่เก็บ bazel-toolchains ที่ปักหมุดไว้เป็นเวอร์ชันล่าสุดของรุ่นที่เผยแพร่ลงในไฟล์ WORKSPACE ของบิลด์ ตามที่อธิบายไว้ที่นี่
  • เพิ่ม Flag ลงในไฟล์ .bazelrc เพื่อเปิดใช้ฟีเจอร์ สร้างไฟล์ในไดเรกทอรีรูทของโปรเจ็กต์ Bazel หากยังไม่มี แฟล็กด้านล่างเป็นเพียงตัวอย่างข้อมูลอ้างอิง โปรดดูไฟล์ .bazelrc ล่าสุดในรีโพซิทอรี bazel-toolchains และคัดลอกค่าของ Flag ที่กําหนดไว้สําหรับการกําหนดค่า docker-sandbox
# Docker Sandbox Mode
build:docker-sandbox --host_javabase=<...>
build:docker-sandbox --javabase=<...>
build:docker-sandbox --crosstool_top=<...>
build:docker-sandbox --experimental_docker_image=<...>
build:docker-sandbox --spawn_strategy=docker --strategy=Javac=docker --genrule_strategy=docker
build:docker-sandbox --define=EXECUTOR=remote
build:docker-sandbox --experimental_docker_verbose
build:docker-sandbox --experimental_enable_docker_sandbox

หากกฎต้องใช้เครื่องมือเพิ่มเติม ให้ทําดังนี้

  1. สร้างคอนเทนเนอร์ Docker ที่กำหนดเองโดยการติดตั้งเครื่องมือโดยใช้ Dockerfile และสร้างอิมเมจในเครื่อง

  2. แทนที่ค่าของ Flag --experimental_docker_image ด้านบนด้วยชื่อของภาพคอนเทนเนอร์ที่กำหนดเอง

การแก้ปัญหาแบบดั้งเดิม

วิธีนี้จะเรียกใช้ Bazel และการดำเนินการทั้งหมดของการสร้างในเครื่องโดยตรง และเป็นวิธีที่เชื่อถือได้ในการยืนยันว่าการสร้างจะสำเร็จหรือไม่เมื่อดำเนินการจากระยะไกล

อย่างไรก็ตาม เมื่อใช้วิธีนี้ เครื่องมือ ไบนารี และข้อมูลในเครื่องอาจรั่วไหลเข้าสู่บิลด์ โดยเฉพาะหากใช้กฎ WORKSPACE สไตล์การกําหนดค่า การเปิดเผยข้อมูลดังกล่าวจะทำให้เกิดปัญหาในการเรียกใช้จากระยะไกล หากต้องการตรวจหา ให้แก้ปัญหาในคอนเทนเนอร์ Docker นอกเหนือจากการแก้ปัญหาโดยตรง

ขั้นตอนที่ 1: เรียกใช้บิลด์

  1. เพิ่ม Flag --config=docker-sandbox ลงในคำสั่ง Bazel ที่เรียกใช้บิลด์ เช่น

    bazel --bazelrc=.bazelrc build --config=docker-sandbox target
  2. เรียกใช้บิลด์และรอให้เสร็จสมบูรณ์ บิลด์จะทำงานช้ากว่าปกติถึง 4 เท่าเนื่องจากฟีเจอร์แซนด์บ็อกซ์ของ Docker

คุณอาจพบข้อผิดพลาดต่อไปนี้

ERROR: 'docker' is an invalid value for docker spawn strategy.

หากใช่ ให้เรียกใช้บิลด์อีกครั้งโดยใช้ Flag --experimental_docker_verbose Flag นี้จะเปิดใช้ข้อความแสดงข้อผิดพลาดแบบละเอียด ข้อผิดพลาดนี้มักเกิดจากการติดตั้ง Docker ที่มีข้อบกพร่องหรือไม่มีสิทธิ์เรียกใช้ภายใต้บัญชีผู้ใช้ปัจจุบัน ดูข้อมูลเพิ่มเติมได้ในเอกสารประกอบของ Docker หากยังพบปัญหาอยู่ ให้ข้ามไปที่การแก้ปัญหาในคอนเทนเนอร์ Docker

ขั้นตอนที่ 2: แก้ไขปัญหาที่ตรวจพบ

ต่อไปนี้คือปัญหาที่พบบ่อยที่สุดและวิธีแก้ปัญหา

  • ไม่มีไฟล์ เครื่องมือ ไบนารี หรือทรัพยากรที่อ้างอิงโดยต้นไม้ runfiles ของ Bazel ยืนยันว่าได้ประกาศอย่างชัดแจ้งเกี่ยวกับทรัพยากรทั้งหมดของเป้าหมายที่ได้รับผลกระทบแล้ว ดูข้อมูลเพิ่มเติมที่หัวข้อการจัดการการพึ่งพาโดยนัย

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

  • การเรียกใช้ไบนารีไม่สำเร็จ กฎการสร้างข้อใดข้อหนึ่งอ้างอิงไบนารีที่เข้ากันไม่ได้กับสภาพแวดล้อมการดําเนินการ (คอนเทนเนอร์ Docker) ดูข้อมูลเพิ่มเติมที่หัวข้อการจัดการไบนารีที่ขึ้นอยู่กับแพลตฟอร์ม หากแก้ปัญหาไม่ได้ โปรดติดต่อขอความช่วยเหลือที่ bazel-discuss@google.com

  • ไฟล์จาก @local-jdk ขาดหายไปหรือทำให้เกิดข้อผิดพลาด ไฟล์ไบนารี Java ในเครื่องของคุณรั่วไหลไปยังบิลด์ในขณะที่ใช้ร่วมกันไม่ได้ ใช้ java_toolchain ในกฎและเป้าหมายแทน @local_jdk โปรดติดต่อ bazel-discuss@google.com หากต้องการความช่วยเหลือเพิ่มเติม

  • ข้อผิดพลาดอื่นๆ โปรดติดต่อ bazel-discuss@google.com เพื่อขอความช่วยเหลือ

การแก้ปัญหาในคอนเทนเนอร์ Docker

เมื่อใช้วิธีการนี้ Bazel จะทำงานภายในคอนเทนเนอร์ Docker โฮสต์ และการดำเนินการสร้างของ Bazel จะทำงานภายในคอนเทนเนอร์เครื่องมือต่างๆ แต่ละรายการที่ฟีเจอร์แซนด์บ็อกซ์ของ Docker สร้างขึ้น Sandbox จะสร้างคอนเทนเนอร์เครื่องมือทางเทคนิคใหม่เอี่ยมสําหรับการดําเนินการบิลด์แต่ละรายการ และจะมีการดำเนินการเพียงรายการเดียวในคอนเทนเนอร์เครื่องมือทางเทคนิคแต่ละรายการ

วิธีนี้ช่วยให้ควบคุมเครื่องมือที่ติดตั้งในสภาพแวดล้อมโฮสต์ได้อย่างละเอียดยิ่งขึ้น การแยกการเรียกใช้บิลด์ออกจากการเรียกใช้การดำเนินการบิลด์และลดเครื่องมือที่ติดตั้งไว้ให้เหลือน้อยที่สุดจะช่วยให้คุณยืนยันได้ว่าบิลด์ของคุณมีการพึ่งพาสภาพแวดล้อมการเรียกใช้ในเครื่องหรือไม่

ขั้นตอนที่ 1: สร้างคอนเทนเนอร์

  1. สร้าง Dockerfile ที่สร้างคอนเทนเนอร์ Docker และติดตั้ง Bazel ด้วยชุดเครื่องมือสร้างขั้นต่ำ ดังนี้

    FROM debian:stretch
    
    RUN apt-get update && apt-get install -y apt-transport-https curl software-properties-common git gcc gnupg2 g++ openjdk-8-jdk-headless python-dev zip wget vim
    
    RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
    
    RUN add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
    
    RUN apt-get update && apt-get install -y docker-ce
    
    RUN wget https://releases.bazel.build/<latest Bazel version>/release/bazel-<latest Bazel version>-installer-linux-x86_64.sh -O ./bazel-installer.sh && chmod 755 ./bazel-installer.sh
    
    RUN ./bazel-installer.sh
    
  2. สร้างคอนเทนเนอร์เป็น bazel_container โดยทำดังนี้

    docker build -t bazel_container - < Dockerfile

ขั้นตอนที่ 2: เริ่มคอนเทนเนอร์

เริ่มคอนเทนเนอร์ Docker โดยใช้คำสั่งที่แสดงด้านล่าง ในคำสั่ง ให้แทนที่เส้นทางไปยังซอร์สโค้ดบนโฮสต์ที่ต้องการสร้าง

docker run -it \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /tmp:/tmp \
  -v your source code directory:/src \
  -w /src \
  bazel_container \
  /bin/bash

คำสั่งนี้จะเรียกใช้คอนเทนเนอร์ในฐานะรูท แมปซ็อกเก็ต Docker และต่อเชื่อมไดเรกทอรี /tmp ซึ่งช่วยให้ Bazel สร้างคอนเทนเนอร์ Docker อื่นๆ และใช้ไดเรกทอรีภายใต้ /tmp เพื่อแชร์ไฟล์กับคอนเทนเนอร์เหล่านั้นได้ รหัสต้นทางจะอยู่ที่ /src ในคอนเทนเนอร์

คำสั่งนี้ตั้งใจเริ่มต้นจากคอนเทนเนอร์ฐาน debian:stretch ที่มีไบนารีที่ใช้ไม่ได้กับคอนเทนเนอร์ rbe-ubuntu16-04 ที่ใช้เป็นคอนเทนเนอร์เครื่องมือ หากไฟล์ไบนารีจากสภาพแวดล้อมในเครื่องรั่วไหลไปยังคอนเทนเนอร์เครื่องมือ ไฟล์เหล่านั้นจะทำให้เกิดข้อผิดพลาดในการบิลด์

ขั้นตอนที่ 3: ทดสอบคอนเทนเนอร์

เรียกใช้คําสั่งต่อไปนี้จากภายในคอนเทนเนอร์ Docker เพื่อทดสอบ

docker ps
bazel version

ขั้นตอนที่ 4: เรียกใช้บิลด์

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

bazel --output_user_root=/tmp/bazel_docker_root --bazelrc=.bazelrc \ build --config=docker-sandbox target

ขั้นตอนที่ 5: แก้ไขปัญหาที่ตรวจพบ

คุณแก้ไขการสร้างที่ไม่สําเร็จได้ดังนี้

  • หากการบิลด์ล้มเหลวด้วยข้อผิดพลาด "พื้นที่ในดิสก์ไม่เพียงพอ" คุณสามารถเพิ่มขีดจำกัดนี้ได้โดยการเริ่มคอนเทนเนอร์โฮสต์ด้วย Flag --memory=XX โดยที่ XX คือพื้นที่ในดิสก์ที่จัดสรรเป็นกิกะไบต์ การดำเนินการนี้อยู่ในขั้นทดลองและอาจส่งผลให้เกิดลักษณะการทำงานที่ไม่คาดคิด

  • หากการบิลด์ไม่สําเร็จระหว่างระยะการวิเคราะห์หรือการโหลด แสดงว่ากฎการสร้างอย่างน้อย 1 ข้อที่ประกาศไว้ในไฟล์ WORKSPACE ใช้งานร่วมกับการเรียกใช้จากระยะไกลไม่ได้ ดูสาเหตุที่เป็นไปได้และวิธีแก้ปัญหาชั่วคราวได้ที่การปรับกฎ Bazel สําหรับการดําเนินการจากระยะไกล

  • หากการบิลด์ไม่สำเร็จด้วยเหตุผลอื่น โปรดดูขั้นตอนการแก้ปัญหาในขั้นตอนที่ 2: แก้ไขปัญหาที่ตรวจพบ