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

समस्या की शिकायत करें सोर्स देखें

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

इस पेज पर, 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 --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 कंटेनर में समस्या हल करना पर जाएं.

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

सामान्य रूप से सामने आने वाली सबसे सामान्य समस्याएं और उनके समाधान नीचे दिए गए हैं.

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

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

  • बाइनरी लागू नहीं होती. बिल्ड के नियमों में से एक है, जो लागू करने वाले एनवायरमेंट (डॉकर कंटेनर) के साथ काम न करने वाले बाइनरी के बारे में बता रहा है. ज़्यादा जानकारी के लिए, प्लैटफ़ॉर्म पर निर्भर बाइनरी मैनेज करना देखें. अगर समस्या हल नहीं हो पा रही है, तो मदद के लिए 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

यह निर्देश, कंटेनर को रूट की तरह चलाता है. साथ ही, डॉकर के सॉकेट को मैप करता है और /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 के नियमों को अपनाना देखें.

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