pex는 Python EXecutable의 약자이며 배포하기 쉬운 Python 패키지를 생성하는 방법입니다. 주목해야 할 중요한 점 중 하나는 pex가 Windows를 제대로 지원하지 않는다는 것입니다. 따라서 *NIX 시스템에서 pex를 실행해야 합니다. 이 기사에서는 다양한 유형의 Python 프로젝트를 배포하기 위해 pex를 사용하여 수행할 수 있는 몇 가지 작업을 보여줍니다.
Pex 패키징을 위한 Python 인터프리터의 중요성을 고려하여 가상 환경을 사용하는 것이 좋습니다. 예를 들어 Python 3.11 환경을 사용하겠습니다.
$ 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 실행의 일반적인 형식은 다음과 같습니다.
pex [模块] [选项]
여기서 [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는 대화형 셸로 들어가며 제공된 모듈은 다음에서 사용할 수 있습니다.
>>> import requests >>> import setproctitle >>> import uvicorn >>>
콘솔을 닫으면 가상 환경 패키지가 전혀 영향을 받지 않은 것을 확인할 수 있습니다.
$ 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]
pex는 -r
옵션과 전달된 requirements.txt
파일을 사용하여 실행할 수 있습니다:
$ 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
参数也可以多次传递,以防您捆绑多个项目。如果您已经设置了虚拟环境,那么您可以将 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
对于已经设置了 virtualenv 的情况很有用。
pex 还支持 python 包作为模块,其结构类似于 python 打包文档中的基本结构。对于此示例,我将使用此 git 存储库中的项目布局。它包括一个带有自述文件、许可证、简单模块和 pyproject.toml 的基本布局。这足以让它被 pex
识别,就像开发模式 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 >>>
这一切都是在无需构建项目本身的情况下实现的。
pex
还可以添加测试数据和配置等重要项目的目录。在应用程序存储库中,有一个 resources
目录,其中包含一个 test_data.json
文件,如下所示:
{ "a": 1, "b": 2 }
我们可以使用 pex
和 -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 数据被加载,然后传递给 simple_math
函数,在该函数中返回正确的结果。
Python 脚本的一个功能是能够像运行基本程序一样设置入口点。对于此示例,我将使用此存储库中托管的代码。使这项工作有效的是控制台脚本的声明,如下所示:
[project.scripts] adder = "cli_pex:run"
这将生成一个名为“adder”的脚本,该脚本将从 cli_pex
包中执行 run
:
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
使用 -c
告诉 pex 我们要使用 pyproject.toml
中定义的 adder
脚本。现在,当我们打包所有内容时,它就像一个基本程序一样。还有一个使用固定参数的选项,因此只需要执行 .pex
文件:
$ pex . -o adder.pex -c adder --inject-args "--integer1 3 --integer2 4" $ ./adder.pex 7
这对于轻松部署采用绑定端口和主机名等参数的服务器脚本非常有用。
为了将这一切放在一起,我将对 pex Web 应用程序进行 Docker 部署。它将把 Gunicorn 与 Flask 应用程序捆绑在一起,该应用程序将充当容器的入口点。可以在此处找到此示例中使用的代码。在此设置中,有一个简单的 Flask 应用程序、一个 Gunicorn 配置文件和一个用于启用部署的 Dockerfile。这次 pyproject.toml
声明了一些依赖项:
dependencies = [ "flask", "gunicorn", "setproctitle", ]
另一件需要考虑的事情是,pex 需要将其打包的系统设置与目标系统相当接近。这意味着我将在 Unbuntu 盒子上构建,而我的容器将基于 Debian(更精简,并且系统足够接近)。其他一些需要完成的事情:
--inject-args
需要将 --config
参数设置为gunicorn配置.pex
文件需要设置为入口点查看要求,生成的 pex
调用将是:
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
鉴于我构建 .pex
包的解释器是 python 3.11,我将其设置为基础映像。现在剩下的就是构建 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
这将运行新创建的 flask/web-pex:latest
映像并公开端口 8000。现在使用curl 进行测试:
$ curl http://127.0.0.1:8000 Hello World
感谢 setproctitle
进程列表也变得更清晰:
$ ps aux USER 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 还提供了一些可用的工具,可以让我们创建性能更高的 docker 镜像。为了完成这项工作,我们需要将 --include-tools
添加到 pex
构建命令:
$ pex . -o web_pex.pex -c gunicorn --inject-args "--config /home/gunicorn/app/gunicorn.config.py" --include-to ols
Dockerfile 也将更新为多阶段构建以生成最终的映像:
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-bullseye RUN 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
这将分离依赖项和源编译。当 python 进行编译时,它将创建一组特定于解释器的字节码,因此不必在运行时完成。这使得事情运行得更快。 docker 构建的唯一变化是 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
查看容器内部,可以看到 gunicorn
用户的 ~/app
目录中 pex
的布局:
$ 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
关于使用 pex
打包 python 代码的介绍到此结束。这是一个有趣的系统,从 GitHub 问题来看也具有可重复构建的潜力。启用工具可以轻松地使用单个包部署,同时通过多阶段编译启用更高性能的选项。我鼓励您看看它如何增强您的 Python 项目。
위 내용은 pex: Python 실행 파일 패키징의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!