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

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

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

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

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

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

सैंडबॉक्स की प्रोसेस की वजहें

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

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

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

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

रणनीति फ़्लैग की मदद से, यह चुना जा सकता है कि सैंडबॉक्स की किस रणनीति का इस्तेमाल करना है या नहीं. sandboxed रणनीति का इस्तेमाल करने पर, Bazel, सैंडबॉक्स को लागू करने के लिए नीचे दी गई किसी एक रणनीति को चुनता है. साथ ही, वह कम hermetic सामान्य रणनीति के बजाय, ओएस के हिसाब से सैंडबॉक्स की रणनीति को प्राथमिकता देता है. अगर --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 नेमस्पेस का इस्तेमाल करता है. इसलिए, 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 सेटिंग से, सेटअप और टीयरडाउन का खर्च कम किया जा सकता है.

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

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

sandboxfs

sandboxfs एक FUSE फ़ाइल सिस्टम है. यह, समय की पाबंदी के बिना, फ़ाइल सिस्टम का कोई भी व्यू दिखाता है. Bazel, हर कार्रवाई के लिए execroot/ को तुरंत जनरेट करने के लिए, sandboxfs का इस्तेमाल करता है. इससे, हज़ारों सिस्टम कॉल जारी करने का खर्च बच जाता है. ध्यान दें कि FUSE ओवरहेड की वजह से, execroot/ में आगे का इनपुट/आउटपुट धीमा हो सकता है.

sandboxfs इंस्टॉल करना

sandboxfs इंस्टॉल करने और इसकी मदद से Bazel बिल्ड करने के लिए, यह तरीका अपनाएं:

डाउनलोड करें

डाउनलोड और इंस्टॉल करें sandboxfs, ताकि sandboxfs बाइनरी आपके PATH में सेव हो जाए.

रन sandboxfs

  1. (सिर्फ़ macOS के लिए) OSXFUSE इंस्टॉल करें.
  2. (सिर्फ़ macOS के लिए) यह कमांड रन करें:

    sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1

    यह कमांड, इंस्टॉलेशन के बाद और हर रीबूट के बाद रन करनी होगी, ताकि यह पक्का किया जा सके कि macOS की मुख्य सिस्टम सेवाएं, sandboxfs के ज़रिए काम करें.

  3. --experimental_use_sandboxfs के साथ Bazel बिल्ड रन करें.

    bazel build target --experimental_use_sandboxfs

समस्या हल करना

अगर रन की गई कार्रवाइयों के लिए एनोटेशन के तौर पर, darwin-sandbox या linux-sandbox के बजाय local दिखता है, तो इसका मतलब है कि सैंडबॉक्स की प्रोसेस बंद है. इसे चालू करने के लिए, --genrule_strategy=sandboxed --spawn_strategy=sandboxed पास करें.

डीबग करना

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

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

कुछ प्लैटफ़ॉर्म पर, जैसे कि 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 को बंद कर दें. ऐसा इसलिए, क्योंकि इससे समय के साथ आपकी डिस्क भर जाती है.