pex(https://github.com/pantsbuild/pex)代表 Python EXecutable,是一種生成易于分發(fā)的 python 包的方法。需要注意的一件重要事情是 pex 沒有可靠的 Windows 支持。因此,您需要在 *NIX 系統(tǒng)上運行 pex。本文將展示您可以使用 pex 執(zhí)行的一些操作,以分發(fā)不同類型的 python 項目。
基本用法
鑒于用于 pex 打包的 python 解釋器很重要,強烈建議使用虛擬環(huán)境。作為示例,我將使用 python 3.11 環(huán)境:
$ virtualenv --python=python3.11 venv $ source venv/bin/activate $ python -m pip install pex Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple Collecting pex Using cached https://www.piwheels.org/simple/pex/pex-2.1.144-py2.py3-none-any.whl (2.9 MB) Installing collected packages: pex Successfully installed pex-2.1.144
pex CLI 執(zhí)行的一般格式為:
pex [MODULES] [OPTIONS]
其中[MODULES]是 pip 樣式依賴項聲明字符串中以空格分隔的模塊列表:
$ pex "requests" "setproctitle==1.3.2" "uvicorn[standard]" Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>>
如果沒有任何其他選項,pex 將進入交互式 shell,并且提供的模塊將在以下位置可用:
>>> import requests >>> import setproctitle >>> import uvicorn >>>
關(guān)閉控制臺后我們可以看到虛擬環(huán)境包完全不受影響:
$ pip list Package Version ---------- ------- pex 2.1.144 pip 23.2.1 setuptools 65.5.0 $
需求管理
由于列出每個模塊通常并不理想,因此可以使用兩種替代方法來傳遞需求。第一個解決方案是使用requirements.txt文件:
requirements.txt
requests setproctitle==1.3.2 uvicorn[standard]
然后可以使用傳入的-r選項和requirements.txt文件運行 pex:
$ pex -r requirements.txt Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>>
-r如果您捆綁了多個項目,也可以多次傳遞參數(shù)。如果您已經(jīng)設(shè)置了虛擬環(huán)境,那么您可以傳遞pip freeze到pex:
$ pex $(pip freeze) Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information.(InteractiveConsole) >>>
requirements.txt如果您有很多模塊需要使用,那么該方法會很好。pip freeze對于已經(jīng)設(shè)置了 virtualenv 的情況很有用。
Python 項目結(jié)構(gòu)化模塊
pex 還支持 python 包作為模塊,其結(jié)構(gòu)類似于python 打包文檔中的基本結(jié)構(gòu)。對于此示例,我將使用此 git 存儲庫中的項目布局(https://github.com/cwgem/pex_simple)。它包括一個帶有自述文件、許可證、簡單模塊和 pyproject.toml 的基本布局。這足以讓它被pex像開發(fā)模式 pip install 一樣識別:
$ pex . Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from simple_pex import simple_math >>> simple_math(3,4) 7 >>>
這一切都是在無需構(gòu)建項目本身的情況下實現(xiàn)的。
資源目錄
pex還可以添加重要項目的目錄,例如測試數(shù)據(jù)和配置。在應(yīng)用程序存儲庫中有一個resources目錄,其中包含一個test_data.json如下所示的文件:
{ "a": 1, "b": 2 }
我們可以使用pex參數(shù)-D來添加用于捆綁的特定目錄。然后可以在腳本/交互式提示中使用它,如下所示:
$ pex . -D resources Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole)>>> from simple_pex import simple_math >>> import json >>> fp = open('resources/test_data.json', 'r') >>> data = json.load(fp) >>> fp.close() >>> simple_math(data['a'], data['b']) 3 >>>
正如您所看到的,JSON 數(shù)據(jù)被加載,然后傳遞給simple_math返回正確結(jié)果的函數(shù)。
切入點
python 腳本的一項功能是能夠像運行基本程序一樣設(shè)置入口點。對于此示例,我將使用此存儲庫中托管的代碼(https://github.com/cwgem/pex_simple_cli)。使這項工作有效的是控制臺腳本的聲明,如下所示:
[project.scripts]adder = "cli_pex:run"
這將生成一個名為“adder”的腳本,該腳本將從包run中執(zhí)行cli_pex:
import argparse def run(): parser = argparse.ArgumentParser() parser.add_argument("--integer1", type=int, help="First Integer") parser.add_argument("--integer2", type=int, help="Second Integer") args = parser.parse_args() print(args.integer1 + args.integer2)
雖然不是一個非常實用的程序,但它可以完成展示 pex 如何與控制臺腳本一起工作的工作。為了展示這一點:
$ pex . -o adder.pex -c adder $ ./adder.pex --integer1 3 --integer2 4 7
using-c告訴 pex 我們要adder使用pyproject.toml. 現(xiàn)在,當(dāng)我們打包所有內(nèi)容時,它就像一個基本程序一樣。還有一個使用固定參數(shù)的選項,因此只.pex需要執(zhí)行文件:
$ pex . -o adder.pex -c adder --inject-args "--integer1 3 --integer2 4" $ ./adder.pex 7
這對于輕松部署采用綁定端口和主機名等參數(shù)的服務(wù)器腳本非常有用。
Docker 部署
為了將這一切放在一起,我將對 pex Web 應(yīng)用程序進行 Docker 部署。它將把 Gunicorn 與 Flask 應(yīng)用程序捆綁在一起,該應(yīng)用程序?qū)⒊洚?dāng)容器的入口點??梢栽诖颂幷业酱耸纠惺褂玫拇a(https://github.com/cwgem/pex_web_example)。在此設(shè)置中,有一個簡單的 Flask 應(yīng)用程序、一個 Gunicorn 配置文件和一個用于啟用部署的 Dockerfile。這次pyproject.toml聲明了一些依賴項:
dependencies = [ "flask", "gunicorn", "setproctitle", ]
另一件需要考慮的事情是,pex 需要將其打包的系統(tǒng)設(shè)置與目標(biāo)系統(tǒng)相當(dāng)接近。這意味著我將在 Unbuntu 盒子上構(gòu)建,而我的容器將基于 Debian(更精簡,并且系統(tǒng)足夠接近)。其他一些需要完成的事情:
pex可執(zhí)行文件需要指向gunicorn控制臺腳本才能運行服務(wù)器
Gunicorn 配置文件需要復(fù)制到系統(tǒng)中
--inject-args需要將--config參數(shù)設(shè)置為gunicorn配置
生成的.pex文件需要設(shè)置為入口點
查看需求,結(jié)果pex調(diào)用將是:
pex . -o web_pex.pex -c gunicorn --inject-args "--config /home/gunicorn/app/gunicorn.config.py"
雖然 Dockerfile 看起來像:
FROM python:3.11.4-bullseye USER root RUN useradd -d /home/gunicorn -r -m -U -s /bin/bash gunicorn USER gunicorn RUN mkdir /home/gunicorn/app COPY config/gunicorn.config.py /home/gunicorn/app COPY web_pex.pex /home/gunicorn/app ENTRYPOINT /home/gunicorn/app/web_pex.pex EXPOSE 8000
鑒于構(gòu)建.pex捆綁包的解釋器是 python 3.11,我將其設(shè)置為基礎(chǔ)映像?,F(xiàn)在剩下的就是構(gòu)建 Dockerfile,然后運行生成的映像:
$ docker buildx build -f Dockerfile -t flask/web-pex:latest . $ docker run -it -p 8000:8000 flask/web-pex:latest [2023-08-25 00:13:11 +0000] [7] [INFO] Starting gunicorn 21.2.0 [2023-08-25 00:13:11 +0000] [7] [INFO] Listening at: http://0.0.0.0:8000 (7) [2023-08-25 00:13:11 +0000] [7] [INFO] Using worker: sync [2023-08-25 00:13:11 +0000] [8] [INFO] Booting worker with pid: 8 [2023-08-25 00:13:11 +0000] [9] [INFO] Booting worker with pid: 9
這將運行新創(chuàng)建的flask/web-pex:latest映像并公開端口 8000?,F(xiàn)在使用curl 進行測試:
$ curl http://127.0.0.1:8000 Hello World
感謝setproctitle進程列表也變得更清晰:
$ ps auxUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND gunicorn 1 0.0 0.0 2480 512 pts/0 Ss+ 00:13 0:00 /bin/sh -c /home/gunicorn/app/web_pex.pex gunicorn 7 4.5 0.2 53904 48244 pts/0 S+ 00:13 0:00 gunicorn: master [gunicorn] gunicorn 8 1.1 0.3 63244 52084 pts/0 S+ 00:13 0:00 gunicorn: worker [gunicorn] gunicorn 9 0.6 0.3 62024 51644 pts/0 S+ 00:13 0:00 gunicorn: worker [gunicorn] gunicorn 10 0.5 0.0 6052 3784 pts/1 Ss 00:13 0:00 /bin/bash gunicorn 17 0.0 0.0 8648 3276 pts/1 R+ 00:13 0:00 ps aux
這使得更容易辨別容器上的各種gunicorn進程。
工具
另一個有趣的功能是 pex 還提供了一些可用的工具,可以讓我們創(chuàng)建性能更高的 docker 鏡像。為了使這項工作正常進行,我們需要添加--include-tools到pex構(gòu)建命令中:
$ pex . -o web_pex.pex -c gunicorn --inject-args "--config /home/gunicorn/app/gunicorn.config.py" --include-tools
Dockerfile 還將更新為多階段構(gòu)建以生成最終的映像:
FROM python:3.11.4-bullseye as deps RUN mkdir -p /home/gunicorn/app COPY web_pex.pex /home/gunicorn/ RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /home/gunicorn/web_pex.pex venv --scope=deps --compile /home/gunicorn/app FROM python:3.11.4-bullseye as srcs RUN mkdir -p /home/gunicorn/app COPY web_pex.pex /home/gunicorn COPY config/gunicorn.config.py /home/gunicorn/app RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /home/gunicorn/web_pex.pex venv --scope=srcs --compile /home/gunicorn/app FROM python:3.11.4-bullseyeRUN useradd -d /home/gunicorn -r -m -U -s /bin/bash gunicorn COPY --from=deps --chown=gunicorn:gunicorn /home/gunicorn/app /home/gunicorn/app COPY --from=srcs --chown=gunicorn:gunicorn /home/gunicorn/app /home/gunicorn/app USER gunicorn ENTRYPOINT /home/gunicorn/app/pex EXPOSE 8000
這將分離依賴項和源編譯。當(dāng) python 進行編譯時,它將創(chuàng)建一組特定于解釋器的字節(jié)碼,因此不必在運行時完成。這使得事情運行得更快。docker 構(gòu)建的唯一變化是 Dockerfile 不同,而運行命令保持不變:
$ docker buildx build -f Dockerfile_pex_tools -t flask/web-pex:latest . $ docker run -it -p 8000:8000 flask/web-pex:latest [2023-08-25 01:25:47 +0000] [7] [INFO] Starting gunicorn 21.2.0 [2023-08-25 01:25:47 +0000] [7] [INFO] Listening at: http://0.0.0.0:8000 (7) [2023-08-25 01:25:47 +0000] [7] [INFO] Using worker: sync [2023-08-25 01:25:47 +0000] [8] [INFO] Booting worker with pid: 8 [2023-08-25 01:25:47 +0000] [9] [INFO] Booting worker with pid: 9
查看容器內(nèi)部,您可以看到用戶目錄pex中的布局:~/appgunicorn
$ cd ~/app $ ls PEX-INFO __main__.py __pycache__ bin gunicorn.config.py include lib lib64 pex pyvenv.cfg
并且緩存文件也顯示在gunicorn工人生成之前的時間,以表明它們確實是編譯輸出,而不僅僅是Python自然生成它們:
$ ls -lah lib/python3.11/site-packages/flask/__pycache__/ total 388K drwxr-xr-x 2 gunicorn gunicorn 4.0K Aug 25 01:03 . drwxr-xr-x 4 gunicorn gunicorn 4.0K Aug 25 01:03 .. -rw-r--r-- 1 gunicorn gunicorn 4.0K Aug 25 01:03 __init__.cpython-311.pyc -rw-r--r-- 1 gunicorn gunicorn 249 Aug 25 01:03 __main__.cpython-311.pyc -rw-r--r-- 1 gunicorn gunicorn 86K Aug 25 01:03 app.cpython-311.pyc -rw-r--r-- 1 gunicorn gunicorn 32K Aug 25 01:03 blueprints.cpython-311.pyc
結(jié)論
pex對用于打包 Python 代碼的了解到此結(jié)束。(https://github.com/pantsbuild/pex/issues/716)這是一個有趣的系統(tǒng),從GitHub 問題來看也具有可重復(fù)構(gòu)建的潛力。啟用工具可以輕松地使用單個包部署,同時通過多階段編譯啟用更高性能的選項。我鼓勵您看看它如何增強您的 Python 項目。文章來源:http://www.zghlxwxcb.cn/article/301.html
文章來源地址http://www.zghlxwxcb.cn/article/301.html
到此這篇關(guān)于使用PEX打包Python可執(zhí)行文件的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!