सैंडबॉक्सिंग

इस लेख में, Bazel में सैंडबॉक्स की प्रोसेस और सैंडबॉक्सिंग एनवायरमेंट को डीबग करने के बारे में बताया गया है.

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

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

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

खास तौर पर, Bazel हर कार्रवाई के लिए एक execroot/ डायरेक्ट्री बनाता है. यह डायरेक्ट्री, कार्रवाई के दौरान उसकी वर्किंग डायरेक्ट्री के तौर पर काम करती है. execroot/ में, कार्रवाई के सभी इनपुट फ़ाइलें होती हैं. साथ ही, यह जनरेट किए गए सभी आउटपुट के लिए कंटेनर के तौर पर काम करती है. इसके बाद, Bazel, ऑपरेटिंग सिस्टम की ओर से दी गई एक तकनीक का इस्तेमाल करता है. Linux पर कंटेनर और macOS पर sandbox-exec का इस्तेमाल करके, कार्रवाई को execroot/ में सीमित किया जाता है.

सैंडबॉक्सिंग की वजहें

  • कार्रवाई की सैंडबॉक्सिंग के बिना, Bazel को यह पता नहीं चलता कि कोई टूल, बिना बताई गई इनपुट फ़ाइलों (ऐसी फ़ाइलें जो किसी कार्रवाई की डिपेंडेंसी में साफ़ तौर पर शामिल नहीं होती हैं) का इस्तेमाल करता है या नहीं. जब बिना बताई गई किसी इनपुट फ़ाइल में बदलाव होता है, तब भी Bazel को लगता है कि बिल्ड अप-टू-डेट है. इसलिए, वह कार्रवाई को फिर से नहीं बनाता. इससे, इंक्रीमेंटल बिल्ड गलत हो सकता है.

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

  • सैंडबॉक्सिंग, रिमोट एक्ज़ीक्यूशन के जैसा काम करती है. अगर कोई बिल्ड, सैंडबॉक्सिंग के साथ अच्छी तरह काम करता है, तो वह रिमोट एक्ज़ीक्यूशन के साथ भी काम करेगा. रिमोट एक्ज़ीक्यूशन से सभी ज़रूरी फ़ाइलें (स्थानीय टूल भी शामिल हैं) अपलोड कराकर, कंपाइल क्लस्टर के रखरखाव की लागत को काफ़ी कम किया जा सकता है. इसके लिए, हर बार नया कंपाइलर आज़माने या मौजूदा टूल में बदलाव करने पर, क्लस्टर में मौजूद हर मशीन पर टूल इंस्टॉल करने की ज़रूरत नहीं होती.

सैंडबॉक्स की किस रणनीति का इस्तेमाल करना है

रणनीति फ़्लैग की मदद से, यह चुना जा सकता है कि किस तरह की सैंडबॉक्सिंग का इस्तेमाल करना है या नहीं. sandboxed रणनीति का इस्तेमाल करने पर, Bazel, नीचे दी गई सैंडबॉक्स लागू करने की किसी एक सुविधा को चुनता है. साथ ही, वह कम हर्मेटिक सामान्य सैंडबॉक्स के बजाय, ओएस के हिसाब से बने सैंडबॉक्स को प्राथमिकता देता है. अगर --worker_sandboxing फ़्लैग पास किया जाता है, तो पर्सिस्टेंट वर्कर, सामान्य सैंडबॉक्स में चलते हैं.

local (इसे standalone भी कहा जाता है) रणनीति में, किसी भी तरह की सैंडबॉक्सिंग नहीं की जाती. यह रणनीति, कार्रवाई की कमांड लाइन को सीधे तौर पर आपके वर्कस्पेस के execroot पर सेट की गई वर्किंग डायरेक्ट्री के साथ लागू करती है.

processwrapper-sandbox एक ऐसी सैंडबॉक्सिंग रणनीति है जिसके लिए किसी "एडवांस" सुविधा की ज़रूरत नहीं होती. यह किसी भी POSIX सिस्टम पर काम करती है. यह एक सैंडबॉक्स डायरेक्ट्री बनाती है, जिसमें सिमलंक होते हैं. ये सिमलंक, ओरिजनल सोर्स फ़ाइलों की ओर इशारा करते हैं. यह रणनीति, कार्रवाई की कमांड लाइन को execroot के बजाय इस डायरेक्ट्री पर सेट की गई वर्किंग डायरेक्ट्री के साथ लागू करती है. इसके बाद, जाने-पहचाने आउटपुट आर्टफ़ैक्ट को सैंडबॉक्स से execroot में ले जाती है और सैंडबॉक्स को मिटा देती है. इससे, कार्रवाई के दौरान, बिना बताई गई किसी भी इनपुट फ़ाइल का इस्तेमाल करने और execroot में बिना बताई गई आउटपुट फ़ाइलों को सेव करने से रोका जा सकता है.

linux-sandbox , processwrapper-sandbox से एक कदम आगे है और यह processwrapper-sandbox पर आधारित है. यह, Docker की तरह ही, कार्रवाई को होस्ट से अलग करने के लिए, Linux नेमस्पेस (यूज़र, माउंट, पीआईडी, नेटवर्क, और आईपीसी नेमस्पेस) का इस्तेमाल करता है. इसका मतलब है कि यह सैंडबॉक्स डायरेक्ट्री को छोड़कर, पूरे फ़ाइल सिस्टम को रीड-ओनली बना देता है. इसलिए, कार्रवाई के दौरान, होस्ट फ़ाइल सिस्टम में किसी भी तरह का बदलाव नहीं किया जा सकता. इससे, ऐसी स्थितियों से बचा जा सकता है जहां किसी गड़बड़ी वाले टेस्ट की वजह से, आपकी $HOME डायरेक्ट्री गलती से rm -rf हो जाए. आपके पास कार्रवाई को नेटवर्क ऐक्सेस करने से रोकने का विकल्प भी होता है. linux-sandbox , पीआईडी नेमस्पेस का इस्तेमाल करके, कार्रवाई को अन्य प्रोसेस देखने से रोकता है. साथ ही, यह सभी प्रोसेस (कार्रवाई से जनरेट हुए डेमॉन भी) को आखिर में बंद कर देता है.

darwin-sandbox भी इसी तरह काम करता है, लेकिन यह macOS के लिए है. यह, Apple के sandbox-exec टूल का इस्तेमाल करके, Linux सैंडबॉक्स के जैसा ही काम करता है.

ऑपरेटिंग सिस्टम की ओर से दिए गए मैकेनिज़्म में मौजूद पाबंदियों की वजह से, linux-sandbox और darwin-sandbox, "नेस्टेड" सिनेरियो में काम नहीं करते. Docker भी अपने कंटेनर मैजिक के लिए Linux नेमस्पेस का इस्तेमाल करता है. इसलिए, docker run --privileged का इस्तेमाल किए बिना, linux-sandbox को Docker कंटेनर में आसानी से नहीं चलाया जा सकता. macOS पर, sandbox-exec को ऐसी प्रोसेस में नहीं चलाया जा सकता जो पहले से सैंडबॉक्स की जा रही हो. इसलिए, इन मामलों में, Bazel अपने-आप processwrapper-sandbox का इस्तेमाल करता है.

अगर आपको बिल्ड में गड़बड़ी चाहिए, ताकि कम सख्त एक्ज़ीक्यूशन रणनीति के साथ गलती से बिल्ड न हो, तो Bazel की ओर से इस्तेमाल की जाने वाली एक्ज़ीक्यूशन रणनीतियों की सूची में साफ़ तौर पर बदलाव करें. उदाहरण के लिए, bazel build --spawn_strategy=worker,linux-sandbox.

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

सैंडबॉक्सिंग के नुकसान

  • सैंडबॉक्सिंग के लिए, सेटअप और टियरडाउन की लागत अलग से चुकानी पड़ती है. यह लागत कितनी होगी, यह कई चीज़ों पर निर्भर करता है. जैसे, बिल्ड का आकार और होस्ट ओएस की परफ़ॉर्मेंस. Linux के लिए, सैंडबॉक्स किए गए बिल्ड की स्पीड में कुछ प्रतिशत से ज़्यादा की कमी नहीं आती. --reuse_sandbox_directories सेटिंग से, सेटअप और टियरडाउन की लागत को कम किया जा सकता है.

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

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

डीबग करना

सैंडबॉक्सिंग से जुड़ी समस्याओं को डीबग करने के लिए, यहां दी गई रणनीतियों का पालन करें.

बंद किए गए नेमस्पेस

कुछ प्लैटफ़ॉर्म पर, जैसे कि Google Kubernetes Engine क्लस्टर नोड या Debian पर, सुरक्षा से जुड़ी चिंताओं की वजह से, उपयोगकर्ता नेमस्पेस डिफ़ॉल्ट रूप से बंद होते हैं. अगर /proc/sys/kernel/unprivileged_userns_clone फ़ाइल मौजूद है और इसमें 0 है, तो इसे चलाकर उपयोगकर्ता नेमस्पेस चालू किए जा सकते हैं:

   sudo sysctl kernel.unprivileged_userns_clone=1

नियम लागू न हो पाने की समस्याएं

सिस्टम सेटअप की वजह से, सैंडबॉक्स में नियम लागू नहीं हो सकते. अगर आपको कोई मैसेज दिखता हैnamespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory, तो genrules के लिए --strategy=Genrule=local और अन्य नियमों के लिए --spawn_strategy=local का इस्तेमाल करके, सैंडबॉक्स को बंद करने की कोशिश करें.

बिल्ड में गड़बड़ी की वजह जानने के लिए डीबग करना

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

गड़बड़ी के मैसेज का उदाहरण:

ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:

Sandboxed execution failed, which may be legitimate (such as a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned

namespace-sandbox failed: error executing command
  (cd /some/path && \
  exec env - \
    LANG=en_US \
    PATH=/some/path/bin:/bin:/usr/bin \
    PYTHONPATH=/usr/local/some/path \
  /some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
  /some/path/to/your/some-compiler --some-params some-target)

अब जनरेट की गई सैंडबॉक्स डायरेक्ट्री की जांच की जा सकती है. साथ ही, यह देखा जा सकता है कि Bazel ने कौनसी फ़ाइलें बनाई हैं. इसके अलावा, यह देखने के लिए कि यह कैसे काम करता है, कमांड को फिर से चलाया जा सकता है.

ध्यान दें कि --sandbox_debug का इस्तेमाल करने पर, Bazel सैंडबॉक्स डायरेक्ट्री को नहीं मिटाता. अगर डीबग नहीं किया जा रहा है, तो --sandbox_debug को बंद कर दें. ऐसा इसलिए, क्योंकि इससे समय के साथ आपकी डिस्क भर जाती है.