Python 虛擬環境全知道

對於每個python項目依賴的庫版本都有可能不一樣,如果將依賴包都安裝到公共環境的話顯然是沒法進行區分的,甚至是不同的項目使用的python版本都不盡相同,有的用python2.7,有的用python3.6,所以對於python項目的環境進行隔離管理就成為一個必然的需求了。

需求

  • 不同項目間能區分依賴包版本
  • 不同項目間能區分python版本
  • 方便自由切換

解決方案

  • 解決依賴包問題:virtualenv
  • 解決python版本問題:pyenv
  • 終極(也許吧)解決方案:docker

virtualenv

運行pip install virtualenv即可安裝virtualenv,當然了還可以用easy_install安裝,即使是沒有安裝任何Python包管理器(比如pip),也可以直接獲取virtualenv.py並運行python virtualenv.py,效果也是一樣的,當然我還是強烈推薦你安裝包管理工具:pip,他一定能為你帶來很多便利的(新版本的virtualenv也包含了pip管理工具)。

$ pip install virtualenv
Collecting virtualenv

Using cached virtualenv-15.1.0-py2.py3-none-any.whl
Installing collected packages: virtualenv
Successfully installed virtualenv-15.1.0

安裝完成後,就可以直接創建一個虛擬環境了(virtualenv 環境名稱):

$ virtualenv env4test

創建完成後,用下面的命令即可激活當前虛擬環境:

$ source env4test/bin/activate
(env4test)$

現在就可以隨意的安裝你的依賴包了,現在安裝的包只會對當前環境env4test有效,比如安裝django2.0:

(env4test)$ pip install django

要退出當前虛擬環境也是非常簡單的,如下:

$ deactivate

現在我們用pip list命令可以發現已經沒有django的身影了。

virtualenv還有很多高級的用法,可以前往該文檔查看。

virtualenvwrapper

virtualenvwrapper是virtualenv的一個擴展包,可以讓你更加方便的使用virtualenv,優點:

  • 將所有虛擬環境整合在一個目錄下
  • 管理(新增,刪除,複製)虛擬環境
  • 方便切換虛擬環境

安裝也很方便,用包管理工具即可:

$ pip install virtualenvwrapper

安裝完成以後還需要小小的配置一下才可以使用,首先我們找到virtualenvwrapper.sh的文章,通常會是:/usr/local/bin/virtualenvwrapper.sh:

$ sudo find / -name virtualenvwrapper.sh
Password:
/usr/local/bin/virtualenvwrapper.sh

然後我們可以在.zshrc(取決於你用的終端,我用的zsh)添加一行命令:

source /usr/local/bin/virtualenvwrapper.sh

然後讓我們的配置生效:

$ source ~/.zshrc

現在我們就可以使用virtualenvwrapper的基本命令了:

  • 創建基本環境:mkvirtualenv [環境名]
  • 刪除環境:rmvirtualenv [環境名]
  • 激活環境:workon [環境名]
  • 退出環境:deactivate
  • 列出所有環境:workon或者lsvirtualenv -b

參考文檔:https://virtualenvwrapper.readthedocs.io/en/latest/

pyenv

pyenv是Python版本管理工具,可以改變全局的Python版本,安裝多個版本的Pytho,設置目錄級別的Python版本,還能創建和管理虛擬環境。所有的設置都是用戶級別的操作,不需要sudo命令。 pyenv通過系統修改環境變量來實現Python不同版本的切換。而virtualenv 通過將Python包安裝到一個目錄來作為Python 包虛擬環境,通過切換目錄來實現不同包環境間的切換。

如果你使用的MAC系統,推薦使用homebrew來安裝:

$ brew update
$ brew install pyenv

如果你使用的是其他系統,也不擔心,pyenv官方提供了一鍵安裝的方式:

$ curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash

安裝完成以後,可以添加幾條命令到.zshrc(同樣的也可能是.bashrc,根據自己使用的終端進行配置)中開啟自動補全功能:

export PATH=$HOME/.pyenv/bin:$PATH
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

然後同樣激活上面的配置:

$ source ~/.zshrc

現在我們就可以使用pyenv了:

  • 查看本機安裝Python版本:
$ pyenv versions
∗ system (set by /Users/ych/.pyenv/version)
3.6.4
3.6.4/envs/ops3.6.4
3.6.4/envs/talk3.6.4
ops3.6.4
talk3.6.4
  • 星號表示當前正在使用的Python版本。
  • 查看所有可安裝的Python版本:
$ pyenv install -l
  • 安裝與卸載:
$ pyenv install 2.7.3 # 安裝python
$ pyenv uninstall 2.7.3 # 卸載python
  • 版本切換:
$ pyenv global 2.7.3
$ pyenv local 2.7.3
  • global用於設置全局的Python版本,通過將版本號寫入~/.pyenv/version文件的方式。local用於設置本地版本,通過將版本號寫入當前目錄下的.python-version文件的方式。通過這種方式設置的Python版本優先級比global高。
  • python優先級:shell > local > global pyenv會從當前目錄開始向上逐級查找.python-version文件,直到根目錄為止。若找不到,就用global版本。
$ pyenv shell 2.7.3 # 設置面向 shell 的 Python 版本,通過設置當前 shell 的 PYENV_VERSION 環境變量的方式。這個版本的優先級比 local 和 global 都要高。
$ pyenv shell --unset # –unset 參數用於取消當前 shell 設定的版本。

pyenv-virtualenv

自動安裝pyenv後,它會自動安裝部分插件,通過pyenv-virtualenv插件可以很好的和virtualenv進行結合:

$ ls -la ~/.pyenv/plugins
total 8
drwxr-xr-x 9 ych staff 288 12 26 16:27 .
drwxr-xr-x 23 ych staff 736 12 26 17:44 ..
-rw-r--r-- 1 ych staff 52 12 26 16:26 .gitignore
drwxr-xr-x 11 ych staff 352 12 26 16:27 pyenv-doctor
drwxr-xr-x 12 ych staff 384 12 26 16:27 pyenv-installer
drwxr-xr-x 7 ych staff 224 12 26 16:27 pyenv-update
drwxr-xr-x 13 ych staff 416 12 26 16:27 pyenv-virtualenv
drwxr-xr-x 8 ych staff 256 12 26 16:27 pyenv-which-ext
drwxr-xr-x 8 ych staff 256 12 26 16:26 python-build

基本使用命令:

  • 列出當前虛擬環境:pyenv virtualenvs
  • 激活虛擬環境:pyenv activate 環境名稱
  • 退出虛擬環境:pyenv deactivate
  • 刪除虛擬環境:pyenv uninstall 環境名稱或者rm -rf ~/.pyenv/versions/環境名稱
  • 創建虛擬環境:pyenv virtualenv 3.6.4 env3.6.4

若不指定python 版本,會默認使用當前環境python 版本。如果指定Python 版本,則一定要是已經安裝過的版本,否則會出錯。環境的真實目錄位於~/.pyenv/versions下。

總結:利用pyenv和pyenv-virtualenv插件就能夠簡單方便的將python版本和依賴包進行環境隔離了,在實際開發過程中比較推薦這種方式。

參考文檔:https://github.com/pyenv/pyenv。

Docker

有沒有一種方式能夠不按照這些工具來進行環境隔離的呢?當然有,那就是大名鼎鼎的Docker。如果你的服務都是容器化的話,應該對Docker不陌生,將當前項目跑在一個隔離的容器中,對系統中的其他服務或者項目是沒有任何影響的,不用擔心會汙染環境,唯一不友好的地方是項目中的代碼改變後需要重新構建鏡像。

比如現在有一個django的項目,項目結構如下:

$ testpyenv tree
.
├── manage.py
└── testpyenv
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

在項目根目錄下面新建文件requirements.txt:

Django==2.0

然後我們在根目錄下面創建一個Dockerfile文件:

FROM python:3.6.4
# 設置工作目錄
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# 添加依賴(利用Docker 的緩存)
ADD ./requirements.txt /usr/src/app/requirements.txt
# 安裝依賴
RUN pip install -r requirements.txt
# 添加應用
ADD . /usr/src/app
# 運行服務
CMD python manage.py runserver 0.0.0.0:8000

因為django2.0只支持python3以上了,所以我們這裡基礎鏡像使用python:3.6.4,然後是添加應用代碼,安裝依賴,運行服務等。然後我們構建一個鏡像:

$ docker build -t cnych/testpyenv:v0.1.1 .

構建完成以後,在我們項目根目錄中新建一個start.sh的腳本來啟動容器:

docker run -d -p 8000:8000 --name testpyenv cnych/testpyenv:v0.1.1

將本地的8000端口和容器的8000進行映射,執行我們的啟動腳本:

$ source start.sh

啟動完成後,我們就可以在本地通過http://127.0.0.1:8000進行訪問了。

Python 虛擬環境全知道

但是如果只這樣配置的話,的確能夠解決我們的環境隔離問題,但是現在有一個最大的一個問題是,每次代碼更改過後都需要重新構建鏡像才能生效,這對於開發階段是非常不友好的,有什麼解決方案呢?你是否還記得當你更改了代碼後django項目會自動加載的,要是每次更改了項目代碼後,容器中的代碼也變化的話那豈不是容器中的服務也自動加載了?是不是?

幸好Docker為我們提供了volume掛載的概念,我們只需要將我們的代碼掛載到容器中的工作目錄就行了,現在來更改start.sh腳本:

work_path=$(pwd)
docker run -d -p 8000:8000 --name testpyenv -v ${work_path}:/usr/src/app cnych/testpyenv:v0.1.1

然後激活啟動腳本,隨意更改一次代碼,看看是否能夠及時生效,怎樣查看呢?查看日誌就行了:

$ docker logs -f testpyenv

最後,如果是生產環境記得把代碼掛載給去掉,因為線上不需要這樣做,只需要構建一次就行。


分享到:


相關文章: