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

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

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

Docker सैंडबॉक्स सुविधा, रिमोट तरीके से चलाने पर लागू होने वाली पाबंदियों को इस तरह से लागू करती है:

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

  • कंटेनर की सीमा से बाहर, कोई भी अतिरिक्त डेटा नहीं जाता है. सिर्फ़ साफ़ तौर पर बताए गए इनपुट और आउटपुट, कंटेनर में आते और जाते हैं. साथ ही, ये सिर्फ़ तब आते और जाते हैं, जब उनसे जुड़ा बिल्ड ऐक्शन पूरी तरह से पूरा हो जाता है.

  • हर ऐक्शन, नए कंटेनर में लागू होता है. हर स्पॉन किए गए बिल्ड ऐक्शन के लिए, नया और यूनीक कंटेनर बनाया जाता है.

इन समस्याओं को हल करने के लिए, इनमें से कोई एक तरीका इस्तेमाल किया जा सकता है:

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

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

ज़रूरी शर्तें

समस्या हल करने की प्रक्रिया शुरू करने से पहले, अगर आपने ये काम नहीं किए हैं, तो इन्हें पूरा करें:

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

अगर आपके नियमों के लिए, अतिरिक्त टूल की ज़रूरत है, तो यह तरीका अपनाएं:

  1. Dockerfile

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

नेटिव तरीके से समस्या हल करना

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

हालांकि, इस तरीके से, लोकल तरीके से इंस्टॉल किए गए टूल, बाइनरी, और डेटा, आपके बिल्ड में लीक हो सकते हैं . ऐसा तब हो सकता है, जब बिल्ड में configure-style 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 कंटेनर में समस्या हल करना पर जाएं.

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

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

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 के नियमों को अडैप्ट करना देखें.

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