SSD Nodes Learn 🎉 VPS $5.50/மாதம் முதல்
கல்வி வழிகாட்டிகள் Matt Connorஆல் Matt Connor · புதுப்பிக்கப்பட்டது 2026-08-13

Ubuntu server-ல் venv, pipx மற்றும் uv: எதை தேர்வு

Ubuntu-வில் pip install தோல்வியடையும் externally-managed-environment பிழையை சரிசெய்ய venv, pipx அல்லது uv ஆகியவற்றை எவ்வாறு பயன்படுத்துவது என்பதை இந்த வழிகாட்டி விளக்குகிறது.

புதிய Ubuntu server-ல் pip install ஏன் தோல்வியடைகிறது

ஒரு server-ல் Python venv, pipx மற்றும் uv ஆகியவற்றில் எதைத் தேர்ந்தெடுப்பது என்பது ஒரு கேள்வியைப் பொறுத்தது: நீங்கள் எதை நிறுவுகிறீர்கள்? ஒரு application-ன் dependencies அந்த application-ன் சொந்த directory-க்குள் இருக்கும் virtual environment-ல் இருக்க வேண்டும். நீங்கள் பெயரைக் குறிப்பிட்டு இயக்க விரும்பும் command-line கருவிகள் pipx-ல் இருக்க வேண்டும். uv இந்த இரண்டு வேலைகளையும் செய்கிறது, மேலும் இது ஒரு lockfile-ஐயும் சேர்க்கிறது; இரண்டாவது machine-ல் அதே environment-ஐ உருவாக்க வேண்டிய சூழலில் இது முக்கியத்துவம் பெறுகிறது. இவை எவையும் system Python-ல் நிறுவுவதில்லை, ஏனெனில் தற்போதைய Ubuntu server அதை முற்றிலுமாகத் தடுக்கிறது.

Ubuntu 24.04-ல் sudo pip install requests-ஐ இயக்கினால், ஒரு கோப்பைக் கூட பதிவிறக்கம் செய்வதற்கு முன்பே pip நின்றுவிடும்.

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 கோப்பை வைக்கின்றன, அந்த marker கோப்பைக் கொண்ட எந்தவொரு interpreter-லும் எழுத pip மறுத்துவிடுகிறது.

இந்த விதி sys.path வரிசை காரணமாகவே உள்ளது. apt நூலகங்களை /usr/lib/python3/dist-packages-ல் நிறுவுகிறது. 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 எழுதிய நகல், apt நிறுவிய நகலை மறைத்துவிடுகிறது (shadows); /usr/bin/python3-ன் கீழ் இயங்கும் அந்த box-ல் உள்ள ஒவ்வொரு நிரலுக்கும் இது பொருந்தும், இதில் distribution-ன் சொந்த கருவிகளும் அடங்கும். cloud-init அந்த interpreter-லிருந்து requests, jinja2 மற்றும் PyYAML ஆகியவற்றை import செய்கிறது. pip மூலம் அவற்றில் ஒன்றை upgrade செய்து, பொருந்தாத ஒரு release-க்குச் சென்றால், நீங்கள் தொடாத ஏதோ ஒன்று அடுத்த boot-ன் போது தோல்வியடையும்; அந்தச் சங்கிலியில் இருந்ததாக உங்களுக்குத் தெரியாத ஒரு package-ன் traceback-ஐ அது காட்டும். apt தனது சொந்த version-ஐ நிறுவியதாகவே பதிவு செய்திருக்கும், எனவே எதுவும் உங்களை எச்சரிக்காது, மேலும் அதைச் சரிசெய்வது sudo apt reinstall python3-requests ஆகும்.

இதனைத் தொடர்ந்து வரும் விதி சுருக்கமானது. system Python என்பது distribution-க்குச் சொந்தமானது. அதில் எதையும் நிறுவ வேண்டாம், pip மூலம் அதன் நூலகங்களை upgrade செய்ய வேண்டாம், மேலும் அந்தச் செய்தியை நீக்குவதற்காக EXTERNALLY-MANAGED கோப்பை நீக்க வேண்டாம். /usr/bin/python3-க்கு நீங்கள் கொடுக்க வேண்டிய ஒரே வேலை virtual environments-ஐ உருவாக்குவது மட்டுமே.

venv vs pipx vs uv: முடிவெடுப்பதற்கான விதி

நீங்கள் எதை நிறுவுகிறீர்கள் என்பதைப் பொறுத்து கருவியைத் தேர்ந்தெடுக்கவும்; சமீபத்தில் எதைப் பற்றி படித்தீர்கள் என்பதை வைத்து முடிவெடுக்க வேண்டாம்.

  • நீங்கள் ஒரு service-ஆக deploy செய்து இயக்கும் application (உதாரணமாக Django அல்லது Flask project): அந்த application-ன் directory-க்குள் ஒரு virtual environment (venv) பயன்படுத்தவும்.
  • உங்கள் PATH-ல் இருக்க வேண்டிய command-line tool (உதாரணமாக ansible அல்லது httpie): pipx பயன்படுத்தவும். இது ஒவ்வொரு tool-க்கும் ஒரு தனிப்பட்ட environment-ஐ உருவாக்கி, PATH-ல் ஒரு link-ஐ வழங்கும்.
  • lockfile, வேகமான installation அல்லது distribution-ல் இல்லாத Python version தேவைப்படும் project: uv பயன்படுத்தவும். இது ஒரு சாதாரண venv மற்றும் ஒரு uv.lock கோப்பை உருவாக்கும்.
  • உங்கள் code-க்குத் தேவைப்படாமல், ஒரு distribution tool-க்குத் தேவைப்படும் library: sudo apt install python3-<name> பயன்படுத்தவும். இது மட்டுமே system interpreter-ல் எதையும் சேர்ப்பதற்கான அங்கீகரிக்கப்பட்ட வழியாகும்.

pipx மற்றும் uv tool install ஆகிய இரண்டும் ஒரே வேலையைச் செய்கின்றன, எனவே uv ஏற்கனவே உள்ள ஒரு கணினியில் pipx தேவையில்லை. நீங்கள் எந்த web framework-ஐத் தேர்ந்தெடுத்தாலும் இதில் மாற்றம் இல்லை: VPS-ல் Django மற்றும் Flask என்பவை requirements.txt-ல் என்ன சேமிக்கப்படுகிறது என்பதில் மாறுபடுமே தவிர, அதைச் சுற்றியுள்ள environment எவ்வாறு கட்டமைக்கப்படுகிறது என்பதில் மாறுபடாது. கீழே உள்ள அனைத்தும் Ubuntu 24.04 மற்றும் அதன் Python 3.12-ஐப் பயன்படுத்துகின்றன, எனவே உங்களுடையது வேறாக இருந்தால் paths-ல் உள்ள version-ஐ மாற்றிக்கொள்ளவும்.

ஒவ்வொரு application-க்கும் தனித்தனி venv உருவாக்குதல்

Ubuntu-வில் venv module அடிப்படை Python package-லிருந்து பிரிக்கப்பட்டுள்ளது. எனவே, minimal image-ல் முதல்முறை முயற்சிக்கும்போது, தேவையான module இல்லை என்ற பிழைச் செய்தியுடன் செயல்முறை தோல்வியடையும்.

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

முதலில் அந்த module-ஐ install செய்யவும். பிறகு, அந்த code-க்கு உரிமையாளராக இருக்கும் user-ஐக் கொண்டு 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-க்குள் install ஆகிறது; இதற்குக் காரணம் binary இருக்கும் இடமே தவிர, நீங்கள் shell-ல் export செய்த எதுவும் அல்ல. அடுத்த கட்டத்திற்குச் செல்லும் முன் இதை உறுதிப்படுத்தவும்.

/srv/myapp/.venv/bin/python -c 'import sys; print(sys.prefix)'

இது /srv/myapp/.venv என்பதை அச்சிடும். ஒருவேளை இது /usr என்று அச்சிட்டால், நீங்கள் system interpreter-ஐ இயக்குகிறீர்கள் என்று அர்த்தம். அப்போது உங்கள் packages நீங்கள் விரும்பாத இடத்திற்குச் சென்றுவிட்டன.

ஒரு venv-ன் இரண்டு பண்புகள், அதன் பிறகு நீங்கள் என்ன செய்ய முடியும் என்பதைத் தீர்மானிக்கின்றன. ஒரு venv-ஐ ஓரிடத்திலிருந்து மற்றோர் இடத்திற்கு மாற்ற முடியாது (not relocatable). ஏனெனில், bin/-ல் உள்ள ஒவ்வொரு script-ம் ஒரு absolute shebang line-ஐக் கொண்டிருக்கும்: head -1 /srv/myapp/.venv/bin/pip என்பது #!/srv/myapp/.venv/bin/python-ஐ வாசிக்கும். அதன் parent directory-ஐப் பெயர் மாற்றினால், அந்த scripts bad interpreter: No such file or directory பிழையுடன் தோல்வியடையும். மேலும், ஒரு venv அதை உருவாக்கிய interpreter-ஐயே சார்ந்திருக்கும். இது /srv/myapp/.venv/pyvenv.cfg-ல் உள்ள home வரியில் பதிவாகியிருக்கும், மேலும் bin/python3 என்பது அந்த binary-க்கான symlink ஆகும். நீங்கள் OS release-ஐ upgrade செய்து python3.12 நீக்கப்பட்டால், அந்த symlink-க்கு இலக்கு இருக்காது; service தொடங்கும்போது No such file or directory பிழையுடன் நின்றுவிடும். இரண்டு சூழல்களுக்கும் ஒரே தீர்வுதான்: அந்த venv-ஐ நீக்கிவிட்டு, requirements.txt-லிருந்து புதிய ஒன்றை உருவாக்க வேண்டும். மீண்டும் உருவாக்குவதற்குச் சில நொடிகள் மட்டுமே ஆகும். ஒரு venv-ஐ ஒரு machine-லிருந்து மற்றொன்றுக்கு ஒருபோதும் நகல் எடுக்காதீர்கள்.

venv எங்கு இருக்க வேண்டும் மற்றும் அதன் உரிமையாளர் யார்

/srv/myapp/.venv-ல் உள்ள குறியீட்டிற்கு அருகிலேயே அதை வைக்கவும், ஒவ்வொரு application-க்கும் ஒரு venv-ஐப் பயன்படுத்தவும். இவ்வாறு செய்வதால் deployment ஒரு ஒற்றை directory-ஆக இருக்கும், systemd unit மாறாத ஒரு path-ஐப் பெறும், மேலும் இரண்டு application-கள் ஒரு பகிரப்பட்ட dependency upgrade மூலம் ஒன்றையொன்று பாதிக்காது. உங்கள் web server நேரடியாக files-ஐ வெளியிடும் எந்த இடத்திலும் venv-ஐ வைக்க வேண்டாம், ஏனெனில் அதில் உங்கள் dependencies மற்றும் பெரும்பாலும் configuration-கள் இருக்கும்.

உரிமையாளர் (ownership) குறித்து அரை நிமிடம் கவனிக்க வேண்டும். ஒரு deploy பயனர் குறியீடு மற்றும் environment-ஐ வைத்திருக்கட்டும், 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-ஐ இறக்குமதி செய்ய முடியும், ஆனால் அவற்றை மாற்றியமைக்க முடியாது. அதாவது, web application-ல் உள்ள ஒரு code execution bug, வட்டில் (disk) உள்ள ஒரு library-ஐ ரகசியமாக மாற்றி, restart செய்த பிறகும் நிலைத்திருக்க முடியாது. கணினியின் பிற பகுதிகளுக்கும் இதே தர்க்கத்தைப் பயன்படுத்துவது குறைந்தபட்ச சலுகை கொண்ட பயனர்களாக service-களை இயக்குதல் பகுதியில் விளக்கப்பட்டுள்ளது.

command-line கருவிகளுக்கான pipx

pipx என்பது libraries-ஐ அல்ல, applications-ஐ நிறுவுகிறது. ஒவ்வொரு கருவியும் ~/.local/share/pipx/venvs/<name>-ன் கீழ் தனித்தனி சூழலைப் பெறுகிறது, மேலும் அந்தக் கருவியின் executables ~/.local/bin-ல் இணைக்கப்படுகின்றன. இதனால், ஒரே library-ன் வெவ்வேறு பதிப்புகள் தேவைப்படும் இரண்டு கருவிகளுக்கு இடையே மோதல் ஏற்படாது.

sudo apt update
sudo apt install -y pipx
pipx ensurepath
pipx install httpie

pipx ensurepath, உங்கள் shell startup கோப்பைத் திருத்துவதன் மூலம் ~/.local/bin-ஐ PATH-ல் சேர்க்கிறது. இது நீங்கள் தற்போது பயன்படுத்தும் shell-ஐ மாற்ற முடியாது, எனவே நிறுவிய பின் http: command not found என்று வந்தால், நீங்கள் இன்னும் logout செய்து மீண்டும் login செய்யவில்லை என்று அர்த்தம். Ubuntu-வின் இயல்புநிலை ~/.profile, login-ன் போது அந்த directory ஏற்கனவே இருந்தால் மட்டுமே ~/.local/bin-ஐச் சேர்க்கும். இதனால்தான் புதிய கணக்குகளில் இது ஒருமுறை மட்டும் சிக்கலை ஏற்படுத்துகிறது.

ஒரு library-ஐ pipx மூலம் நிறுவ முயன்றால், அது பின்வரும் செய்தியுடன் மறுத்துவிடும்:

No apps associated with package requests or its dependencies.

இது தவறான கருவியைப் பயன்படுத்துகிறீர்கள் என்பதை உங்களுக்கு உணர்த்துகிறது. Libraries ஒரு application-ன் venv-க்குள் இருக்க வேண்டும்.

server-ல் கவனிக்க வேண்டிய முக்கியமான விஷயம் அதன் இருப்பிடம். சாதாரண pipx install கட்டளை, அனைத்தையும் ஒரு பயனர் home directory-க்குள் வைக்கிறது. myapp-ஆக இயங்கும் systemd unit-ஆல் அதைப் பார்க்க முடியாது, root cron job-ஆல் அதைப் பார்க்க முடியாது, மேலும் sudo-ஆலும் அதைக் கண்டறிய முடியாது. ஏனெனில் /etc/sudoers-ல் உள்ள secure_path, PATH-ஐ ஒரு நிலையான பட்டியலைக் கொண்டு மாற்றுகிறது. முழு இயந்திரத்திற்கும் பயன்படும் ஒரு கருவிக்கு, அதை globally நிறுவவும்.

sudo pipx install --global ansible
sudo pipx ensurepath --global

--global flag, சூழல்களை /opt/pipx-லும், executables-ஐ /usr/local/bin-லும் வைக்கிறது. இது இயல்புநிலை PATH-லும் secure_path-க்கு உள்ளேயும் உள்ளது. முதலில் pipx --version மூலம் உங்கள் பதிப்பைச் சரிபார்க்கவும், ஏனெனில் Ubuntu 24.04-ல் pipx 1.4.3 பதிப்பு உள்ளது, இது --global-ஐ விட பழையது. பழைய pipx பதிப்புகள் unrecognized arguments: --global என்று பதிலளிக்கும். அந்தப் பதிப்பில், ஆவணப்படுத்தப்பட்ட இரண்டு directories-ஐயும் நீங்களே அமைக்கவும்:

sudo env PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install ansible
command -v ansible

command -v ansible கட்டளை /usr/local/bin/ansible என்று அச்சிட வேண்டும். அது /home-க்கு கீழ் ஒரு பாதையைக் காட்டினால், அந்தக் கருவி ஒரு பயனர் கணக்கிற்குள் சென்றுவிட்டது என்று அர்த்தம்; எந்த service-ஆலும் அதைக் கண்டறிய முடியாது.

lockfile தேவைப்படும்போது uv-ஐப் பயன்படுத்துதல்

uv என்பது Astral நிறுவனத்தின் ஒற்றை binary கோப்பாகும். இது pip, venv மற்றும் pip-tools ஆகியவற்றின் பணிகளை ஒருங்கிணைத்துச் செய்கிறது; மேலும், இது Python interpreters-ஐயும் தரவிறக்கம் செய்யக்கூடியது. சிறிய VPS-ல் கூட இதன் வேகம் குறிப்பிடத்தக்க மாற்றத்தை ஏற்படுத்தும், மேலும் இது முறையான lockfile-ஐ உருவாக்குகிறது.

இதன் அதிகாரப்பூர்வ installer, uv மற்றும் uvx ஆகியவற்றை ~/.local/bin-ல் நிறுவுகிறது:

curl -LsSf https://astral.sh/uv/install.sh | sh
uv --version

ஒரு server-ல் script-ஐ நேரடியாக shell-க்கு pipe செய்வது கவனமாகச் செய்யப்பட வேண்டிய செயல். URL-ல் உள்ள version-ஐ pin செய்து, இயக்குவதற்கு முன் கோப்பை வாசித்துப் பார்க்கவும்:

curl -LsSf https://astral.sh/uv/0.12.3/install.sh -o uv-install.sh
less uv-install.sh
sh uv-install.sh

ஏற்கனவே pipx இருந்தால் pipx install uv மூலமும் இதை நிறுவலாம். uv என்பது எவ்வித Python dependency-யும் இல்லாத ஒரு தனித்த binary என்பதால், அதை /usr/local/bin-க்கு நகலெடுப்பது அந்த server-ல் உள்ள அனைத்து பயனர்களுக்கும் அதைப் பகிர்ந்தளிக்க ஒரு சரியான வழியாகும்.

pyproject.toml கொண்ட ஒரு project-க்கு, நான்கு கட்டளைகள் கொண்ட workflow-ஐப் பின்பற்ற வேண்டும்; இதில் கடைசி கட்டளை மட்டுமே server-ல் இயங்கும்.

uv init myapp
uv add flask gunicorn
uv lock
uv sync --frozen --no-dev

uv lock என்பது uv.lock-ஐ உருவாக்குகிறது. இது துல்லியமான resolved versions-ஐக் கொண்ட ஒரு cross-platform lockfile ஆகும்; இதை உங்கள் code-உடன் சேர்த்து commit செய்ய வேண்டும். uv sync, lockfile-க்கு ஏற்ப project root-ல் .venv-ஐ உருவாக்குகிறது. Server-ல், --frozen என்ற flag மிக முக்கியமானது: lockfile-ஐச் சரிபார்ப்பதற்குப் பதிலாக, அதில் உள்ள versions-ஐயே ஆதாரமாகக் கொண்டு இது செயல்படும் என்று ஆவணங்கள் குறிப்பிடுகின்றன; deployment-க்கு இதுவே தேவையான செயல்பாடாகும். --no-dev, development dependency group-ஐத் தவிர்க்கிறது.

ஏற்கனவே உள்ள requirements.txt project-க்கு எவ்வித மாற்றமும் தேவையில்லை, ஏனெனில் 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 உருவாக்கியது போலவே செயல்படும், எனவே இந்த வழிகாட்டியின் பிற்பகுதிகளில் எவ்வித மாற்றமும் இல்லை.

Server-ல் uv-ஐப் பயன்படுத்தும் முன் அதன் ஒரு default அமைப்பைத் தெரிந்துகொள்வது அவசியம். அதன் python-preference அமைப்பு default-ஆக managed என்று இருக்கும். இது, ஏற்கனவே system-ல் உள்ள interpreters-ஐ விட "uv மூலம் தரவிறக்கம் செய்யப்பட்டு நிறுவப்பட்டவற்றை" முன்னுரிமைப்படுத்தித் தேர்ந்தெடுக்கும். எனவே, 3.12 மட்டும் உள்ள ஒரு server-ல் uv venv --python 3.13 என்று கொடுத்தால், அது தோல்வியடையாமல் ~/.local/share/uv/python-க்குள் 3.13-ஐத் தரவிறக்கம் செய்யும். இது laptop-க்கு வசதியானது, ஆனால் server-ல் இது ஆச்சரியத்தைத் தரும்; ஏனெனில் உங்கள் service இப்போது home directory-ல் உள்ள ஒரு interpreter-ஐச் சார்ந்து இயங்கும், அதை apt upgrade ஒருபோதும் patch செய்யாது. உங்களுக்கு distribution-ன் interpreter தேவைப்பட்டால், uv.toml-ல் python-preference-ஐ only-system என அமைக்கவும். Project root-க்கு வெளியே environment அமைய வேண்டுமெனில், project virtual environment-க்காகப் பயன்படுத்த வேண்டிய directory-ஐ UV_PROJECT_ENVIRONMENT மூலம் குறிப்பிடலாம்.

systemd-ஐ activate script-க்கு பதிலாக venv interpreter-க்கு சுட்டிக்காட்டவும்

Python deployments-ல் பெரும்பாலானவை இங்குதான் தோல்வியடைகின்றன. activate எதைச் செய்கிறது என்பதைத் தவறாகப் புரிந்துகொள்வதே இதற்குக் காரணம்.

bin/activate என்பது ஒரு shell script ஆகும். இது venv-ன் bin கோப்பகத்தை PATH-க்கு முன்னால் சேர்க்கிறது, VIRTUAL_ENV-ஐ அமைக்கிறது, பழைய மதிப்புகளைச் சேமித்து வைக்கிறது (இதனால் deactivate அவற்றை மீண்டும் கொண்டுவர முடியும்), மேலும் உங்கள் prompt-ஐ மாற்றுகிறது. இதில் interpreter நேரடியாக வாசிக்கும் எந்தத் தகவலும் இல்லை. ஒரு பயனர் prompt-ல் python என்று தட்டச்சு செய்யும்போது வசதிக்காக மட்டுமே இந்த activation பயன்படுகிறது.

எந்த interpreter கோப்பை நீங்கள் இயக்குகிறீர்கள் என்பதுதான் எந்த environment பயன்படுத்தப்பட வேண்டும் என்பதைத் தீர்மானிக்கிறது. /srv/myapp/.venv/bin/python தொடங்கும்போது, Python-ன் site module, executable இருக்கும் கோப்பகத்திலும் அதற்கு ஒரு நிலை மேலேயும் pyvenv.cfg கோப்பைத் தேடும். /srv/myapp/.venv/pyvenv.cfg-ஐக் கண்டறிந்தால், அது sys.prefix-ஐ அந்த venv-க்கு அமைக்கும். இது அந்த venv-ன் site-packages-ஐ sys.path-ல் சேர்க்கிறது. இதுவே முழுமையான செயல்முறை. இதற்கு எந்த environment variable-ம் அல்லது shell-ம் தேவையில்லை.

எனவே, இந்த unit ஒருபோதும் தொடங்காது:

[Service]
ExecStart=source /srv/myapp/.venv/bin/activate && gunicorn app:app
myapp.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/EXEC

ExecStart என்பது shell command line அல்ல. systemd ஒரு நிரலை நேரடியாக இயக்குகிறது. எனவே, அங்கு source builtin கிடையாது, && ஒரு literal argument-ஆகவே எடுத்துக்கொள்ளப்படும், மேலும் எதுவும் விரிவுபடுத்தப்படாது (expand ஆகாது).

இந்த unit தொடங்குகிறது, ஆனால் உடனே நின்றுவிடுகிறது:

[Service]
ExecStart=/usr/bin/python3 /srv/myapp/app.py
ModuleNotFoundError: No module named 'flask'

/usr/bin/python3 என்பது system interpreter ஆகும். அதன் sys.path-ல் உங்கள் venv இருந்ததில்லை. உங்கள் SSH session-ல் அதே command வேலை செய்கிறது என்றால், அதற்கு நீங்கள் அங்கு venv-ஐ activate செய்திருந்ததுதான் காரணம். அதனால் shell python3-ஐ PATH வழியாக .venv/bin/python3 என்று கண்டறிந்தது.

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.target
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -n 50 --no-pager

systemctl status myapp கட்டளையானது active (running)-ஐக் காட்ட வேண்டும், அதில் Main PID உங்கள் gunicorn process-ஆக இருக்க வேண்டும். வேறு ஏதேனும் இருந்தால், journal-ஐ வாசிக்கவும்.

Environment=PATH= வரி ExecStart-க்காக அங்கு இல்லை, ஏனெனில் அது ஏற்கனவே முழுமையான பாதையைக் கொண்டுள்ளது. இது உங்கள் application தொடங்கும் பிற process-களுக்காக உள்ளது. ஒரு service, systemd-லிருந்து ஒரு குறுகிய default PATH-ஐப் பெறுகிறது. எனவே, subprocess.run(["ffmpeg", ...])-ஐ அழைக்கும் Python code அல்லது venv-ல் உள்ள console script-ஐ இயக்கும் management command-களால் தங்களுக்குத் தேவையானவற்றைக் கண்டறிய முடியாது. venv-ன் bin கோப்பகத்தை முதலில் வைப்பதுதான், ஒரு service உண்மையில் பயன்படுத்தும் activate-ன் ஒரே பகுதி. systemctl show -p Environment myapp மூலம் unit உண்மையில் எதைப் பெற்றது என்பதைச் சரிபார்க்கவும்.

இதே விதி திட்டமிடப்பட்ட பணிகளுக்கும் (scheduled work) பொருந்தும். cron வேலைகளை /usr/bin:/bin என்ற PATH-ல் இயக்குகிறது. எனவே, python3 /srv/myapp/cleanup.py என்றுள்ள crontab வரி system interpreter-ஐ இயக்கி, அதிகாலை மூன்று மணிக்கு ModuleNotFoundError பிழையுடன் தோல்வியடையும். அந்தப் பிழை யாரும் கவனிக்காத local mail spool-க்குச் சென்றுவிடும். அங்கும் venv-ன் முழுமையான பாதையை எழுதவும். அந்த output-ஐ journal-ல் பெறவும், கடைசி இயக்கத்தைப் பதிவு செய்யவும், systemd service மற்றும் timer ஜோடியைப் பயன்படுத்தவும். அதுவும் அதே ExecStart வரியையே பயன்படுத்துகிறது.

Docker இந்த முடிவை மாற்றியமைக்கிறதா?

ஒரு container தனக்கென ஒரு filesystem-ஐக் கொண்டுள்ளது, எனவே இந்த கேள்வி மறைவதற்குப் பதிலாக அதன் வடிவம் மாறுகிறது. python:3.12-slim போன்ற ஒரு official image-ல், Python ஆனது /usr/local-க்குள் கட்டமைக்கப்பட்டுள்ளது மற்றும் அதில் எந்த EXTERNALLY-MANAGED குறியீடும் இல்லை. எனவே, packages-ஐச் சேர்க்க pip install-ஐ root பயனராகப் பயன்படுத்துவதே சரியான முறையாகும், மேலும் venv-ஆல் பெரிய பயன் ஏதுமில்லை. அதற்குப் பதிலாக FROM ubuntu:24.04-ஐ உருவாக்கினால், host-ல் உள்ள அதே காரணத்திற்காக, image-க்குள்ளும் externally-managed-environment-ஐ நீங்கள் சந்திப்பீர்கள்: இது அந்த distribution-ன் interpreter மற்றும் அது அந்த distribution-ன் marker file-ஐக் கொண்டுள்ளது.

பல images இப்போதும் venv-ஐப் பயன்படுத்துகின்றன, ஏனெனில் இது multi-stage build-ஐ எளிதாக்குகிறது. Builder stage-ஆனது /opt/venv-ல் installation-ஐச் செய்கிறது, runtime stage அந்த directory-ஐ மட்டும் நகலெடுத்துக்கொண்டு compilers-ஐ விட்டுவிடுகிறது. Activate தொடர்பான சிக்கல் இதிலும் தொடர்கிறது. ஒரு RUN source /opt/venv/bin/activate வரி அந்த build layer-ன் shell-ஐ மட்டுமே பாதிக்கும், எனவே runtime-ல் container system interpreter-ல் தொடங்கி ModuleNotFoundError பிழையை ஏற்படுத்தும். ENV PATH="/opt/venv/bin:$PATH"-ஐ அமைக்கவும், அல்லது CMD-க்கு /opt/venv/bin/gunicorn என்ற absolute path-ஐ வழங்கவும். இது systemd-ல் உள்ள அதே பிழைதான், ஆனால் வேறொரு கோப்பில் உள்ளது.

எனவே, ஒரு container interpreter குறித்த கேள்வியை மாற்றுகிறது, ஏனெனில் image-ஆனது interpreter-ஐயும் அதற்குக்கீழ் உள்ள அனைத்தையும் pin செய்கிறது. ஆனால் இது pinning குறித்த கேள்வியை மாற்றாது. Pin செய்யப்படாத requirements.txt-லிருந்து உருவாக்கப்பட்ட ஒரு image, அடுத்த மாதம் வெவ்வேறு versions-ஐ resolve செய்யும். அதாவது, அந்த image-ஐ உருவாக்கிய build reproducible-ஆக இருக்காது, ஆனால் image tag மட்டும் அப்படியே இருக்கும். uv.lock போன்ற ஒரு lockfile அல்லது முழுமையாக pin செய்யப்பட்ட requirements file மட்டுமே இந்த இடைவெளியை நிரப்பும், container இருந்தாலும் இல்லாவிட்டாலும் இது பொருந்தும். ஒரு application systemd-ன் கீழ் ஒரு VPS-ல் இயங்கும்போது, container இந்த முடிவை ஒரு Dockerfile-க்கு மாற்றுகிறது, ஏனெனில் systemd ஏற்கனவே தோல்வியுற்ற process-ஐ restart செய்து அதன் output-ஐ journal-ல் சேமிக்கிறது. VPS-ல் Docker-ஐ இயக்குதல் என்பது, நீங்கள் உருவாக்கிய image-ஐயே deploy செய்ய விரும்பும்போது பயனுள்ளதாக இருக்கும்.

FAQ

நான் --break-system-packages உடன் pip install-ஐப் பயன்படுத்தலாமா?

தொடர்ந்து இயங்க வேண்டிய server-ல் இதைப் பயன்படுத்த வேண்டாம். இந்த flag அதன் பெயருக்கேற்ப செயல்படுகிறது: இது பாதுகாப்பை நீக்குகிறது, மேலும் pip ஆனது /usr/local/lib/python3.12/dist-packages-ல் கோப்புகளை எழுதுகிறது. இது sys.path-ல் உள்ள apt directory-க்கு முன்னதாகவே முன்னுரிமை பெறுகிறது. இதனால் /usr/bin/python3-ன் கீழ் இயங்கும் ஒவ்வொரு system script-க்கும் உங்கள் version-ஆனது distribution-ன் version-ஐ மறைத்துவிடும் (shadowing). apt தனது சொந்த version-தான் நிறுவப்பட்டிருப்பதாகக் கருதும், எனவே ஏதேனும் ஒன்று பழுதாகும் வரை இந்த முரண்பாடு கண்டறியப்படாது. ஒவ்வொரு முறையும் புதிதாக உருவாக்கும் container image-க்குள் இதைப் பயன்படுத்தினால், பாதிப்பு அந்த image-உடன் முடிந்துவிடும், எனவே அங்கு இது ஏற்றுக்கொள்ளத்தக்கது. நீங்கள் பராமரிக்கும் ஒரு machine-ல், venv-ஐ உருவாக்குங்கள். அது ஒரே ஒரு command-தான்.

Server-ல் virtual environment எங்கே இருக்க வேண்டும்?

Application-ன் சொந்த directory-க்குள், /srv/myapp/.venv என்ற பெயரில் இருக்க வேண்டும். இது deploy user-ன் உரிமையில் இருக்க வேண்டும், service account-க்கு வாசிப்பதற்கும் (read) இயக்குவதற்கும் (execute) மட்டுமே அனுமதி இருக்க வேண்டும். ஒவ்வொரு application-க்கும் தனித்தனி venv-ஐப் பராமரியுங்கள், ஏனெனில் பகிரப்பட்ட venv-ல் ஒரு application-ஐ upgrade செய்வது மற்றொன்றைப் பாதிக்கலாம். ஒரு venv-ஐ உருவாக்கிய பிறகு அதை நகர்த்தவோ அல்லது நகல் எடுக்கவோ வேண்டாம்: அதன் bin/ directory-ல் உள்ள ஒவ்வொரு script-ன் shebang வரியிலும் அந்த absolute path எழுதப்பட்டிருக்கும். எனவே நகர்த்தப்பட்ட venv bad interpreter: No such file or directory பிழையுடன் தோல்வியடையும். அதற்குப் பதிலாக அதை நீக்கிவிட்டு requirements.txt மூலம் மீண்டும் உருவாக்குங்கள்.

எனது systemd service ஏன் ModuleNotFoundError பிழையைக் காட்டுகிறது?

ஏனெனில் அந்த unit, venv-க்குச் சொந்தமில்லாத ஒரு interpreter-ஐ இயக்குகிறது. systemctl cat myapp-ஐ இயக்கி ExecStart-ஐப் படியுங்கள். அது /srv/myapp/.venv/bin/python-ஐ அல்லது அதே bin/ directory-ல் உள்ள ஒரு console script-ஐ absolute path மூலம் குறிப்பிட வேண்டும். Unit file-ல் activate-ஐ source செய்வது வேலை செய்யாது, ஏனெனில் ExecStart ஒரு shell அல்ல, மேலும் systemd status=203/EXEC உடன் Failed to locate executable source பிழையைப் புகாரளிக்கும். Environment=PATH=/srv/myapp/.venv/bin:/usr/local/bin:/usr/bin:/bin-ஐச் சேர்க்கவும், அப்போதுதான் உங்கள் code தொடங்கும் எந்தவொரு subprocess-ம் venv-ன் கருவிகளைக் கண்டறியும்.

நான் venv மற்றும் pip-க்கு பதிலாக uv-ஐப் பயன்படுத்த வேண்டுமா?

உங்களுக்கு lockfile தேவைப்படும்போது, நிறுவல் நேரம் (install time) அதிகமாக இருக்கும்போது, அல்லது உங்கள் distribution-ல் இல்லாத Python version தேவைப்படும்போது uv-ஐப் பயன்படுத்துங்கள். இது ஒரு சாதாரண venv-ஐ உருவாக்குவதால், systemd unit மற்றும் file layout மாறாது, மேலும் uv sync --frozen ஆனது lockfile-ல் உள்ளவற்றை அப்படியே நிறுவும். ஒரு application-ஐ git மூலம் pinned requirements.txt உடன் deploy செய்து, சில நொடிகளில் நிறுவல் முடிந்துவிட்டால், python3 -m venv போதுமானது. மேலும், server-ல் பராமரிக்க வேண்டிய binary-களின் எண்ணிக்கை குறையும்.

#python#venv#pipx#uv#deployment