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

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

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

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

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

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

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

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

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

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

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

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

  • ติดตั้ง Docker และกำหนดค่าสิทธิ์ที่จำเป็นในการดำเนินการ
  • ติดตั้ง Bazel 0.14.1 ขึ้นไป เวอร์ชันก่อนหน้าไม่รองรับฟีเจอร์แซนด์บ็อกซ์ Docker
  • เพิ่ม repo bazel-toolchains ที่ปักหมุดไว้กับเวอร์ชันที่เผยแพร่ล่าสุดลงในไฟล์ WORKSPACE ของบิลด์ตามที่อธิบายไว้ที่นี่
  • เพิ่มแฟล็กในไฟล์ .bazelrc เพื่อเปิดใช้ฟีเจอร์ สร้างไฟล์ในไดเรกทอรีรากของโปรเจ็กต์ Bazel หากยังไม่มี แฟล็กด้านล่างเป็นตัวอย่างข้อมูลอ้างอิง โปรดดูไฟล์ล่าสุด .bazelrc ใน repo bazel-toolchains และคัดลอกค่าของแฟล็กที่กำหนดไว้ ที่นั่นสำหรับการกำหนดค่า 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 --experimental_docker_verbose
build:docker-sandbox --experimental_enable_docker_sandbox

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

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

  2. แทนที่ค่าของแฟล็ก --experimental_docker_image ด้านบนด้วยชื่ออิมเมจคอนเทนเนอร์ที่กำหนดเอง

การแก้ปัญหาโดยตรง

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

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

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

  1. เพิ่มแฟล็ก --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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

docker ps
bazel version

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

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

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

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

คุณสามารถแก้ไขความล้มเหลวในการบิลด์ได้ดังนี้

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

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

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