使用Docker搭建私有PyPI镜像仓库的完整步骤教学

 更新时间:2025年09月15日 10:07:57   作者:东方佑  
在企业内网或离线开发环境中,我们常常需要一个稳定、快速且可控制的 Python 包管理方案,本文将详细介绍如何使用 devpi 和 Docker 构建一个私有的 PyPI 镜像服务器,有需要的小伙伴可以了解下

在企业内网或离线开发环境中,我们常常需要一个稳定、快速且可控制的 Python 包管理方案。本文将详细介绍如何使用 devpi 和 Docker 构建一个私有的 PyPI 镜像服务器,并实现对 Windows 与 Linux 平台的 64 位二进制包(wheel) 的自动下载、缓存和分发。

通过本教程,你可以:

  • 快速搭建本地 PyPI 缓存服务器;
  • 支持不同操作系统平台(win_amd64 / manylinux);
  • 自动从国内镜像源(阿里云)预下载指定依赖包;
  • 实现高效、安全的企业级 Python 包管理。

准备工作

1. 创建项目结构

首先,在你的项目目录中创建以下文件结构:

pypi-mirror/
├── init/
│   ├── Dockerfile
│   └── setup-devpi.sh
├── docker-compose.yml
├── requirements.txt          # 待安装的包列表
└── devpi-data/               # 数据持久化目录(自动生成)

注意:首次运行前需手动创建空的 devpi-data 目录用于存储 devpi 数据。

2. 编写 Dockerfile(./init/Dockerfile)

# 使用 Python 3.10 作为基础镜像(国内加速)
FROM python:3.10

# 设置环境变量,使用阿里云 PyPI 镜像
ENV PIP_DEFAULT_TIMEOUT=100 \
    PIP_RETRIES=5 \
    PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/ \
    PIP_TRUSTED_HOST=mirrors.aliyun.com

# 安装 devpi 相关组件
RUN pip install --no-cache-dir devpi-server devpi-web devpi-client passlib

# 创建数据目录
RUN mkdir -p /data/server

# 暴露端口
EXPOSE 3141

# 启动 devpi-server
CMD ["devpi-server", "--host", "0.0.0.0", "--port", "3141", "--serverdir", "/data/server"]

说明:

  • 使用阿里云镜像提升国内网络下载速度。
  • 安装了 devpi-server(服务端)、devpi-web(Web 界面)、devpi-client(命令行工具)。
  • 所有数据保存在 /data/server,通过卷挂载实现持久化。

3. 编写初始化脚本(./init/setup-devpi.sh)

该脚本负责配置 devpi 用户、索引,并根据 requirements.txt 下载并上传指定包及其依赖。

#!/bin/bash
set -e

echo "配置 devpi 客户端..."
devpi use http://localhost:3141

# 创建用户
echo "创建用户和索引..."
devpi user -c mirroruser password=securepassword123 || echo "用户已存在"

# 登录该用户(关键步骤!否则无法操作索引)
echo "登录新创建的用户..."
devpi login mirroruser --password=securepassword123

# 创建主索引
devpi index -c main bases=root/pypi || echo "索引已存在"

# 切换到主索引
devpi use mirroruser/main

# 创建临时目录
mkdir -p /tmp/packages

# 设置 pip 使用阿里云镜像
export PIP_INDEX_URL="https://mirrors.aliyun.com/pypi/simple/"
export PIP_TRUSTED_HOST="mirrors.aliyun.com"

echo "开始处理 requirements.txt 中的包..."

# 检查 requirements.txt 是否存在
if [ ! -f "/app/requirements.txt" ]; then
    echo "错误: /app/requirements.txt 文件不存在!"
    exit 1
fi

# 第一阶段:解析所有包及依赖
all_packages=()
while IFS= read -r package; do
  [[ -z "$package" || "$package" =~ ^# ]] && continue
  echo "分析包: $package"
  
  # 获取依赖(模拟安装但不实际安装)
  dependencies=$(pip install --no-deps --dry-run "$package" 2>&1 | grep 'Collecting' | awk '{print $2}' | sed 's/[<=>].*//')

  all_packages+=("$package")
  while IFS= read -r dep; do
    [[ -z "$dep" ]] && continue
    all_packages+=("$dep")
  done <<< "$dependencies"
done < /app/requirements.txt

# 去重排序
unique_packages=($(printf "%s\n" "${all_packages[@]}" | sort -u))

# 第二阶段:下载 64 位平台 wheel 包
echo "正在下载 64 位平台二进制包..."
for package in "${unique_packages[@]}"; do
  echo "处理 $package..."
  rm -f /tmp/packages/*  # 清空临时目录

  # 下载 Windows 64-bit 包(Python 3.13 兼容)
  echo "  下载 win_amd64 版本..."
  pip download --only-binary=:all: --python-version 313 --platform win_amd64 \
    -i https://mirrors.aliyun.com/pypi/simple/ -d /tmp/packages "$package" > /dev/null 2>&1

  # 下载 Linux x86_64 包(manylinux)
  echo "  下载 manylinux_2_17_x86_64 版本..."
  pip download --only-binary=:all: --python-version 313 --platform manylinux_2_17_x86_64 \
    -i https://mirrors.aliyun.com/pypi/simple/ -d /tmp/packages "$package" > /dev/null 2>&1

  # 上传到 devpi
  for whl in /tmp/packages/*.whl; do
    if [ -f "$whl" ]; then
      echo "  上传 $whl 到私有仓库..."
      devpi upload "$whl"
    fi
  done
done

# 第三阶段:创建平台专用索引
echo "创建平台过滤索引..."

devpi index -c win_amd64 bases=main \
    mirrorsync=1 \
    platform=win_amd64 \
    python_version=3.13 || echo "索引 win_amd64 已存在"

devpi index -c linux_x86_64 bases=main \
    mirrorsync=1 \
    platform=manylinux_2_17_x86_64 \
    python_version=3.13 || echo "索引 linux_x86_64 已存在"

echo "✅ 初始化完成!DevPI 私有仓库已就绪。"

echo ""
echo "📌 使用方式如下:"
echo "   Windows 用户:"
echo "     pip install -i http://<YOUR_LOCAL_IP>:3141/mirroruser/win_amd64/+simple/ <package>"
echo ""
echo "   Linux 用户:"
echo "     pip install -i http://<YOUR_LOCAL_IP>:3141/mirroruser/linux_x86_64/+simple/ <package>"
echo ""
echo "💡 提示:请将 <YOUR_LOCAL_IP> 替换为宿主机 IP 地址(如 192.168.1.100)"

安全建议:

  • 生产环境下应修改默认密码;
  • 可启用 HTTPS 和认证机制增强安全性。

4. 配置 Docker Compose(docker-compose.yml)

version: '3.8'

services:
  devpi:
    build:
      context: .
      dockerfile: init/Dockerfile
    container_name: pypi-mirror
    ports:
      - "3141:3141"
    volumes:
      - ./devpi-data:/data/server
      - ./init/setup-devpi.sh:/setup-devpi.sh
      - ./requirements.txt:/app/requirements.txt
    environment:
      - DEVPISERVER_SERVERDIR=/data/server
    restart: unless-stopped
    entrypoint: >
      sh -c "
        if [ ! -f /data/server/.serverversion ]; then
          devpi-init --serverdir /data/server;
        fi;
        devpi-server --host 0.0.0.0 --port 3141 --serverdir /data/server &
        sleep 20 &&
        /setup-devpi.sh &&
        wait
      "

功能说明:

  • 第一次启动时自动初始化 devpi 数据目录;
  • 后续启动直接复用已有数据;
  • 脚本延迟执行确保服务已就绪;
  • 支持容器重启后自动恢复服务。

获取热门包列表并生成 requirements.txt

为了构建一个实用的私有镜像,我们可以基于 PyPI 上最受欢迎的包 来填充初始内容。

步骤一:下载 top-pypi-packages.csv

访问 https://hugovk.github.io/top-pypi-packages/

点击 “Download CSV” 下载最新的 top-pypi-packages.csv 文件。

步骤二:使用 gen_requirements.py 生成 requirements.txt

假设你有一个脚本 gen_requirements.py,其功能是从 CSV 中提取前 N 个最流行包名,输出为 requirements.txt

示例代码(gen_requirements.py):

import csv

# 读取 top-pypi-packages.csv,提取前 50 个包
with open('top-pypi-packages.csv', newline='', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    packages = [row['project'] for row in reader]

# 写入 requirements.txt
with open('requirements.txt', 'w') as f:
    for pkg in packages[:50]:  # 取前 50 名
        f.write(f"{pkg}\n")

print("✅ 已生成 requirements.txt,包含前 50 个热门 PyPI 包")

运行后生成的 requirements.txt 示例:

requests
urllib3
certifi
idna
charset_normalizer
click
flask
...

启动服务

第一步:构建并启动容器

docker-compose up --build

首次运行会经历以下过程:

  • 构建镜像;
  • 初始化 devpi 数据目录;
  • 启动 devpi-server;
  • 执行 setup-devpi.sh 脚本,下载并上传包;
  • 创建平台专用索引。

时间消耗:取决于 requirements.txt 中包的数量和网络速度,可能需要数分钟。

第二步:查看 Web 界面

打开浏览器访问:

http://localhost:3141/mirroruser/main/+simple/

你将看到所有已上传包的简单索引页面。

客户端安装测试

Windows 用户

pip install -i http://192.168.1.100:3141/mirroruser/win_amd64/+simple/ requests

Linux 用户

pip install -i http://192.168.1.100:3141/mirroruser/linux_x86_64/+simple/ pandas

成功标志:

  • 不再连接公网 PyPI;
  • 直接从本地服务器下载 .whl 文件;
  • 安装速度快,稳定性高。

日常使用命令

命令说明
docker-compose up启动服务(无需重建)
docker-compose down停止并移除容器
docker-compose logs查看日志调试问题

数据已挂载至 ./devpi-data,即使删除容器也不会丢失已缓存的包。

高级特性与扩展建议

支持更多平台

可以扩展脚本支持其他平台,例如:

  • macosx_11_0_arm64(M1/M2 Mac)
  • linux_aarch64

只需添加对应的 --platform 参数即可。

定期更新包

可通过定时任务拉取新版本包,保持私有仓库同步。

添加身份验证与权限控制

devpi 支持细粒度用户权限管理,可用于团队协作场景。

集成 CI/CD 流程

在内部 CI 环境中设置此镜像为默认源,避免外部依赖风险。

总结

本文介绍了一种完整的解决方案,利用 devpi + Docker + 阿里云镜像 + 多平台 wheel 分发 技术栈,打造了一个高性能、跨平台、可持久化的私有 PyPI 仓库。

适用场景:

  • 企业内网隔离环境;
  • 开发团队统一依赖管理;
  • 提升 CI/CD 构建效率;
  • 减少对外部源的依赖与安全风险。

核心优势:

  • 自动化初始化流程;
  • 支持平台差异化索引;
  • 国内镜像加速下载;
  • 易于部署与维护。

现在就开始搭建属于你自己的私有 PyPI 仓库吧!

GitHub 参考资源:

到此这篇关于使用Docker搭建私有PyPI镜像仓库的完整步骤教学的文章就介绍到这了,更多相关Docker搭建私有PyPI镜像仓库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 用docker搭建selenium grid分布式环境实践之路

    用docker搭建selenium grid分布式环境实践之路

    这篇文章主要介绍了用docker搭建selenium grid分布式环境实践之路,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 在Docker容器下运行cronjob的全过程

    在Docker容器下运行cronjob的全过程

    当您想要安排计划任务,可以使用内置在 macOS 和 Linux 中的常见工具,比如 cron,或者像 AWS Lambda 这样的特殊工具,,Cron 不如 AWS Lambda 强大,但它在 Unix 系统的后台任务中工作得很好,特别是在使用容器的情况下,本文给大家介绍了在Docker容器下运行cronjob的全过程
    2026-01-01
  • 从Docker容器中备份整个PostgreSQL的操作步骤

    从Docker容器中备份整个PostgreSQL的操作步骤

    现在需要从Docker容器中备份整个PostgreSQL后,然后,使用备份文件在另外一个pg的docker容器中恢复过来,所以本文给大家介绍了从Docker容器中备份整个PostgreSQL的操作步骤,通过代码示例讲解的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2024-10-10
  • 使用Nexus创建Docker仓库的方法步骤

    使用Nexus创建Docker仓库的方法步骤

    这篇文章主要介绍了使用Nexus创建Docker仓库的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 私有云存储Minio Docker镜像无法启动,提示:Adding local Minio host to 'mc' configuration

    私有云存储Minio Docker镜像无法启动,提示:Adding local Minio

    使用Minio在本地搭建私有云存储时出现无法启动,查看日志频繁输出“Adding local Minio host to 'mc' configuration...”,然后停止了,本文给大家分享私有云存储Minio Docker镜像无法启动,提示:Adding local Minio host to 'mc' configuration,感兴趣的朋友一起看看吧
    2023-11-11
  • docker 使用mysqldump命令备份导出项目中的mysql数据

    docker 使用mysqldump命令备份导出项目中的mysql数据

    这篇文章主要介绍了docker 使用mysqldump命令备份导出项目中的mysql数据本文通过命令给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12
  • 详解利用ELK搭建Docker容器化应用日志中心

    详解利用ELK搭建Docker容器化应用日志中心

    这篇文章主要介绍了详解利用ELK搭建Docker容器化应用日志中心,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • Docker磁盘空间使用分析与清理的方法

    Docker磁盘空间使用分析与清理的方法

    本篇文章主要介绍了Docker磁盘空间使用分析与清理的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • docker搭建zookeeper集群和kafka集群并使用Java测试详解

    docker搭建zookeeper集群和kafka集群并使用Java测试详解

    本文详细介绍了如何在Linux虚拟机中使用Docker搭建Kafka集群环境,并通过Kafka-Manager进行可视化管理,文章包括了从镜像拉取、容器网络设置、Zookeeper和Kafka集群搭建到测试和使用Java连接集群的全过程
    2026-01-01
  • 解决docker run 或者 docker restart 启动镜像就自动退出

    解决docker run 或者 docker restart 启动镜像就自动退出

    这篇文章主要介绍了解决docker run 或者 docker restart 启动镜像就自动退出的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11

最新评论