Ubuntu sunucuda Python venv, pipx ve uv kullanımı
Ubuntu sunucularda pip install komutunun externally-managed-environment hatası vermesinin nedenini öğrenin. Uygulama ve araç kurulumu için doğru yöntemi seçin.
Yeni bir Ubuntu sunucusunda pip install neden başarısız olur
Bir sunucuda Python venv, pipx ve uv arasında seçim yapmak tek bir soruya dayanır: ne yüklüyorsunuz? Uygulama bağımlılıkları, uygulamanın kendi dizini içindeki bir sanal ortama aittir. İsmiyle çağırmak istediğiniz komut satırı araçları pipx'e aittir. uv her iki işi de yapar ve ikinci bir makinenin aynı ortamı oluşturması gerektiğinde önem kazanan bir kilit dosyası (lockfile) ekler. Hiçbiri sistem Python'ına kurulum yapmaz, çünkü güncel bir Ubuntu sunucusu bunu doğrudan reddeder.
Ubuntu 24.04 üzerinde sudo pip install requests komutunu çalıştırın; pip, tek bir dosya bile indirmeden duracaktır.
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.Bu, görevini yerine getiren PEP 668'dir (Python geliştirme önerisi 668, "harici olarak yönetilen ortamlar"). Debian ve Ubuntu, yorumlayıcının yanına /usr/lib/python3.12/EXTERNALLY-MANAGED konumunda bir işaretçi dosyası bırakır ve pip, bu dosyayı taşıyan hiçbir yorumlayıcıya yazmayı kabul etmez.
Bu kural, sys.path düzeni nedeniyle mevcuttur. apt, kütüphaneleri /usr/lib/python3/dist-packages dizinine kurar. root yetkisiyle sistem yorumlayıcısına karşı çalıştırılan pip, /usr/local/lib/python3.12/dist-packages dizinine yazar ve Debian'ın paketleme sistemi bu dizini arama yolunda daha ön sıraya koyar. Bunu python3 -c 'import sys; print(sys.path)' ile kendiniz yazdırıp sırayı inceleyebilirsiniz. Dolayısıyla, pip tarafından yazılan kopya, sunucudaki /usr/bin/python3 altında çalışan her program için apt tarafından kurulan kopyayı gölgeler; buna dağıtımın kendi araçları da dahildir. cloud-init, requests, jinja2 ve PyYAML kütüphanelerini bu yorumlayıcıdan içe aktarır. Bunlardan birini pip ile yükseltip uyumsuz bir sürüme geçerseniz, hiç dokunmadığınız bir şey bir sonraki açılışta, zincirde olduğunu bilmediğiniz bir paketi işaret eden bir traceback ile başarısız olur. apt kendi sürümünü kurulu olarak kaydettiği için hiçbir şey sizi uyarmaz ve onarım işlemi sudo apt reinstall python3-requests gerektirir.
Bunu takip eden kural kısadır. Sistem Python'ı dağıtıma aittir. Ona kurulum yapmayın, kütüphanelerini pip ile yükseltmeyin ve hata mesajını ortadan kaldırmak için EXTERNALLY-MANAGED dosyasını silmeyin. /usr/bin/python3 aracına verilecek tek görev, sanal ortamlar oluşturmaktır.
venv, pipx ve uv: karar mekanizması
En son okuduğunuz araca göre değil, ne kurduğunuza göre seçim yapın.
- Django veya Flask projesi gibi bir servis olarak dağıtıp çalıştırdığınız bir uygulama: Uygulamanın dizini içinde bir adet sanal ortam (venv).
PATHüzerinde bulunmasını istediğinizansibleveyahttpiegibi bir komut satırı aracı: Her araca özel bir ortam vePATHüzerinde tek bir bağlantı sağlayan pipx.- Lockfile gerektiren, daha hızlı kurulum isteyen veya dağıtımın sunmadığı bir Python sürümüne ihtiyaç duyan bir proje: Standart bir venv ve bir
uv.lockdosyası oluşturan uv. - Kodunuzdan ziyade bir dağıtım aracının ihtiyaç duyduğu bir kütüphane: Sistem yorumlayıcısına herhangi bir şey eklemenin tek desteklenen yolu olan
sudo apt install python3-<name>.
pipx ve uv tool install aynı işi yapar, bu nedenle uv kurulu olan bir sistemde ayrıca pipx kullanılmasına gerek yoktur. Seçtiğiniz web framework'ü burada bir şeyi değiştirmez: VPS üzerinde Django ve Flask kurulumları, requirements.txt içine neyin yerleştiği konusunda farklılık gösterir, ancak çevresindeki ortamın nasıl oluşturulduğu konusunda değil. Aşağıdaki her şey Ubuntu 24.04 ve onun Python 3.12 sürümünü kullanır, bu nedenle sürümünüz farklıysa yolların içindeki sürüm numaralarını düzenleyin.
Uygulama bazlı venv oluşturma
Ubuntu, venv modülünü temel Python paketinden ayırır; bu nedenle minimal bir imaj üzerinde yapılan ilk deneme, eksik olanı belirten bir hata mesajıyla başarısız olur.
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-venvGerekli paketi kurun ve ardından ortamı, kodun sahibi olacak kullanıcı ile oluşturun.
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.txtNelerin orada olmadığına dikkat edin: source yok, activate yok. /srv/myapp/.venv/bin/pip, ikili dosyanın bulunduğu konum nedeniyle o ortama kurulur; kabuğa aktardığınız herhangi bir değişken nedeniyle değil. Devam etmeden önce bunu doğrulayın.
/srv/myapp/.venv/bin/python -c 'import sys; print(sys.prefix)'Bu komut /srv/myapp/.venv çıktısını verir. Eğer /usr çıktısını veriyorsa, sistem yorumlayıcısını çalıştırıyorsunuz demektir ve paketleriniz hedeflemediğiniz bir yere gitmiştir.
Bir venv'nin iki özelliği, sonrasında onunla neler yapabileceğinizi belirler. Bir venv taşınabilir değildir, çünkü bin/ içindeki her betik mutlak bir shebang satırı taşır: head -1 /srv/myapp/.venv/bin/pip, #!/srv/myapp/.venv/bin/python dosyasını okur. Üst dizini yeniden adlandırdığınızda bu betikler bad interpreter: No such file or directory hatasıyla başarısız olur. Bir venv ayrıca onu oluşturan yorumlayıcıyı sabitler; bu, /srv/myapp/.venv/pyvenv.cfg içindeki home satırında kayıtlıdır ve bin/python3, o ikili dosyaya giden bir sembolik bağdır. Sürümü yükseltip python3.12 dosyasını kaldırırsanız, sembolik bağ hedefsiz kalır ve servis başlangıçta No such file or directory hatasıyla durur. Her iki durumun çözümü de aynıdır: venv'yi silin ve requirements.txt kullanarak yenisini oluşturun. Yeniden oluşturma saniyeler sürer. Bir venv'yi asla makineler arasında kopyalamayın.
venv dizininin konumu ve sahipliği
venv dizinini /srv/myapp/.venv yolundaki kodun yanına yerleştirin ve her uygulama için ayrı bir venv kullanın. Bu sayede dağıtım tek bir dizinden ibaret olur, systemd birimi asla değişmeyen bir yola sahip olur ve iki uygulama, paylaşılan bir bağımlılık güncellemesi nedeniyle birbirini bozamaz. venv dizinini, web sunucunuzun dosyaları doğrudan yayınladığı bir yere koymayın; çünkü bu dizin bağımlılıklarınızı ve genellikle yapılandırma dosyalarınızı barındırır.
Sahiplik konusu kısa bir incelemeyi hak eder. Kodun ve ortamın sahipliğini bir deploy kullanıcısına verin ve servis hesabına yalnızca okuma ve çalıştırma yetkisi tanıyın.
sudo adduser --system --group --no-create-home myapp
sudo chown -R deploy:myapp /srv/myapp
sudo chmod -R o-rwx /srv/myappServis artık bağımlılıklarını içe aktarabilir ancak bunları değiştiremez. Bu durum, web uygulamasındaki bir kod yürütme açığının disk üzerindeki bir kütüphaneyi sessizce değiştirmesini ve yeniden başlatma sonrasında varlığını sürdürmesini engeller. Makinenin geri kalanı için de geçerli olan aynı mantık, servisleri en düşük yetkili kullanıcılarla çalıştırma bölümünde ele alınmıştır.
Komut satırı araçları için pipx
pipx, kütüphaneleri değil uygulamaları kurar. Her araç ~/.local/share/pipx/venvs/<name> altında kendi ortamına sahip olur ve aracın çalıştırılabilir dosyaları ~/.local/bin dizinine bağlanır; böylece aynı kütüphanenin farklı sürümlerine ihtiyaç duyan iki araç asla çakışmaz.
sudo apt update
sudo apt install -y pipx
pipx ensurepath
pipx install httpiepipx ensurepath, kabuk başlangıç dosyanızı düzenleyerek ~/.local/bin yolunu PATH değişkenine ekler. Hâlihazırda kullandığınız kabuk oturumunu değiştiremeyeceği için, kurulumdan hemen sonra alınan http: command not found hatası genellikle oturumu kapatıp tekrar açmadığınız anlamına gelir. Ubuntu'nun varsayılan ~/.profile dosyası, ~/.local/bin yolunu yalnızca giriş sırasında dizin mevcutsa ekler; bu nedenle yeni bir hesapta bu durum bir kez yaşanır ve bir daha tekrarlanmaz.
pipx'i bir kütüphaneye yönlendirirseniz, şu ifadeyle başlayan bir mesajla reddeder:
No apps associated with package requests or its dependencies.Bu, aracın size yanlış bir araç kullandığınızı söyleme biçimidir. Kütüphaneler bir uygulamanın venv dizinine aittir.
Sunucu tarafında önemli olan detay konumdur. Standart bir pipx install komutu, her şeyi tek bir kullanıcının ev dizini altına yerleştirir. myapp kullanıcısı olarak çalışan bir systemd birimi buna erişemez, root yetkisiyle çalışan bir cron işi bunu göremez ve sudo de bulamaz; çünkü /etc/sudoers içindeki secure_path, PATH değerini sabit bir listeyle değiştirir. Tüm makinenin erişmesi gereken bir araç için kurulumu global olarak yapın.
sudo pipx install --global ansible
sudo pipx ensurepath --global--global bayrağı, ortamları /opt/pipx dizinine yerleştirir ve çalıştırılabilir dosyaları, varsayılan PATH değişkeninde ve secure_path içinde yer alan /usr/local/bin dizinine bağlar. Önce pipx --version ile sürümünüzü kontrol edin; çünkü Ubuntu 24.04, --global sürümünden daha eski olan pipx 1.4.3 paketini içerir ve eski pipx sürümleri unrecognized arguments: --global ile yanıt verir. Bu sürümde, belgelenen iki dizini kendiniz ayarlayın:
sudo env PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install ansible
command -v ansiblecommand -v ansible komutu /usr/local/bin/ansible çıktısını vermelidir. Eğer /home altında bir yol yazdırıyorsa, araç tek bir kullanıcının hesabına kurulmuştur ve hiçbir servis onu bulamayacaktır.
uv ile lockfile kullanımı
uv, pip, venv ve pip-tools araçlarının yaptığı işleri tek başına üstlenen, ayrıca Python yorumlayıcılarını da indirebilen Astral imzalı tek bir binary dosyasıdır. Küçük bir VPS üzerinde dahi fark edilecek kadar hızlıdır ve gerçek bir lockfile oluşturur.
Resmi yükleyici, uv ve uvx dosyalarını ~/.local/bin dizinine yerleştirir:
curl -LsSf https://astral.sh/uv/install.sh | sh
uv --versionBir sunucuda script'i doğrudan shell'e yönlendirmek (pipe) dikkat gerektirir. URL içindeki sürümü sabitleyin ve çalıştırmadan önce dosyayı inceleyin:
curl -LsSf https://astral.sh/uv/0.12.3/install.sh -o uv-install.sh
less uv-install.sh
sh uv-install.shEğer sistemde pipx yüklüyse pipx install uv de kullanılabilir. uv, kendi Python bağımlılığı olmayan bağımsız bir binary olduğu için, onu /usr/local/bin dizinine kopyalamak sunucudaki tüm kullanıcıların erişimine açmak için geçerli bir yöntemdir.
pyproject.toml içeren bir proje için iş akışı dört komuttan oluşur ve bunlardan sadece sonuncusu sunucuda çalıştırılır.
uv init myapp
uv add flask gunicorn
uv lock
uv sync --frozen --no-devuv lock, tam çözümlenmiş sürümleri içeren platformlar arası bir lockfile olan uv.lock dosyasını oluşturur; bu dosyayı kodunuzla birlikte commit etmelisiniz. uv sync, proje kök dizininde bu dosyaya uygun bir .venv oluşturur. Sunucuda önemli olan bayrak --frozen bayrağıdır: dokümantasyon bunu, lockfile'ın güncel olup olmadığını kontrol etmek yerine lockfile içindeki sürümleri tek gerçek kaynak olarak kabul etmek şeklinde tanımlar; bu, bir dağıtım (deployment) için istenen davranıştır. --no-dev ise geliştirme bağımlılık grubunu dışarıda bırakır.
Mevcut bir requirements.txt projesinin dönüştürülmesine gerek yoktur, çünkü uv, pip'in dilinden anlar:
uv venv /srv/myapp/.venv
uv pip install --python /srv/myapp/.venv/bin/python -r /srv/myapp/requirements.txtSonuçta ortaya çıkan yapı standart bir sanal ortamdır (virtual environment). .venv/bin/python, tıpkı python3 -m venv tarafından oluşturulmuş gibi davranır, bu nedenle bu kılavuzun ilerleyen kısımlarında hiçbir şey değişmez.
Sunucuda kullanmadan önce uv'nin bir varsayılan ayarını bilmekte fayda vardır. python-preference ayarı varsayılan olarak managed değerindedir; bu, sistemde halihazırda bulunan yorumlayıcılar yerine "uv tarafından indirilen ve kurulan" yorumlayıcıların tercih edilmesi anlamına gelir. Dolayısıyla, sadece 3.12 sürümü yüklü olan bir sunucuda uv venv --python 3.13 komutu, hata vermek yerine sessizce 3.13 sürümünü ~/.local/share/uv/python dizinine indirir. Bu durum dizüstü bilgisayarlarda kullanışlı olsa da sunucularda şaşırtıcı olabilir; çünkü servisiniz artık ev dizininde yaşayan ve apt upgrade tarafından asla yamalanmayacak bir yorumlayıcıya bağımlı hale gelir. Dağıtımın kendi yorumlayıcısını kullanmak istiyorsanız uv.toml dosyasında python-preference ayarını only-system olarak yapılandırın. Eğer ortamın proje kök dizini dışında bir yerde olmasını istiyorsanız, UV_PROJECT_ENVIRONMENT ile proje sanal ortamı için kullanılacak dizini belirtebilirsiniz.
systemd'yi activate betiğine değil, venv yorumlayıcısına yönlendirin
Python dağıtımlarının büyük çoğunluğu burada hata verir; bunun nedeni activate komutunun işlevinin yanlış anlaşılmasıdır.
bin/activate bir kabuk betiğidir. venv'in bin dizinini PATH değişkeninin başına ekler, VIRTUAL_ENV değerini ayarlar, eski değerleri deactivate ile geri yüklenebilecek şekilde saklar ve komut satırı isteminizi değiştirir. Bu betik, yorumlayıcının kendisinin okuduğu hiçbir şey içermez. Aktivasyon, sadece komut satırında python yazan bir kullanıcı için sağlanan bir kolaylıktır.
Ortamı belirleyen asıl şey, çalıştırdığınız yorumlayıcı dosyasıdır. /srv/myapp/.venv/bin/python başladığında, Python'ın site modülü, çalıştırılabilir dosyanın bulunduğu dizinde veya bir üst dizinde bir pyvenv.cfg dosyası arar. /srv/myapp/.venv/pyvenv.cfg dosyasının bulunması, sys.prefix değerini venv olarak ayarlar ve bu da venv'in site-packages dizinini sys.path değişkenine ekler. Tüm mekanizma bundan ibarettir. Herhangi bir ortam değişkenine veya kabuğa ihtiyaç duymaz.
Bu nedenle, aşağıdaki birim asla başlamaz:
[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 bir kabuk komut satırı değildir. systemd bir programı doğrudan çalıştırır; bu yüzden source yerleşik komutu yoktur, && ifadesi değişmez bir argüman olarak iletilir ve hiçbir genişletme işlemi gerçekleşmez.
Aşağıdaki birim ise başlar ancak hemen sonlanır:
[Service]
ExecStart=/usr/bin/python3 /srv/myapp/app.pyModuleNotFoundError: No module named 'flask'/usr/bin/python3 sistem yorumlayıcısıdır ve sys.path değişkeni hiçbir zaman venv'inizi içermemiştir. Aynı komutun SSH oturumunuzda çalışmasının tek nedeni, orada venv'i aktive etmiş olmanız ve kabuğun python3 ifadesini PATH üzerinden .venv/bin/python3 yoluna çözümlemesidir.
Komutu /bin/bash -c 'source ... && gunicorn ...' ile sarmalamak işe yarar. Ancak bu, systemd ile süreciniz arasına gereksiz bir kabuk katmanı ekler. Oysa mutlak bir yol kullanımı sorunu kökten çözer:
[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 komutu, Main PID değeri gunicorn süreciniz olan bir active (running) çıktısı vermelidir. Başka bir sonuç alırsanız günlük kayıtlarını inceleyin.
Environment=PATH= satırı, zaten tam yolu içeren ExecStart için gerekli değildir. Bu satır, uygulamanızın başlattığı süreçler için gereklidir. Bir servis, systemd'den kısa ve varsayılan bir PATH değeri devralır. Bu nedenle, subprocess.run(["ffmpeg", ...]) çağıran Python kodu veya venv içindeki bir konsol betiğini çalıştıran yönetim komutları ihtiyaç duydukları dosyaları bulamaz. venv'in bin dizinini başa eklemek, activate betiğinin bir servisin gerçekten kullandığı tek kısmıdır. Birimin ne aldığını systemctl show -p Environment myapp ile kontrol edin.
Aynı kural zamanlanmış görevler için de geçerlidir. cron, işleri /usr/bin:/bin değerinde bir PATH ile çalıştırır. Bu yüzden, crontab dosyasındaki python3 /srv/myapp/cleanup.py satırı sistem yorumlayıcısını çalıştırır, sabahın üçünde ModuleNotFoundError hatasıyla başarısız olur ve hata mesajı kimsenin okumadığı yerel bir posta kuyruğuna gider. Oraya da mutlak venv yolunu yazın. Çıktıyı günlük kayıtlarında görmek ve son çalıştırma kaydını tutmak için bir systemd servisi ve zamanlayıcı çifti kullanın; bu yapı aynı ExecStart satırını kullanır.
Docker bu kararın yerini tutar mı?
Bir container kendi dosya sistemine sahiptir, bu nedenle soru ortadan kalkmak yerine şekil değiştirir. python:3.12-slim gibi resmi bir imajda Python, /usr/local içine gömülüdür ve herhangi bir EXTERNALLY-MANAGED işareti taşımaz; bu nedenle paket eklemek için hedeflenen yöntem pip install olarak root kullanmaktır ve venv kullanımı çok az katkı sağlar. Bunun yerine FROM ubuntu:24.04 oluşturduğunuzda, ana makinedekiyle aynı nedenden dolayı imajın içinde tekrar externally-managed-environment ile karşılaşırsınız: bu, dağıtımın işaretçi dosyasını taşıyan dağıtım yorumlayıcısıdır.
Birçok imaj hala venv kullanır çünkü bu, çok aşamalı (multi-stage) derlemeyi basitleştirir. Derleyici aşaması kurulumu /opt/venv içine yapar ve çalışma zamanı aşaması sadece o dizini kopyalayarak derleyicileri geride bırakır. "Activate" sorunu da bununla birlikte gelir. Bir RUN source /opt/venv/bin/activate satırı yalnızca o derleme katmanının kabuğunu etkiler, bu nedenle çalışma zamanında container sistem yorumlayıcısı üzerinde başlar ve ModuleNotFoundError hatasını verir. ENV PATH="/opt/venv/bin:$PATH" ayarını yapın veya CMD için /opt/venv/bin/gunicorn mutlak yolunu belirtin. Bu, farklı bir dosyadaki systemd hatasıyla aynı hatadır.
Sonuç olarak container, imaj yorumlayıcıyı ve altındaki her şeyi sabitlediği için yorumlayıcı sorununun yerini tutar. Ancak sabitleme (pinning) sorununun yerini tutmaz. Sabitlenmemiş bir requirements.txt dosyasından oluşturulan bir imaj, gelecek ay farklı sürümleri çözümleyebilir; bu da imaj etiketinin yeniden üretilebilir olduğu, ancak onu oluşturan derleme işleminin öyle olmadığı anlamına gelir. uv.lock gibi bir kilit dosyası veya tamamen sabitlenmiş bir gereksinim dosyası, container olsun ya da olmasın bu açığı kapatan şeydir. Bir uygulama systemd altında tek bir VPS üzerinde çalıştığında, container bu kararın çoğunu bir Dockerfile dosyasına taşır; çünkü systemd zaten başarısız olan bir süreci yeniden başlatır ve çıktısını journal içinde yakalar. VPS üzerinde Docker çalıştırmak, oluşturulan imajın bizzat kendisini dağıtmak istediğinizde değerini kanıtlar.
FAQ
--break-system-packages ile pip install kullanabilir miyim?
Sürekliliğini sağlamanız gereken bir sunucuda bunu yapmamalısınız. Bu bayrak, isminin ima ettiği işi yapar: korumayı kaldırır ve pip, sys.path üzerindeki apt dizininden önce gelen /usr/local/lib/python3.12/dist-packages içine yazma yapar. Bu durumda, /usr/bin/python3 altında çalışan tüm sistem betikleri için sizin sürümünüz, dağıtımın kendi sürümünün önüne geçer. apt ise kendi sürümünün yüklü olduğunu sanmaya devam eder; bu nedenle bir şeyler bozulana kadar çakışma tespit edilemez. Her seferinde sıfırdan oluşturduğunuz bir container imajı içinde, hasar yalnızca o imajla sınırlı kalacağı için bu yöntem savunulabilir. Yönettiğiniz bir makinede ise bir venv oluşturun. Bu sadece tek bir komuttur.
Sunucuda sanal ortam (virtual environment) nerede bulunmalıdır?
Uygulamanın kendi dizini içinde, /srv/myapp/.venv adıyla, bir deploy kullanıcısının sahipliğinde ve servis hesabının yalnızca okuma ve çalıştırma erişimine sahip olduğu bir konumda bulunmalıdır. Uygulama başına bir venv tutun; çünkü paylaşılan bir venv, ilk uygulama için yapılan bir yükseltmenin ikinciyi bozmasına neden olabilir. Bir venv oluşturulduktan sonra yerini değiştirmeyin veya kopyalamayın: bin/ dizinindeki her betik, shebang satırına o mutlak yolu yazar; bu yüzden taşınan bir venv, bad interpreter: No such file or directory hatasıyla başarısız olur. Bunun yerine onu silin ve requirements.txt dosyasından yeniden oluşturun.
systemd servisim neden ModuleNotFoundError ile başarısız oluyor?
Çünkü unit dosyası, venv'ye ait olmayan bir yorumlayıcıyı çalıştırıyordur. systemctl cat myapp komutunu çalıştırın ve ExecStart dosyasını okuyun. Bu dosya, mutlak yol ile /srv/myapp/.venv/bin/python değerini veya aynı bin/ dizinindeki bir konsol betiğini işaret etmelidir. Bir unit dosyası içinde activate dosyasını kaynak olarak göstermek (source) çalışmaz; çünkü ExecStart bir kabuk (shell) değildir ve systemd, status=203/EXEC ile Failed to locate executable source hatasını bildirir. Kodunuzun başlattığı tüm alt süreçlerin de venv araçlarını bulabilmesi için Environment=PATH=/srv/myapp/.venv/bin:/usr/local/bin:/usr/bin:/bin değerini ekleyin.
venv ve pip yerine uv kullanmalı mıyım?
Bir lockfile dosyasına ihtiyaç duyduğunuzda, kurulum süresi sizi rahatsız edecek kadar yavaş olduğunda veya dağıtımınızın sunmadığı bir Python sürümüne ihtiyaç duyduğunuzda uv kullanın. uv, standart bir venv oluşturur; bu nedenle systemd unit dosyası ve dosya düzeni değişmez ve uv sync --frozen, lockfile dosyasında kayıtlı olanın aynısını yükler. Eğer tek bir uygulama, sabitlenmiş bir requirements.txt ile git üzerinden dağıtılıyorsa ve kurulum saniyeler içinde bitiyorsa, python3 -m venv zaten yeterlidir ve sunucuda güncel tutulması gereken bir ikili dosyadan daha kurtulmuş olursunuz.