利用Docker快速构建基于devpi的企业级私有PyPI Server

2021-08-18 15:15:52 浏览数 (1)

阅读本文大约需要1.1分钟。

点击?小卡片,回复 “合集” 获取系统性的学习笔记和测试开发技能图谱

背景

我们平常使用 pip 命令安装 Python 包时,默认是去 https://pypi.python.org/simple/ 源查找相应的包下载并安装的,但是在企业内网环境我们需要发布一些私有包提供给内部用户使用时,就需要搭建自己的 PyPI Server了。

PyPI Server 方案对比

下面是目前已知的一些部署私有仓库服务的方案

框架

代理镜像

本地缓存

搜索

devpi

支持

支持

支持 Web XML RPC

DjangoPyPI

支持

不支持

支持 Web XML RPC

chishop

不支持

不支持

不支持

pypiserver

支持

不支持

不支持

Cheese Shop

不支持

不支持

支持 Web XML RPC

localshop

支持

支持

只支持 XML RPC

mypypi

不支持

不支持

不支持

proxypypi

支持

支持

不支持

Flask-Pypi-Proxy

支持

支持

不支持

介绍

devpi有一些特有的功能:

  • 支持本地缓存,可以做到公司内网加速的效果
  • 支持Sphinx文档
  • 提供多索引支持,多索引之间还可以继承,这在维护多版本系统上非常有用
  • 支持集群部署,支持一台或多台服务器部署实现访问加速
  • 支持通过 json 接口,实时监控集群的状态
  • 支持导入导出功能
  • 支持给索引设置 Jenkins 触发器,可以使用 tox 自动测试上传的包
  • 使用插件可以完成Web界面的访问控制,增加私有包的安全

容器化部署

这里介绍一下用容器的方式如何部署,首先我们这个容器中包括三个组件:

  • devpi-server 属于核心组件,提供镜像与缓存功能
  • devpi-web 提供Web界面和查询功能
  • devpi-lockdown 通过在nginx的帮助下实现对Web界面添加访问控制的功能

Dockerfile

代码语言:javascript复制
FROM suadminwen/python3-ubuntu:latest

WORKDIR /root/

RUN pip install supervisor
RUN mkdir /devpi
RUN pip install devpi-server devpi-web devpi-lockdown 
  && devpi-init 
  && devpi-gen-config --host 0.0.0.0 --port 3141

RUN apt update 
  && apt install nginx -y

COPY ./nginx-devpi.conf /etc/nginx/sites-enabled/default
COPY ./run.sh /root/

EXPOSE 31415
EXPOSE 80
 
ENTRYPOINT ["bash", "run.sh"]

nginx-devpi.conf

代码语言:javascript复制
server {
    server_name 0.0.0.0;
    listen 80;
    gzip             on;
    gzip_min_length  2000;
    gzip_proxied     any;
    gzip_types       application/json;

    proxy_read_timeout 60s;
    client_max_body_size 64M;

    # set to where your devpi-server state is on the filesystem
    root /root/.devpi/server;

    # this redirects to the login view when not logged in
    recursive_error_pages on;
    error_page 401 = @error401;
    location @error401 {
        return 302 / login;
    }

    # lock down everything by default
    auth_request / authcheck;

    location = / login {
        auth_request off;
        proxy_set_header X-outside-url $scheme://$http_host;
        proxy_pass http://localhost:3141;
    }

    location ~ / api$ {
        auth_request off;
        proxy_set_header X-outside-url $scheme://$http_host;
        proxy_pass http://localhost:3141;
    }

    # try serving static files directly
    location ~ / f/ {
        auth_request off;
        # workaround to pass non-GET/HEAD requests through to the named location below
        error_page 418 = @proxy_to_app;
        if ($request_method !~ (GET)|(HEAD)) {
            return 418;
        }

        expires max;
        try_files / files$uri @proxy_to_app;
    }
    # try serving docs directly
    location ~ / doc/ {
        auth_request off;
    # if the --documentation-path option of devpi-web is used,
    # then the root must be set accordingly here
    root /root/.devpi/server;
    try_files $uri @proxy_to_app;
            }
  location / {
    # workaround to pass all requests to / through to the named location below
    error_page 418 = @proxy_to_app;
    return 418;
  }
  location @proxy_to_app {
    proxy_pass http://localhost:3141;
    proxy_set_header X-outside-url $scheme://$http_host;
    proxy_set_header X-Real-IP $remote_addr;
  }

  location = / authcheck {
    internal;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-outside-url $scheme://$http_host;
    proxy_pass http://localhost:3141;
  }
}

run.sh

代码语言:javascript复制
echo -e 'start supervisord'
/usr/local/bin/supervisord -c /root/gen-config/supervisord.conf

echo -e 'start nginx'
nginx -g 'daemon off;'

docker-compose.yml

代码语言:javascript复制
services:
  devpiserver:
    container_name: devpiserver
    build:
      context: .
    ports:
      - 80:80
      - 31415:80
    volumes:
      - ~/.devpi:/root/.devpi

在准备好上述文件后,先在用户根目录执行下面的命令:

代码语言:javascript复制
pip install devpi-server
devpi init

然后在docker文件根目录执行下面的命令即可完成服务的启动:

代码语言:javascript复制
docker-compose up -d

使用

安装依赖

本地的操作是需要使用devpi-client来完成的,执行下面的命令安装依赖:

代码语言:javascript复制
pip install -U devpi-client

创建连接

代码语言:javascript复制
devpi use http://devpi.xxxxx.com/

用户管理

默认的用户是root,密码是空

代码语言:javascript复制
# 使用root账号登录
devpi login root --password=
# 修改root用户密码为qwe
devpi user -m root password=qwe 
# 创建新用户dev并设定密码为qwe
devpi user -c dev password=qwe
# 新用户登录
devpi login dev --password=qwe
# 退出登录
devpi logoff

索引管理

登录之后才可以进行索引操作

代码语言:javascript复制
# 创建dev索引
devpi index -c dev bases=root/pypi
# 使用dev索引
devpi use root/dev

# 当仓库中不存在包时,从豆瓣下载包缓存到本地(默认是从官方源 https://pypi.python.org/simple/ 下载)
devpi index root/dev mirror_url = “https://pypi.doubanio.com/simple/"
# devpi push 命令是将包从一个索引推送到另外一个索引,例如将包example推送到root/dev
devpi push example==1.0 root/dev

上传私有包

上传包使用的是 devpi upload 命令,需要在 setup.py 文件所在目录下执行,这个命令有两个常用的参数:

  • --with-docs 参数,连带docs文件一块上传,支持 sphinx 创建的文档
  • --formats bdist_wheel 参数,上传wheel格式的包,需要安装wheel库, pip install wheel
代码语言:javascript复制
devpi use http://pypi-xx.com/
devpi login root --password=qwe
devpi use root/dev
devpi upload --formats bdist_wheel
devpi upload --with-docs
devpi upload

删除私有包

代码语言:javascript复制
devpi remove example
devpi remove example>=1.0.1

下载私有包

无访问限制:

代码语言:javascript复制
pip install -i "http://[host]/root/dev/ simple/" [package] --trusted-host [host]

有访问限制:

代码语言:javascript复制
pip install -i "http://[user]:[password]@[host]/root/dev/ simple/" [package] --trusted-host [host]

本地环境配置

无访问限制:

代码语言:javascript复制
[global]
timeout = 60
index-url = http://pypi-xx.com/root/dev/ simple/
[install]
trusted-host = pypi-xx.com

有访问限制:

代码语言:javascript复制
[global]
timeout = 60
index-url = http://[user]:[password]@[host]/root/dev/ simple/
[install]
trusted-host = pypi-xx.com

devpi服务器迁移

如果想要前移服务器的文件,首先需要找到devpi服务器数据所在地址,进入server目录中找到 ' files' 目录拷贝出来,然后使用下面命令把已有的私有包导入新的服务中:

代码语言:javascript复制
devpi upload --from-dir ' files' 

效果图

0 人点赞