Ubuntu पर Python venv, pipx और uv का सही उपयोग कैसे करें
Ubuntu सर्वर पर externally-managed-environment एरर आने पर क्या करें? जानें कि कब venv, pipx या uv का उपयोग करना है और systemd के साथ इनका सही तालमेल कैसे बिठाया जाए।
नए Ubuntu सर्वर पर pip install विफल क्यों होता है
सर्वर पर Python venv, pipx और uv के बीच चुनाव एक ही प्रश्न पर निर्भर करता है: आप क्या install कर रहे हैं? Application dependencies को application की अपनी directory के भीतर एक virtual environment में होना चाहिए। जिन command-line tools को आप नाम से चलाना चाहते हैं, उन्हें pipx में होना चाहिए। uv दोनों काम करता है और एक lockfile जोड़ता है, जो तब महत्वपूर्ण हो जाता है जब दूसरी मशीन को वही environment build करना हो। इनमें से कोई भी system Python में install नहीं करता, क्योंकि वर्तमान Ubuntu सर्वर इसे पूरी तरह से अस्वीकार कर देता है।
Ubuntu 24.04 पर sudo pip install requests चलाएं और pip एक भी file download करने से पहले रुक जाता है।
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this behaviour by passing --break-system-packages.यह PEP 668 (Python enhancement proposal 668, "externally managed environments") है जो अपना काम कर रहा है। Debian और Ubuntu, /usr/lib/python3.12/EXTERNALLY-MANAGED पर interpreter के बगल में एक marker file डालते हैं, और pip किसी भी ऐसे interpreter में लिखने से मना कर देता है जिसमें यह file मौजूद हो।
यह नियम sys.path क्रम के कारण मौजूद है। apt libraries को /usr/lib/python3/dist-packages में install करता है। root के रूप में system interpreter के विरुद्ध चलाया गया pip, /usr/local/lib/python3.12/dist-packages में लिखता है, और Debian की packaging उस directory को search path में पहले रखती है। इसे स्वयं python3 -c 'import sys; print(sys.path)' के साथ print करें और क्रम पढ़ें। इसलिए, pip द्वारा लिखी गई copy, apt द्वारा install की गई copy को shadow कर देती है, उस box पर चलने वाले हर program के लिए जो /usr/bin/python3 के अंतर्गत चलता है, जिसमें distribution के अपने tools भी शामिल हैं। cloud-init उस interpreter से requests, jinja2 और PyYAML import करता है। pip के साथ उनमें से किसी एक को upgrade करें, एक incompatible release पर पहुँचें, और कोई ऐसी चीज़ जिसे आपने कभी छुआ नहीं, वह अगले boot पर एक traceback के साथ विफल हो जाएगी, जिसमें एक ऐसे package का नाम होगा जिसके बारे में आप नहीं जानते थे कि वह chain में है। apt अभी भी अपने स्वयं के version को install के रूप में record करता है, इसलिए कोई भी आपको चेतावनी नहीं देता है, और सुधार sudo apt reinstall python3-requests है।
इसका पालन करने वाला नियम संक्षिप्त है। system Python distribution का है। इसमें install न करें, pip के साथ इसकी libraries को upgrade न करें, और संदेश को हटाने के लिए EXTERNALLY-MANAGED file को delete न करें। /usr/bin/python3 को दिया जाने वाला एकमात्र काम virtual environments बनाना है।
venv बनाम pipx बनाम uv: निर्णय लेने का नियम
आप क्या इंस्टॉल कर रहे हैं, उसके आधार पर चुनाव करें, न कि इस आधार पर कि आपने हाल ही में किस टूल के बारे में सबसे अधिक पढ़ा है।
- कोई एप्लिकेशन जिसे आप डिप्लॉय करते हैं और एक सर्विस के रूप में चलाते हैं, जैसे कि Django या Flask प्रोजेक्ट: उस एप्लिकेशन की डायरेक्टरी के अंदर एक वर्चुअल एनवायरनमेंट (venv) का उपयोग करें।
- कोई कमांड-लाइन टूल जिसे आप अपने
PATHपर चाहते हैं, जैसे किansibleयाhttpie: pipx का उपयोग करें, जो प्रत्येक टूल को एक प्राइवेट एनवायरनमेंट औरPATHपर एक लिंक देता है। - कोई प्रोजेक्ट जिसे लॉकफाइल, तेज़ इंस्टॉलेशन या ऐसे Python वर्ज़न की आवश्यकता है जिसे डिस्ट्रिब्यूशन प्रदान नहीं करता है: uv का उपयोग करें, जो एक सामान्य venv और एक
uv.lockफाइल बनाता है। - कोई लाइब्रेरी जिसकी आवश्यकता किसी डिस्ट्रिब्यूशन टूल को है, न कि आपके कोड को:
sudo apt install python3-<name>, सिस्टम इंटरप्रेटर में कुछ भी जोड़ने का एकमात्र समर्थित तरीका है।
pipx और uv tool install एक ही काम करते हैं, इसलिए जिस सिस्टम में पहले से uv है, उसे pipx की आवश्यकता नहीं है। आपने कौन सा वेब फ्रेमवर्क चुना है, इससे यहाँ कोई फर्क नहीं पड़ता: VPS पर Django और Flask इस बात में भिन्न हैं कि requirements.txt में क्या जाता है, न कि इस बात में कि उसके चारों ओर का एनवायरनमेंट कैसे बनाया जाता है। नीचे दी गई हर चीज़ Ubuntu 24.04 और इसके Python 3.12 का उपयोग करती है, इसलिए यदि आपका वर्ज़न अलग है तो पाथ के अंदर वर्ज़न को एडजस्ट करें।
प्रत्येक-एप्लिकेशन के लिए venv बनाएँ
Ubuntu, venv मॉड्यूल को बेस Python पैकेज से अलग रखता है, इसलिए minimal image पर पहला प्रयास इस संदेश के साथ विफल हो जाता है कि क्या गायब है।
The virtual environment was not created successfully because ensurepip is not
available. On Debian/Ubuntu systems, you need to install the python3-venv
package using the following command.
apt install python3.12-venvइसे इंस्टॉल करें, फिर उस उपयोगकर्ता के रूप में environment बनाएँ जो कोड का स्वामी होगा।
sudo apt update
sudo apt install -y python3-venv
sudo install -d -o deploy -g deploy -m 755 /srv/myapp
sudo -u deploy python3 -m venv /srv/myapp/.venv
sudo -u deploy /srv/myapp/.venv/bin/pip install -r /srv/myapp/requirements.txtध्यान दें कि क्या मौजूद नहीं है: न source, न activate। /srv/myapp/.venv/bin/pip उस environment में इंस्टॉल होता है क्योंकि बाइनरी वहीं स्थित है, न कि इसलिए कि आपने शेल में कुछ export किया है। आगे बढ़ने से पहले इसकी पुष्टि करें।
/srv/myapp/.venv/bin/python -c 'import sys; print(sys.prefix)'यह /srv/myapp/.venv प्रिंट करता है। यदि यह /usr प्रिंट करता है, तो आप system interpreter चला रहे हैं और आपके पैकेज ऐसी जगह चले गए हैं जहाँ आप नहीं चाहते थे।
venv के दो गुण यह तय करते हैं कि आप बाद में इसके साथ क्या कर सकते हैं। एक venv को relocate नहीं किया जा सकता, क्योंकि bin/ में प्रत्येक स्क्रिप्ट में एक absolute shebang लाइन होती है: head -1 /srv/myapp/.venv/bin/pip, #!/srv/myapp/.venv/bin/python को पढ़ता है। पैरेंट डायरेक्टरी का नाम बदलें और वे स्क्रिप्ट्स bad interpreter: No such file or directory के साथ विफल हो जाती हैं। एक venv उस interpreter को भी पिन करता है जिसने इसे बनाया है, जिसे /srv/myapp/.venv/pyvenv.cfg में home लाइन के रूप में रिकॉर्ड किया जाता है, और bin/python3 उस बाइनरी का एक symlink है। release को अपग्रेड करें जिससे python3.12 हट जाए, तो symlink का कोई target नहीं बचेगा, और service शुरुआत में ही No such file or directory के साथ बंद हो जाएगी। दोनों मामलों का एक ही समाधान है: venv को डिलीट करें और requirements.txt से एक नया बनाएँ। इसे फिर से बनाने में कुछ ही सेकंड लगते हैं। मशीनों के बीच कभी भी venv को कॉपी न करें।
venv कहाँ स्थित होना चाहिए और इसका स्वामी कौन होना चाहिए
इसे /srv/myapp/.venv पर कोड के बगल में रखें, और प्रति एप्लिकेशन एक venv बनाए रखें। इससे deployment एक एकल निर्देशिका (directory) बन जाती है, systemd unit को एक ऐसा पथ (path) मिल जाता है जो कभी नहीं बदलता, और दो एप्लिकेशन एक साझा dependency upgrade के कारण कभी भी एक-दूसरे को बाधित नहीं कर सकते। venv को ऐसी किसी जगह न रखें जहाँ आपका वेब सर्वर सीधे फाइलें प्रकाशित (publish) करता हो, क्योंकि इसमें आपकी dependencies और अक्सर आपकी configuration होती है।
स्वामित्व (ownership) पर थोड़ा ध्यान देना आवश्यक है। कोड और environment का स्वामी एक deploy उपयोगकर्ता को बनाएं, और service account को केवल read और execute एक्सेस दें।
sudo adduser --system --group --no-create-home myapp
sudo chown -R deploy:myapp /srv/myapp
sudo chmod -R o-rwx /srv/myappअब service अपनी dependencies को import तो कर सकती है लेकिन उन्हें rewrite नहीं कर सकती। इसका अर्थ यह है कि वेब एप्लिकेशन में मौजूद कोई code execution bug चुपचाप डिस्क पर मौजूद किसी library को बदलकर restart के बाद भी सक्रिय नहीं रह सकता। मशीन के बाकी हिस्सों पर लागू होने वाला यही तर्क least-privilege उपयोगकर्ताओं के रूप में सेवाएं चलाना में कवर किया गया है।
command-line tools के लिए pipx
pipx libraries नहीं, बल्कि applications install करता है। प्रत्येक tool को ~/.local/share/pipx/venvs/<name> के अंतर्गत अपना environment मिलता है, और उस tool की executables को ~/.local/bin में link किया जाता है, ताकि एक ही library के अलग-अलग versions की आवश्यकता वाले दो tools के बीच कभी टकराव न हो।
sudo apt update
sudo apt install -y pipx
pipx ensurepath
pipx install httpiepipx ensurepath आपके shell startup file को edit करके ~/.local/bin को PATH में जोड़ता है। यह उस shell को नहीं बदल सकता जिसमें आप अभी काम कर रहे हैं, इसलिए install करने के तुरंत बाद http: command not found का मतलब आमतौर पर यह होता है कि आपने अभी तक logout करके फिर से login नहीं किया है। Ubuntu का default ~/.profile केवल तभी ~/.local/bin जोड़ता है जब login के समय वह directory पहले से मौजूद हो, यही कारण है कि यह समस्या नए account पर एक बार आती है और फिर कभी नहीं।
यदि आप pipx को किसी library की ओर point करते हैं, तो वह मना कर देता है और एक संदेश देता है जो इससे शुरू होता है:
No apps associated with package requests or its dependencies.यह tool आपको बता रहा है कि यह गलत instrument है। Libraries को किसी application के venv में होना चाहिए।
सर्वर पर जो विवरण मायने रखता है वह है location। एक साधारण pipx install सब कुछ एक user की home directory के अंतर्गत डाल देता है। myapp के रूप में चलने वाली systemd unit इसे नहीं देख सकती, root cron job इसे नहीं देख सकती, और sudo भी इसे नहीं ढूँढ पाएगा, क्योंकि /etc/sudoers में secure_path, PATH को एक निश्चित list से बदल देता है। ऐसे tool के लिए जिसे पूरी machine पर उपलब्ध होना चाहिए, उसे globally install करें।
sudo pipx install --global ansible
sudo pipx ensurepath --global--global flag environments को /opt/pipx में रखता है और executables को /usr/local/bin में link करता है, जो default PATH पर और secure_path के अंदर होता है। पहले pipx --version के साथ अपना version check करें, क्योंकि Ubuntu 24.04 में pipx 1.4.3 package होता है, जो --global से पुराना है, और पुराना pipx unrecognized arguments: --global के साथ उत्तर देता है। उस version पर, दो documented directories को स्वयं set करें:
sudo env PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install ansible
command -v ansiblecommand -v ansible को /usr/local/bin/ansible print करना चाहिए। यदि यह /home के अंतर्गत कोई path print करता है, तो tool एक single user के account में चला गया है और कोई भी service उसे नहीं ढूँढ पाएगी।
uv जब आपको lockfile की आवश्यकता हो
uv, Astral द्वारा प्रदान की गई एक single binary है जो pip, venv और pip-tools के कार्यों को कवर करती है, और यह interpreters को भी डाउनलोड कर सकती है। यह इतनी तेज है कि एक छोटे VPS पर भी इसका अंतर स्पष्ट दिखाई देता है, और यह एक वास्तविक lockfile लिखती है।
आधिकारिक इंस्टॉलर uv और uvx को ~/.local/bin में डालता है:
curl -LsSf https://astral.sh/uv/install.sh | sh
uv --versionसर्वर पर शेल में स्क्रिप्ट पाइप करना सावधानी की मांग करता है। URL में version को पिन करें और चलाने से पहले फाइल को पढ़ें:
curl -LsSf https://astral.sh/uv/0.12.3/install.sh -o uv-install.sh
less uv-install.sh
sh uv-install.shpipx install uv भी काम करता है, यदि pipx पहले से मौजूद हो। uv एक आत्मनिर्भर binary है जिसकी अपनी कोई Python dependency नहीं है, इसलिए इसे /usr/local/bin में कॉपी करना इसे बॉक्स के हर user के साथ साझा करने का एक वैध तरीका है।
pyproject.toml वाले प्रोजेक्ट के लिए, वर्कफ़्लो में चार कमांड्स शामिल हैं, और केवल अंतिम कमांड सर्वर पर चलती है।
uv init myapp
uv add flask gunicorn
uv lock
uv sync --frozen --no-devuv lock, uv.lock लिखता है, जो एक cross-platform lockfile है जिसमें सटीक resolved versions होते हैं, और आप इसे अपने कोड के साथ commit करते हैं। uv sync इसे मैच करने के लिए प्रोजेक्ट रूट में .venv बनाता है। सर्वर पर, --frozen वह flag है जो मायने रखता है: डॉक्यूमेंटेशन इसे lockfile में मौजूद versions को सत्य का स्रोत मानने के रूप में परिभाषित करता है, बजाय यह जांचने के कि lockfile अप-टू-डेट है या नहीं, जो कि deployment के लिए आवश्यक व्यवहार है। --no-dev डेवलपमेंट dependency ग्रुप को छोड़ देता है।
एक मौजूदा requirements.txt प्रोजेक्ट को किसी रूपांतरण की आवश्यकता नहीं है, क्योंकि uv pip की भाषा समझता है:
uv venv /srv/myapp/.venv
uv pip install --python /srv/myapp/.venv/bin/python -r /srv/myapp/requirements.txtजो परिणाम मिलता है वह एक सामान्य virtual environment है। .venv/bin/python बिल्कुल वैसे ही व्यवहार करता है जैसे कि इसे python3 -m venv ने बनाया हो, इसलिए इस गाइड में बाद की कोई भी चीज़ नहीं बदलती है।
सर्वर पर uv का उपयोग करने से पहले इसके एक डिफ़ॉल्ट व्यवहार को जानना उपयोगी है। इसकी python-preference सेटिंग डिफ़ॉल्ट रूप से managed पर होती है, जिसे सिस्टम पर पहले से मौजूद interpreters के बजाय "uv द्वारा डाउनलोड और इंस्टॉल किए गए" को चुनने के रूप में प्रलेखित किया गया है। इसलिए, जिस बॉक्स में केवल 3.12 है, वहां uv venv --python 3.13 चुपचाप 3.13 को ~/.local/share/uv/python में फेच कर लेता है, बजाय इसके कि वह विफल हो जाए। यह लैपटॉप पर सुविधाजनक है और सर्वर पर आश्चर्यजनक, क्योंकि आपकी सर्विस अब एक ऐसे interpreter पर निर्भर करती है जो home directory में रहता है और जिसे apt upgrade कभी पैच नहीं करेगा। यदि आप डिस्ट्रीब्यूशन के interpreter का उपयोग करना चाहते हैं, तो uv.toml में python-preference को only-system पर सेट करें। यदि आप environment को प्रोजेक्ट रूट के अलावा कहीं और रखना चाहते हैं, तो UV_PROJECT_ENVIRONMENT प्रोजेक्ट virtual environment के लिए उपयोग की जाने वाली डायरेक्टरी को निर्दिष्ट करता है।
systemd को activate script के बजाय venv interpreter पर point करें
Python deployments में अधिकांश त्रुटियाँ यहीं होती हैं, और इसका कारण activate के कार्य को गलत समझना है।
bin/activate एक shell script है। यह venv की bin directory को PATH में सबसे पहले जोड़ती है, VIRTUAL_ENV को set करती है, पुराने मानों को सुरक्षित रखती है ताकि deactivate उन्हें restore कर सके, और आपके prompt को बदलती है। इसमें ऐसा कुछ भी नहीं है जिसे interpreter स्वयं पढ़ता हो। Activation केवल एक human user के लिए सुविधा है जो prompt पर python टाइप करता है।
वास्तव में environment का चयन इस बात से होता है कि आप कौन सी interpreter file execute करते हैं। जब /srv/myapp/.venv/bin/python शुरू होता है, तो Python का site module executable वाली directory और उससे एक स्तर ऊपर pyvenv.cfg file को खोजता है। /srv/myapp/.venv/pyvenv.cfg मिलने पर sys.prefix venv पर set हो जाता है, जो उस venv की site-packages को sys.path पर ले आता है। यही पूरी प्रक्रिया है। इसके लिए किसी environment variable या shell की आवश्यकता नहीं होती।
इसलिए यह unit कभी शुरू नहीं होती:
[Service]
ExecStart=source /srv/myapp/.venv/bin/activate && gunicorn app:appmyapp.service: Failed to locate executable source: No such file or directory
myapp.service: Failed at step EXEC spawning source: No such file or directory
myapp.service: Main process exited, code=exited, status=203/EXECExecStart कोई shell command line नहीं है। systemd सीधे program को execute करता है, इसलिए यहाँ कोई source builtin नहीं होता, && को एक literal argument के रूप में भेजा जाता है, और कुछ भी expand नहीं होता।
और यह unit शुरू होकर तुरंत बंद हो जाती है:
[Service]
ExecStart=/usr/bin/python3 /srv/myapp/app.pyModuleNotFoundError: No module named 'flask'/usr/bin/python3 system का interpreter है, और इसके sys.path में कभी भी आपका venv शामिल नहीं रहा है। वही command आपके SSH session में इसलिए काम करती है क्योंकि आपने वहाँ venv activate किया था, जिससे shell ने python3 को PATH के माध्यम से .venv/bin/python3 में resolve कर लिया था।
Command को /bin/bash -c 'source ... && gunicorn ...' में लपेटना काम करता है। लेकिन यह बिना किसी लाभ के systemd और आपके process के बीच एक shell खड़ा कर देता है, जबकि एक absolute path से यह समस्या हल हो जाती है:
[Unit]
Description=myapp web service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/srv/myapp
Environment=PYTHONUNBUFFERED=1
Environment=PATH=/srv/myapp/.venv/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/srv/myapp/.venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 app:app
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -n 50 --no-pagersystemctl status myapp को active (running) रिपोर्ट करना चाहिए, जिसमें Main PID आपका gunicorn process हो। यदि कुछ और दिखे, तो journal पढ़ें।
Environment=PATH= line ExecStart के लिए नहीं है, क्योंकि उसमें पहले से ही full path होता है। यह उन processes के लिए है जिन्हें आपका application शुरू करता है। एक service को systemd से एक छोटा default PATH मिलता है, इसलिए Python code जो subprocess.run(["ffmpeg", ...]) को call करता है, या कोई management command जो venv के console script को shell out करती है, उसे आवश्यक चीजें नहीं मिलेंगी। venv की bin directory को सबसे पहले रखना activate का वह हिस्सा है जिसका service वास्तव में उपयोग करती है। systemctl show -p Environment myapp के साथ जाँचें कि unit को वास्तव में क्या प्राप्त हुआ।
यही नियम scheduled कार्यों पर भी लागू होता है। cron jobs को PATH के /usr/bin:/bin के साथ चलाता है, इसलिए crontab की एक line जो python3 /srv/myapp/cleanup.py पढ़ती है, वह system interpreter को चलाती है और सुबह तीन बजे ModuleNotFoundError के साथ विफल हो जाती है, और error एक local mail spool में चला जाता है जिसे कोई नहीं पढ़ रहा होता। वहाँ भी absolute venv path लिखें। उस output को journal में प्राप्त करने और अंतिम run का record रखने के लिए, एक systemd service और timer pair में भी वही ExecStart line उपयोग करें।
क्या Docker इस निर्णय की जगह ले लेता है?
एक container का अपना filesystem होता है, इसलिए यह प्रश्न समाप्त होने के बजाय अपना स्वरूप बदल लेता है। python:3.12-slim जैसी official image में, Python को /usr/local में ही build किया जाता है और इसमें कोई EXTERNALLY-MANAGED marker नहीं होता, इसलिए root के रूप में pip install ही packages जोड़ने का सही तरीका है और venv का उपयोग करने से कोई विशेष लाभ नहीं होता। इसके बजाय FROM ubuntu:24.04 build करें और आप image के भीतर फिर से externally-managed-environment का सामना करेंगे, जिसका कारण वही है जो host पर होता है: यह distribution का interpreter है जिसमें distribution की marker file मौजूद है।
कई images अभी भी venv का उपयोग करती हैं, क्योंकि यह multi-stage build को सरल बनाता है। builder stage, /opt/venv में install करती है, और runtime stage केवल उस एक directory को copy करती है और compilers को पीछे छोड़ देती है। activate करने की समस्या इसके साथ ही बनी रहती है। एक RUN source /opt/venv/bin/activate line केवल उस build layer के shell को प्रभावित करती है, इसलिए runtime पर container system interpreter पर start होता है और ModuleNotFoundError error देता है। ENV PATH="/opt/venv/bin:$PATH" set करें, या CMD को absolute path /opt/venv/bin/gunicorn दें। यह systemd वाली समस्या जैसा ही bug है, बस एक अलग file में।
अतः, एक container interpreter वाले प्रश्न को प्रतिस्थापित कर देता है, क्योंकि image interpreter और उसके अंतर्गत आने वाली हर चीज़ को pin कर देती है। यह pinning वाले प्रश्न को प्रतिस्थापित नहीं करता है। एक unpinned requirements.txt से build की गई image अगले महीने अलग versions resolve कर सकती है, जिसका अर्थ है कि image tag तो reproducible है लेकिन वह build नहीं, जिसने इसे बनाया था। uv.lock जैसी lockfile, या पूरी तरह से pinned requirements file, ही वह चीज़ है जो इस कमी को पूरा करती है, चाहे container हो या न हो। और जब एक application systemd के अंतर्गत एक VPS पर चलती है, तो container मुख्य रूप से इस निर्णय को एक Dockerfile में स्थानांतरित कर देता है, क्योंकि systemd पहले से ही एक failed process को restart करता है और उसके output को journal में capture करता है। VPS पर Docker चलाना तब उपयोगी होता है जब आप स्वयं build की गई image को ही deploy करना चाहते हैं।
FAQ
क्या मैं --break-system-packages के साथ pip install का उपयोग कर सकता हूँ?
ऐसे सर्वर पर नहीं जिसे आपको चालू रखना है। यह फ्लैग वही करता है जो इसका नाम बताता है: यह सुरक्षा को हटा देता है, और pip /usr/local/lib/python3.12/dist-packages में लिखता है, जो sys.path पर apt डायरेक्टरी से पहले आता है। इसके बाद आपका वर्ज़न /usr/bin/python3 के तहत चलने वाली हर सिस्टम स्क्रिप्ट के लिए डिस्ट्रीब्यूशन के वर्ज़न को ओवरराइड (shadow) कर देता है। apt को अभी भी यही लगता है कि उसका अपना वर्ज़न इंस्टॉल है, इसलिए जब तक कुछ खराब नहीं होता, तब तक इस कॉन्फ्लिक्ट का पता नहीं चलता। कंटेनर इमेज के अंदर जिसे आप हर बार स्क्रैच से रीबिल्ड करते हैं, वहाँ नुकसान केवल उसी इमेज तक सीमित रहता है, इसलिए वहाँ इसका उपयोग तर्कसंगत है। जिस मशीन को आप मेंटेन करते हैं, उस पर venv बनाएँ। यह केवल एक कमांड का काम है।
सर्वर पर वर्चुअल एनवायरनमेंट कहाँ होना चाहिए?
एप्लीकेशन की अपनी डायरेक्टरी के अंदर, /srv/myapp/.venv के रूप में, जिसका ओनर एक डिप्लॉय यूजर हो, और सर्विस अकाउंट के पास केवल रीड और एक्जीक्यूट एक्सेस हो। प्रति एप्लीकेशन एक venv रखें, क्योंकि साझा venv का मतलब है कि एक एप्लीकेशन का अपग्रेड दूसरी को खराब कर सकता है। venv बनाने के बाद उसे मूव या कॉपी न करें: इसकी bin/ डायरेक्टरी की हर स्क्रिप्ट में वह एब्सोल्यूट पाथ उसकी shebang लाइन में लिखा होता है, इसलिए मूव किया गया venv bad interpreter: No such file or directory के साथ फेल हो जाता है। इसे डिलीट करें और इसके बजाय requirements.txt से रीबिल्ड करें।
मेरी systemd सर्विस ModuleNotFoundError के साथ फेल क्यों हो रही है?
क्योंकि यूनिट उस इंटरप्रेटर को एक्जीक्यूट कर रही है जो venv का नहीं है। systemctl cat myapp चलाएँ और ExecStart पढ़ें। इसमें एब्सोल्यूट पाथ के साथ /srv/myapp/.venv/bin/python, या उसी bin/ डायरेक्टरी की कोई कंसोल स्क्रिप्ट का नाम होना चाहिए। यूनिट फाइल में activate को सोर्स करना काम नहीं करेगा, क्योंकि ExecStart एक शेल नहीं है, और systemd status=203/EXEC के साथ Failed to locate executable source रिपोर्ट करता है। Environment=PATH=/srv/myapp/.venv/bin:/usr/local/bin:/usr/bin:/bin जोड़ें ताकि आपका कोड जो भी सबप्रोसेस शुरू करे, उसे भी venv के टूल्स मिल सकें।
क्या मुझे venv और pip के बजाय uv का उपयोग करना चाहिए?
uv का उपयोग तब करें जब आपको लॉकफाइल चाहिए हो, जब इंस्टॉलेशन का समय आपको परेशान करने वाला हो, या जब आपको ऐसे Python वर्ज़न की आवश्यकता हो जो आपका डिस्ट्रीब्यूशन प्रदान नहीं करता। यह एक सामान्य venv बनाता है, इसलिए systemd यूनिट और फाइल लेआउट में कोई बदलाव नहीं होता, और uv sync --frozen वही इंस्टॉल करता है जो लॉकफाइल में दर्ज है। यदि कोई सिंगल एप्लीकेशन पिन की गई requirements.txt के साथ git से डिप्लॉय होती है और इंस्टॉलेशन सेकंडों में पूरा हो जाता है, तो python3 -m venv पर्याप्त है, और यह सर्वर पर अपडेट रखने के लिए एक कम बाइनरी है।