इस लेख में, 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 के लिए है. यह, Apple के sandbox-exec टूल का इस्तेमाल करके, Linux सैंडबॉक्स की तरह ही काम करता है.
ऑपरेटिंग सिस्टम की ओर से उपलब्ध कराए गए मैकेनिज़्म में मौजूद पाबंदियों की वजह से, linux-sandbox और darwin-sandbox, "नेस्टेड" सिनेरियो में काम नहीं करते. Docker भी अपने कंटेनर मैजिक के लिए Linux नेमस्पेस का इस्तेमाल करता है. इसलिए, docker run --privileged का इस्तेमाल किए बिना, Docker कंटेनर में linux-sandbox को आसानी से रन नहीं किया जा सकता. 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नियम लागू न हो पाने की समस्याएं
सिस्टम सेटअप की वजह से, सैंडबॉक्स में नियम लागू नहीं हो सकते. अगर आपको
मैसेज दिखता है, तो genrules के लिए --strategy=Genrule=local और अन्य नियमों के लिए --spawn_strategy=local का इस्तेमाल करके, सैंडबॉक्स को बंद करने की कोशिश करें.namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory
बिल्ड में गड़बड़ी की वजह जानने के लिए डीबग करना
अगर आपका बिल्ड नहीं हो पाया है, तो --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 को बंद कर दें. ऐसा न करने पर, समय के साथ आपकी डिस्क भर जाएगी.