इस लेख में, 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
के ऊपर बनता है. Docker की तरह ही, यह भी होस्ट से कार्रवाई को अलग करने के लिए, Linux नेमस्पेस (उपयोगकर्ता, माउंट, पीआईडी, नेटवर्क, और आईपीसी नेमस्पेस) का इस्तेमाल करता है. इसका मतलब है कि यह सैंडबॉक्स डायरेक्ट्री को छोड़कर, पूरे फ़ाइल सिस्टम को सिर्फ़ पढ़ने के लिए उपलब्ध कर देता है. इससे, होस्ट फ़ाइल सिस्टम में गलती से कोई बदलाव नहीं हो सकता. इससे, गड़बड़ी वाले टेस्ट की वजह से आपकी $HOME डायरेक्ट्री को rm
-rf की मदद से गलती से मिटाने जैसी स्थितियों से बचा जा सकता है. इसके अलावा, आपके पास ऐक्शन को नेटवर्क ऐक्सेस करने से रोकने का विकल्प भी है. linux-sandbox
, कार्रवाई को किसी भी अन्य प्रोसेस को देखने से रोकने के लिए, पीआईडी नेमस्पेस का इस्तेमाल करता है. साथ ही, आखिर में सभी प्रोसेस (कार्रवाई से पैदा हुए डेमन भी) को भरोसेमंद तरीके से बंद करता है.
darwin-sandbox
, से मिलता-जुलता है, लेकिन यह macOS के लिए है. यह Linux सैंडबॉक्स की तरह ही काम करने के लिए, Apple के sandbox-exec
टूल का इस्तेमाल करता है.
ऑपरेटिंग सिस्टम के काम करने के तरीके में लगी पाबंदियों की वजह से, linux-sandbox
और darwin-sandbox
, "नेस्ट किए गए" शीट में काम नहीं करते. Docker, अपने कंटेनर के लिए Linux नेमस्पेस का भी इस्तेमाल करता है. इसलिए, linux-sandbox
को Docker कंटेनर में आसानी से तब तक नहीं चलाया जा सकता, जब तक docker run --privileged
का इस्तेमाल नहीं किया जाता. 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
जैसा कोई मैसेज दिखता है, तो जनरेट किए गए नियमों के लिए --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
को बंद रखना चाहिए. ऐसा इसलिए, क्योंकि यह समय के साथ आपकी डिस्क को भर देता है.