Docker सैंडबॉक्स की मदद से, Bazel रिमोट एक्ज़ीक्यूशन की समस्या हल करना

किसी समस्या की शिकायत करें सोर्स देखें 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 के पिछले वर्शन में, सैंडबॉक्स की सुविधा काम नहीं करती.
  • यहां बताए गए तरीके से, अपने बिल्ड की WORKSPACE फ़ाइल में, रिलीज़ के सबसे नए वर्शन पर पिन किए गए bazel-toolchains रिपॉज़िटरी को जोड़ें.
  • इस सुविधा को चालू करने के लिए, अपनी .bazelrc फ़ाइल में फ़्लैग जोड़ें. अगर फ़ाइल मौजूद नहीं है, तो अपने Bazel प्रोजेक्ट की रूट डायरेक्ट्री में फ़ाइल बनाएं. यहां दिए गए फ़्लैग, रेफ़रंस के तौर पर दिए गए हैं. कृपया bazel-toolchains repo में सबसे नई .bazelrc फ़ाइल देखें और कॉन्फ़िगरेशन 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. Dockerfile का इस्तेमाल करके टूल इंस्टॉल करके और इमेज को स्थानीय तौर पर बिल्ड करके, कस्टम Docker कंटेनर बनाएं.

  2. ऊपर दिए गए --experimental_docker_image फ़्लैग की वैल्यू को, अपनी कस्टम कंटेनर इमेज के नाम से बदलें.

समस्या को मूल रूप से हल करना

इस तरीके से, Bazel और उसकी सभी बिल्ड कार्रवाइयां सीधे तौर पर लोकल मशीन पर की जाती हैं. साथ ही, यह पुष्टि करने का भरोसेमंद तरीका है कि रिमोट तौर पर बिल्ड करने पर, आपका बिल्ड पूरा होगा या नहीं.

हालांकि, इस तरीके से, स्थानीय तौर पर इंस्टॉल किए गए टूल, बाइनरी, और डेटा आपके बिल्ड में लीक हो सकते हैं. ऐसा खास तौर पर तब होता है, जब इसमें कॉन्फ़िगर-स्टाइल WORKSPACE नियमों का इस्तेमाल किया जाता है. इस तरह की लीक की वजह से, रिमोट तौर पर प्रोग्राम चलाने में समस्याएं आ सकती हैं. इनका पता लगाने के लिए, Docker कंटेनर में समस्या हल करें. साथ ही, समस्या को सामान्य तरीके से भी हल करें.

पहला चरण: बिल्ड चलाना

  1. अपने बिल्ड को लागू करने वाले Bazel कमांड में --config=docker-sandbox फ़्लैग जोड़ें. उदाहरण के लिए:

    bazel --bazelrc=.bazelrc build --config=docker-sandbox target
  2. बिल्ड चलाएं और इसके पूरा होने का इंतज़ार करें. Docker सैंडबॉक्स की सुविधा की वजह से, बिल्ड सामान्य से चार गुना धीमे चलेगा.

आपको यह गड़बड़ी दिख सकती है:

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

अगर ऐसा है, तो --experimental_docker_verbose फ़्लैग के साथ बिल्ड को फिर से चलाएं. इस फ़्लैग की मदद से, गड़बड़ी के बारे में ज़्यादा जानकारी देने वाले मैसेज दिखाए जा सकते हैं. आम तौर पर, यह गड़बड़ी Docker के गलत तरीके से इंस्टॉल होने या मौजूदा उपयोगकर्ता खाते में इसे चलाने की अनुमतियां न होने की वजह से होती है. ज़्यादा जानकारी के लिए, Docker दस्तावेज़ देखें. अगर समस्याएं बनी रहती हैं, तो Docker कंटेनर में समस्या हल करना लेख पर जाएं.

दूसरा चरण: समस्याओं को हल करना

यहां सबसे आम समस्याओं और उन्हें हल करने के तरीकों के बारे में बताया गया है.

  • Bazel के रनफ़ाइल ट्री में रेफ़र की गई फ़ाइल, टूल, बाइनरी या संसाधन मौजूद नहीं है.. पुष्टि करें कि जिन टारगेट पर असर पड़ा है उनकी सभी डिपेंडेंसी के बारे में साफ़ तौर पर एलान किया गया हो. ज़्यादा जानकारी के लिए, अहम डिपेंडेंसी मैनेज करना देखें.

  • ऐसी फ़ाइल, टूल, बाइनरी या संसाधन मौजूद नहीं है जिसका रेफ़रंस, एब्सोलूट पाथ या PATH वैरिएबल से दिया गया है. पुष्टि करें कि टूलचेन कंटेनर में सभी ज़रूरी टूल इंस्टॉल किए गए हैं. साथ ही, टूलचेन के नियमों का इस्तेमाल करके, मौजूद न होने वाले संसाधन की जानकारी देने वाली डिपेंडेंसी का सही तरीके से एलान करें. ज़्यादा जानकारी के लिए, टूलचेन के नियमों की मदद से, बिल्ड टूल को शुरू करना देखें.

  • बाइनरी को लागू नहीं किया जा सका. बिल्ड के नियमों में से एक, एक ऐसी बाइनरी का रेफ़रंस दे रहा है जो एक्ज़ीक्यूशन एनवायरमेंट (Docker कंटेनर) के साथ काम नहीं करती. ज़्यादा जानकारी के लिए, प्लैटफ़ॉर्म पर निर्भर बाइनरी मैनेज करना देखें. अगर आपको समस्या हल करने में समस्या आ रही है, तो मदद पाने के लिए bazel-discuss@google.com पर संपर्क करें.

  • @local-jdk में मौजूद कोई फ़ाइल मौजूद नहीं है या उससे गड़बड़ियां हो रही हैं. आपकी लोकल मशीन पर मौजूद Java बाइनरी, बिल्ड में लीक हो रही हैं. हालांकि, ये बिल्ड के साथ काम नहीं करती हैं. अपने नियमों और टारगेट में @local_jdk के बजाय, java_toolchain का इस्तेमाल करें. अगर आपको और मदद चाहिए, तो bazel-discuss@google.com पर संपर्क करें.

  • अन्य गड़बड़ियां. मदद पाने के लिए, bazel-discuss@google.com पर संपर्क करें.

Docker कंटेनर में समस्या हल करना

इस तरीके से, Bazel किसी होस्ट Docker कंटेनर में चलता है. साथ ही, Bazel की बिल्ड ऐक्शन, Docker के सैंडबॉक्स की सुविधा से जनरेट किए गए अलग-अलग टूलचेन कंटेनर में लागू होती हैं. सैंडबॉक्स, हर बिल्ड ऐक्शन के लिए एक नया टूलचेन कंटेनर बनाता है. साथ ही, हर टूलचेन कंटेनर में सिर्फ़ एक ऐक्शन लागू होता है.

इस तरीके से, होस्ट के एनवायरमेंट में इंस्टॉल किए गए टूल पर ज़्यादा बेहतर तरीके से कंट्रोल किया जा सकता है. बिल्ड को चलाने की प्रोसेस को, बिल्ड ऐक्शन को चलाने की प्रोसेस से अलग करके और इंस्टॉल किए गए टूल को कम से कम रखकर, यह पुष्टि की जा सकती है कि आपके बिल्ड में, स्थानीय रनटाइम एनवायरमेंट पर कोई डिपेंडेंसी है या नहीं.

पहला चरण: कंटेनर बनाना

  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

दूसरा चरण: कंटेनर शुरू करना

नीचे दिए गए कमांड का इस्तेमाल करके, 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 कंटेनर के साथ काम नहीं करती हैं. अगर स्थानीय एनवायरमेंट से बाइनरी, टूलचेन कंटेनर में लीक हो रही हैं, तो इससे बिल्ड में गड़बड़ियां होंगी.

तीसरा चरण: कंटेनर की जांच करना

Docker कंटेनर की जांच करने के लिए, उसमें ये कमांड चलाएं:

docker ps
bazel version

चौथा चरण: बिल्ड चलाना

नीचे दिखाए गए तरीके से बिल्ड चलाएं. आउटपुट उपयोगकर्ता रूट होता है, ताकि वह उस डायरेक्ट्री से मेल खा सके जिसे होस्ट कंटेनर में उसी सटीक पाथ से ऐक्सेस किया जा सकता है जिसमें Bazel चलता है. साथ ही, Docker के सैंडबॉक्स की सुविधा से जनरेट किए गए टूलचेन कंटेनर से भी उस डायरेक्ट्री को ऐक्सेस किया जा सकता है. इस सुविधा में, Bazel की बिल्ड ऐक्शन चल रही हैं. इसके अलावा, उस लोकल मशीन से भी उस डायरेक्ट्री को ऐक्सेस किया जा सकता है जिस पर होस्ट और ऐक्शन कंटेनर चल रहे हैं.

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

पांचवां चरण: समस्याओं को हल करना

बिल्ड न होने की समस्या को ठीक करने के लिए, यह तरीका अपनाएं:

  • अगर "डिस्क में जगह नहीं है" गड़बड़ी की वजह से बिल्ड पूरा नहीं हो पाता है, तो होस्ट कंटेनर को फ़्लैग --memory=XX के साथ शुरू करके, इस सीमा को बढ़ाया जा सकता है. यहां XX, डिस्क में आवंटित जगह को दिखाता है, जो गीगाबाइट में होती है. यह सुविधा, एक्सपेरिमेंट के तौर पर उपलब्ध है. इसलिए, ऐसा हो सकता है कि इससे अलग तरह का व्यवहार देखने को मिले.

  • अगर विश्लेषण या लोड करने के दौरान बिल्ड पूरा नहीं होता है, तो इसका मतलब है कि WORKSPACE फ़ाइल में बताए गए आपके एक या एक से ज़्यादा बिल्ड नियम, रिमोट तौर पर लागू करने के साथ काम नहीं करते. इस गड़बड़ी की संभावित वजहों और उसे ठीक करने के तरीकों के बारे में जानने के लिए, रिमोट तौर पर प्रोग्राम चलाने के लिए Bazel के नियमों में बदलाव करना देखें.

  • अगर बिल्ड किसी और वजह से पूरा नहीं होता है, तो दूसरा चरण: पाई गई समस्याओं को हल करना में समस्या हल करने का तरीका देखें.