从源码到Docker全方位解析Python项目打包完整指南

Written by

in

文章目录
  • 在开始具体打包之前,我们先了解下主流的Python打包工具及其适用场景: 工具 适用场景 特点 输出格式 setuptools 传统Python库 Python生态标准,历史悠久 wheel, source distribution Poetry 现代Python项目 依赖管理优秀,配置简洁 wheel, source distribution PDM 新式Python项目 快速,PEP 582支持 wheel, source distribution PyInstaller 桌面应用程序 跨平台,单文件打包 EXE, APP, 可执行文件 Docker 微服务部署 环境隔离,持续交付 Docker Image Nuitka 高性能需求 编译为C,性能提升 可执行文件,扩展模块
  • Poetry是当前最流行的Python打包和依赖管理工具之一。
  • PDM是一个现代的Python包管理器,具有快速的依赖解析。
  • Python项目打包已经从简单的源码分发发展到现代化的容器化部署。掌握这些打包技术对于Python开发者至关重要。无论是传统的库分发还是现代的微服务,选择合适的打包方式都能大大提高开发和部署效率。 以上就是从源码到Docker全方位解析Python项目打包完整指南的详细内容,更多关于Python项目打包的资料请关注风君子博客其它相关文章! 您可能感兴趣的文章: python项目打包成docker镜像并运行的完整指南 将python脚本打包进docker的完整步骤记录 将Python项目打包成Docker镜像的全过程 将Python Flask服务打包成Docker镜像并运行的完整指南 Docker打包一个Python脚本的实现方法 Python项目打包并部署到Docker详细步骤 详解如何使用Docker打包Python项目
  • 目录
    • 一、Python打包工具全景图
    • 二、传统setuptools打包详解
      • 2.1 项目结构准备
      • 2.2 基础setup.py配置
      • 2.3 进阶配置(setup.cfg)
      • 2.4 打包命令
    • 三、Poetry现代化打包
      • 3.1 项目初始化
      • 3.2 pyproject.toml配置
      • 3.3 Poetry命令
    • 四、PDM快速打包
      • 4.1 PDM项目配置
      • 4.2 pyproject.toml (PDM版本)
      • 4.3 PDM命令
    • 五、可执行文件打包
      • 5.1 使用PyInstaller
      • 5.2 使用cx_Freeze
    • 六、Docker容器化部署
      • 6.1 多阶段构建Dockerfile
      • 6.2 优化版Dockerfile(Poetry)
      • 6.3 Docker Compose编排
    • 七、高级打包技巧
      • 7.1 使用Nuitka编译优化
      • 7.2 自动化构建脚本
      • 7.3 GitHub Actions自动化
    • 八、最佳实践总结
      • 8.1 项目结构标准化
      • 8.2 依赖管理最佳实践
      • 8.3 安全考虑
      • 8.4 性能优化
    • 结语

      在开始具体打包之前,我们先了解下主流的Python打包工具及其适用场景:

      工具 适用场景 特点 输出格式
      setuptools 传统Python库 Python生态标准,历史悠久 wheel, source distribution
      Poetry 现代Python项目 依赖管理优秀,配置简洁 wheel, source distribution
      PDM 新式Python项目 快速,PEP 582支持 wheel, source distribution
      PyInstaller 桌面应用程序 跨平台,单文件打包 EXE, APP, 可执行文件
      Docker 微服务部署 环境隔离,持续交付 Docker Image
      Nuitka 高性能需求 编译为C,性能提升 可执行文件,扩展模块

      一个标准的Python项目结构如下:

      MyProject/
      ├── src/
      │   └── mypackage/
      │       ├── __init__.py
      │       ├── main.py
      │       └── utils.py
      ├── tests/
      ├── docs/
      ├── requirements.txt
      └── setup.py

      # setup.py - 基础配置
      from setuptools import setup, find_packages
      
      setup(
          name="myproject",
          version="1.0.0",
          author="Your Name",
          author_email="your.email@example.com",
          description="A sample Python project",
          long_description=open("README.md").read(),
          long_description_content_type="text/markdown",
          packages=find_packages(where="src"),
          package_dir={"": "src"},
          classifiers=[
              "Development Status :: 3 - Alpha",
              "Intended Audience :: Developers",
              "License :: OSI Approved :: MIT License",
              "Programming Language :: Python :: 3",
              "Programming Language :: Python :: 3.8",
              "Programming Language :: Python :: 3.9",
              "Programming Language :: Python :: 3.10",
          ],
          python_requires=">=3.8",
          install_requires=[
              "requests>=2.25.0",
              "click>=8.0.0",
          ],
          entry_points={
              "console_scripts": [
                  "myproject=mypackage.main:main",
              ],
          },
      )
      

      # setup.cfg - 现代配置方式
      [metadata]
      name = myproject
      version = 1.0.0
      author = Your Name
      author_email = your.email@example.com
      description = A sample Python project
      long_description = file: README.md
      long_description_content_type = text/markdown
      url = https://github.com/username/myproject
      classifiers =
          Development Status :: 3 - Alpha
          Intended Audience :: Developers
          License :: OSI Approved :: MIT License
          Programming Language :: Python :: 3
          Programming Language :: Python :: 3.8
          Programming Language :: Python :: 3.9
          Programming Language :: Python :: 3.10
      
      [options]
      packages = find:
      package_dir =
          = src
      python_requires = >=3.8
      install_requires =
          requests>=2.25.0
          click>=8.0.0
      
      [options.packages.find]
      where = src
      
      [options.entry_points]
      console_scripts =
          myproject = mypackage.main:main
      

      # 安装构建工具
      pip install build
      
      # 构建源码包和wheel包
      python -m build
      
      # 或者使用传统方式
      python setup.py sdist bdist_wheel
      
      # 安装到当前环境(开发模式)
      pip install -e .
      
      # 清理构建文件
      python setup.py clean --all
      rm -rf build dist *.egg-info
      

      Poetry是当前最流行的Python打包和依赖管理工具之一。

      # 创建新项目
      poetry new myproject
      cd myproject
      
      # 或在现有项目初始化
      poetry init
      

      # pyproject.toml - Poetry配置
      [tool.poetry]
      name = "myproject"
      version = "1.0.0"
      description = "A sample Python project"
      authors = ["Your Name <your.email@example.com>"]
      readme = "README.md"
      license = "MIT"
      
      [tool.poetry.dependencies]
      python = "^3.8"
      requests = "^2.25.0"
      click = "^8.0.0"
      
      [tool.poetry.dev-dependencies]
      pytest = "^7.0.0"
      black = "^22.0.0"
      flake8 = "^4.0.0"
      
      [tool.poetry.scripts]
      myproject = "myproject.main:main"
      
      [build-system]
      requires = ["poetry-core>=1.0.0"]
      build-backend = "poetry.core.masonry.api"
      
      # 可选:工具配置
      [tool.black]
      line-length = 88
      target-version = ['py38']
      
      [tool.pytest.ini_options]
      testpaths = ["tests"]
      

      # 安装依赖
      poetry install
      
      # 添加依赖
      poetry add requests
      poetry add --dev pytest
      
      # 构建项目
      poetry build
      
      # 发布到PyPI
      poetry publish
      
      # 运行脚本
      poetry run myproject
      
      # 进入虚拟环境
      poetry shell
      

      PDM是一个现代的Python包管理器,具有快速的依赖解析。

      # 初始化项目
      pdm init
      
      # 添加依赖
      pdm add requests click
      pdm add -d pytest black
      

      [project]
      name = "myproject"
      version = "1.0.0"
      description = "A sample Python project"
      authors = [
          {name = "Your Name", email = "your.email@example.com"}
      ]
      dependencies = [
          "requests>=2.25.0",
          "click>=8.0.0"
      ]
      requires-python = ">=3.8"
      
      [project.optional-dependencies]
      dev = [
          "pytest>=7.0.0",
          "black>=22.0.0"
      ]
      
      [project.scripts]
      myproject = "myproject.main:main"
      
      [build-system]
      requires = ["pdm-backend"]
      build-backend = "pdm.backend"
      

      # 安装依赖
      pdm install
      
      # 构建项目
      pdm build
      
      # 运行脚本
      pdm run myproject
      
      # 锁定依赖
      pdm lock
      

      # build_spec.py - PyInstaller构建配置
      import PyInstaller.__main__
      
      PyInstaller.__main__.run([
          'src/mypackage/main.py',
          '--name=myproject',
          '--onefile',  # 单文件打包
          '--windowed',  # 无控制台窗口(GUI应用)
          '--add-data=src/mypackage/data;mypackage/data',  # 包含数据文件
          '--icon=assets/icon.ico',  # 应用图标
          '--hidden-import=some_hidden.module',  # 隐藏导入
          '--clean',  # 清理临时文件
      ])
      
      # 命令行方式
      pyinstaller src/mypackage/main.py --onefile --name myproject
      
      # 使用spec文件
      pyinstaller myproject.spec
      

      # setup_cxfreeze.py
      import sys
      from cx_Freeze import setup, Executable
      
      build_exe_options = {
          "packages": ["os", "sys", "requests"],
          "excludes": ["tkinter"],
          "include_files": ["data/", "config.ini"],
      }
      
      base = None
      if sys.platform == "win32":
          base = "Win32GUI"  # 用于GUI应用
      
      setup(
          name="myproject",
          version="1.0.0",
          description="My Python Application",
          options={"build_exe": build_exe_options},
          executables=[Executable("src/mypackage/main.py", base=base)],
      )
      

      # 第一阶段:构建阶段
      FROM python:3.9-slim as builder
      
      WORKDIR /app
      
      # 安装构建依赖
      RUN apt-get update && apt-get install -y 
          gcc 
          && rm -rf /var/lib/apt/lists/*
      
      # 创建虚拟环境
      RUN python -m venv /opt/venv
      ENV PATH="/opt/venv/bin:$PATH"
      
      # 安装依赖
      COPY requirements.txt .
      RUN pip install --no-cache-dir -r requirements.txt
      
      # 第二阶段:运行阶段
      FROM python:3.9-slim
      
      WORKDIR /app
      
      # 创建非root用户
      RUN groupadd -r appuser && useradd -r -g appuser appuser
      
      # 从构建阶段拷贝虚拟环境
      COPY --from=builder /opt/venv /opt/venv
      ENV PATH="/opt/venv/bin:$PATH"
      
      # 拷贝应用代码
      COPY --chown=appuser:appuser . .
      
      # 切换到非root用户
      USER appuser
      
      # 健康检查
      HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 
          CMD curl -f http://localhost:8000/health || exit 1
      
      # 暴露端口
      EXPOSE 8000
      
      # 启动命令
      CMD ["python", "-m", "mypackage.main"]
      

      # 使用多阶段构建优化镜像大小
      FROM python:3.9-slim as builder
      
      WORKDIR /app
      
      # 安装系统依赖
      RUN apt-get update && apt-get install -y --no-install-recommends 
          gcc 
          && rm -rf /var/lib/apt/lists/*
      
      # 安装Poetry
      RUN pip install poetry
      
      # 配置Poetry不创建虚拟环境
      RUN poetry config virtualenvs.create false
      
      # 拷贝依赖文件
      COPY pyproject.toml poetry.lock* ./
      
      # 安装依赖(仅运行时)
      RUN poetry install --no-dev --no-interaction --no-ansi
      
      # 运行阶段
      FROM python:3.9-slim
      
      WORKDIR /app
      
      # 创建非root用户
      RUN groupadd -r appuser && useradd -r -g appuser appuser
      
      # 从构建阶段拷贝已安装的包
      COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
      COPY --from=builder /usr/local/bin /usr/local/bin
      
      # 拷贝应用代码
      COPY --chown=appuser:appuser . .
      
      USER appuser
      
      # 设置环境变量
      ENV PYTHONPATH=/app
      ENV PYTHONUNBUFFERED=1
      
      EXPOSE 8000
      
      CMD ["python", "-m", "mypackage.main"]
      

      # docker-compose.yml
      version: '3.8'
      
      services:
        app:
          build: .
          ports:
            - "8000:8000"
          environment:
            - DATABASE_URL=postgresql://user:pass@db:5432/myapp
            - REDIS_URL=redis://redis:6379/0
          depends_on:
            - db
            - redis
          networks:
            - app-network
          healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
            interval: 30s
            timeout: 10s
            retries: 3
      
        db:
          image: postgres:13
          environment:
            POSTGRES_DB: myapp
            POSTGRES_USER: user
            POSTGRES_PASSWORD: pass
          volumes:
            - db_data:/var/lib/postgresql/data
          networks:
            - app-network
      
        redis:
          image: redis:6-alpine
          volumes:
            - redis_data:/data
          networks:
            - app-network
      
      volumes:
        db_data:
        redis_data:
      
      networks:
        app-network:
          driver: bridge
      

      # 基础编译
      nuitka3 --standalone --onefile src/mypackage/main.py
      
      # 优化版本
      nuitka3 
          --standalone 
          --onefile 
          --enable-plugin=pyqt5 
          --include-package-data=mypackage 
          --output-filename=myapp 
          src/mypackage/main.py
      
      # Windows特定优化
      nuitka3 --windows-icon-from-ico=assets/icon.ico src/mypackage/main.py
      

      #!/bin/bash
      # build.sh - Python项目自动构建脚本
      
      set -e
      
      echo "🚀 开始构建Python项目..."
      
      # 清理构建目录
      echo "🧹 清理构建文件..."
      rm -rf build/ dist/ *.egg-info/ .pytest_cache/ __pycache__/
      find . -name "*.pyc" -delete
      
      # 代码检查
      echo "🔍 运行代码检查..."
      python -m flake8 src/
      python -m black --check src/
      python -m isort --check-only src/
      
      # 运行测试
      echo "🧪 运行测试..."
      python -m pytest tests/ -v
      
      # 构建包
      echo "📦 构建分发包..."
      python -m build
      
      # 构建Docker镜像
      echo "🐳 构建Docker镜像..."
      docker build -t myproject:latest .
      
      echo "✅ 构建完成!"
      echo "📦 分发包位置: dist/"
      echo "🐳 Docker镜像: myproject:latest"
      

      # .github/workflows/ci-cd.yml
      name: Python CI/CD
      
      on:
        push:
          branches: [ main ]
        pull_request:
          branches: [ main ]
      
      jobs:
        test:
          runs-on: ubuntu-latest
          strategy:
            matrix:
              python-version: [3.8, 3.9, 3.10]
      
          steps:
          - uses: actions/checkout@v3
          
          - name: Set up Python ${{ matrix.python-version }}
            uses: actions/setup-python@v3
            with:
              python-version: ${{ matrix.python-version }}
              cache: 'pip'
              
          - name: Install dependencies
            run: |
              python -m pip install --upgrade pip
              pip install -e .[dev]
              
          - name: Lint with flake8
            run: |
              flake8 src/ tests/ --count --show-source --statistics
              
          - name: Test with pytest
            run: |
              pytest tests/ -v
              
        deploy:
          needs: test
          runs-on: ubuntu-latest
          if: github.ref == 'refs/heads/main'
          
          steps:
          - uses: actions/checkout@v3
          
          - name: Build and push Docker image
            run: |
              echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
              docker build -t myproject:${{ github.sha }} .
              docker push myproject:${{ github.sha }}
      

      myproject/
      ├── src/
      │   └── mypackage/
      │       ├── __init__.py
      │       ├── main.py
      │       └── utils.py
      ├── tests/
      │   ├── __init__.py
      │   └── test_main.py
      ├── docs/
      ├── scripts/
      │   └── build.sh
      ├── .github/
      │   └── workflows/
      ├── Dockerfile
      ├── docker-compose.yml
      ├── pyproject.toml
      ├── README.md
      └── .gitignore

      # pyproject.toml - 依赖管理示例
      [project]
      dependencies = [
          "requests>=2.25.0,<3.0.0",  # 版本范围
          "click>=8.0.0",
      ]
      
      [project.optional-dependencies]
      dev = [
          "pytest>=7.0.0",
          "black>=22.0.0",
          "flake8>=4.0.0",
      ]
      test = [
          "pytest>=7.0.0",
          "pytest-cov>=3.0.0",
      ]
      docs = [
          "sphinx>=4.0.0",
          "sphinx-rtd-theme>=1.0.0",
      ]
      

      # 安全加固的Dockerfile
      FROM python:3.9-slim
      
      # 安全更新
      RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*
      
      # 创建非特权用户
      RUN groupadd -r appuser && useradd -r -g appuser -s /bin/false appuser
      
      # 应用适当的文件权限
      RUN chown -R appuser:appuser /app
      USER appuser
      
      # 使用可信的基础镜像
      # 定期更新依赖
      # 扫描安全漏洞
      

      # 优化版Dockerfile
      FROM python:3.9-slim
      
      # 使用国内镜像源加速
      RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
      
      # 禁用缓存和pip版本检查
      ENV PIP_NO_CACHE_DIR=1
      ENV PIP_DISABLE_PIP_VERSION_CHECK=1
      
      # 优化Python设置
      ENV PYTHONUNBUFFERED=1
      ENV PYTHONDONTWRITEBYTECODE=1
      

      Python项目打包已经从简单的源码分发发展到现代化的容器化部署。掌握这些打包技术对于Python开发者至关重要。无论是传统的库分发还是现代的微服务,选择合适的打包方式都能大大提高开发和部署效率。

      以上就是从源码到Docker全方位解析Python项目打包完整指南的详细内容,更多关于Python项目打包的资料请关注风君子博客其它相关文章!

      您可能感兴趣的文章:

      • python项目打包成docker镜像并运行的完整指南
      • 将python脚本打包进docker的完整步骤记录
      • 将Python项目打包成Docker镜像的全过程
      • 将Python Flask服务打包成Docker镜像并运行的完整指南
      • Docker打包一个Python脚本的实现方法
      • Python项目打包并部署到Docker详细步骤
      • 详解如何使用Docker打包Python项目

      站内搜索