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

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

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

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

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

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

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

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

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

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

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

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

ก่อนที่จะเริ่มแก้ปัญหา โปรดทำตามขั้นตอนต่อไปนี้หากคุณยังไม่ได้ดำเนินการ

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

หากกฎของคุณต้องใช้เครื่องมือเพิ่มเติม ให้ทำตามขั้นตอนต่อไปนี้

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

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

การแก้ปัญหาตั้งแต่ต้น

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

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

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

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

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

ขั้นตอนที่ 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 ทำงาน จากคอนเทนเนอร์เชนเครื่องมือที่สร้างขึ้นโดยฟีเจอร์แซนด์บ็อกซ์ของ 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: แก้ปัญหาที่ตรวจพบ