大数跨境

利用docker快速构建基于devpi的pypi仓库

利用docker快速构建基于devpi的pypi仓库 脉策科技
2019-02-15
4
导读:为了满足开发的需求, 我们基于devpi搭建了内网的pypi mirror

相信各位使用Python的朋友一定非常熟悉pypi, Python官方的软件仓库, 基本上你机器上安装的Python软件包(例如通过pip install)都是经由官方的pypi registry下载而来。


然而, 发布在pypi上的package都是公开的, 对于有一定规模的公司, 大部分都有自己内部package发布的需求, 这时候发布到pypi上, 就显得非常不合适了。



再者, 官方的pypi在国内访问速度并不理想, 而且由于不可描述的原因还经常不能访问, 于是乎大家通常都可以通过国内大厂友情赞助的mirror进行安装, 虽然对于新package有一定的延时, 不过基本问题不大。


1# 阿里云镜像
2pip install -i https://mirrors.aliyun.com/pypi/simple/
3# 豆瓣镜像
4pip install -i https://pypi.doubanio.com/simple/


对于日常自用, 掌握上面两个地址已经足够。


但是在脉策, 每天有上百个CI在自动化运行, 为了保障一致性, 大部分都需要重新安装或者对比package以减少不同环境切换的风险. 即使使用国内的镜像, 在速度和可靠性上依然满足不了我们的需求。



为了满足开发的需求, 我们基于devpi搭建了内网的pypi mirror。


首先要了解一下devpi, 除了提供远程pypi的mirror外, 还提供自发布package的管理, 非常适合公司内部发布package管理, 关于devpi的详细使用, 可以参考官方文档。


接着我们先新建一个文件夹, 准备对应的Dockerfiledocker-entrypoint.sh


👉Dockerfile


 1# 这里参考了 https://github.com/muccg/docker-devpi
2FROM python:3.6.8
3
4# 建立运行devpi需要的devpi user
5RUN useradd -m -U -s /bin/bash devpi
6# 安装devpi对应的package, 可以按需更新对应的version
7RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ \
8    "cffi==1.11.5" \
9    "devpi-client==4.0.3" \
10    "devpi-web==3.3.0" \
11    "devpi-server==4.6.0"
12# 暴露官方端口
13EXPOSE 3141
14# 指定package存储的位置, 可随意
15VOLUME /data
16# 载入对应的entrypoint文件, 用于初始化devpi
17COPY docker-entrypoint.sh /docker-entrypoint.sh
18RUN chmod +x /docker-entrypoint.sh
19
20ENV HOME /data
21WORKDIR /data
22
23ENTRYPOINT ["/docker-entrypoint.sh"]
24CMD ["devpi"]


👉docker-entrypoint.sh


 1#!/bin/bash
2

3# 设置devpi的存储路径
4function defaults {
5    : ${DEVPI_SERVERDIR="/data/devpi/server"}
6    : ${DEVPI_CLIENTDIR="/data/devpi/client"}
7
8    echo "DEVPI_SERVERDIR is ${DEVPI_SERVERDIR}"
9    echo "DEVPI_CLIENTDIR is ${DEVPI_CLIENTDIR}"
10
11    export DEVPI_SERVERDIR DEVPI_CLIENTDIR
12}
13
14# 初始化devpi
15function initialise_devpi {
16    echo "[RUN]: Initialise devpi-server"
17    devpi-server --init
18    devpi-server --start --host 127.0.0.1 --port 3141 --serverdir ${DEVPI_SERVERDIR}
19    devpi-server --status
20    devpi use http://localhost:3141
21    # 注意修改成你需要的账户密码
22    devpi user -c ${your_username} email=${your_email} password=${your_password}
23    devpi login ${your_username} --password ${your_password}
24    devpi index -c douban type=mirror mirror_url=http://pypi.douban.com/simple
25    devpi index -c aliyun type=mirror mirror_url=http://mirrors.aliyun.com/pypi/simple/
26    devpi index -c ${your_index} bases=${your_username}/aliyun,${your_username}/douban,root/pypi mirror_whitelist='*'
27    devpi index -y -c public mirror_whitelist='*'
28    devpi-server --stop
29    devpi-server --status
30}
31
32defaults
33
34if [ "$1" = 'devpi' ]; then
35    if [ ! -f  $DEVPI_SERVERDIR/.serverversion ]; then
36        initialise_devpi
37    fi
38
39    echo "[RUN]: Launching devpi-server"
40    exec devpi-server --host 0.0.0.0 --port 3141
41fi
42
43echo "[RUN]: Builtin command not provided [devpi]"
44echo "[RUN]: $@"
45
46exec "$@"


假设${your_username}=mdt, ${your_index}=pypi, 通过以上配置, 我们建立了一个名为mdt/pypi的index。


当安装package的时候, 默认会查找本地, 找不到的时候会一次去aliyun, douban, pypi查找。


接着我们需要build对应的image


1docker build -t devpi:4.6.0 .


短暂的等待镜像完成后, 运行


1docker run -d --name pypi -p 3141:3141 -v ${your_directory}:/data devpi:4.6.0 


然后就可以通过运行以下命令安装python的package了(假设你的服务器是192.168.1.101)。


1pip install --trusted-host 192.168.1.101 -i http://192.168.1.101:3141/mdt/pypi/


以上基本完成了本地pypi的搭建, 为了有更好的静态文件处理以及https支持, 建议在devpi前面再外接一个nginx。


首先得准备好对应的https的签名文件, 没有的话可以去买一个或者去let's encrypt 免费申请一个, 假设${your_directory}=/mnt/data, 然后运行


1docker exec pypi devpi-server --port 3141 --serverdir /data/devpi/server --gen-config
2cat /mnt/data/gen-config/nginx-devpi.conf


就可以获得对应的nginx配置模板, 稍加修改


 1server {
2    # server_name localhost $hostname "";
3    # listen 80;
4
5    # 启用https
6    server_name pypi.abc.com;
7    listen 443 ssl;
8    ssl_certificate abc.com.pem;
9    ssl_certificate_key abc.com.key;
10    ssl_session_timeout 5m;
11    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
12    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
13    ssl_prefer_server_ciphers on;
14
15    gzip             on;
16    gzip_min_length  2000;
17    gzip_proxied     any;
18    gzip_types       text/html application/json;
19
20    proxy_read_timeout 60s;
21    client_max_body_size 64M;
22
23    # set to where your devpi-server state is on the filesystem
24    root /data/devpi/server;
25
26    # try serving static files directly
27    location ~ /\+f/ {
28        # workaround to pass non-GET/HEAD requests through to the named location below
29        error_page 418 = @proxy_to_app;
30        if ($request_method !~ (GET)|(HEAD)) {
31            return 418;
32        }
33
34        expires max;
35        try_files /+files$uri @proxy_to_app;
36    }
37    # try serving docs directly
38    location ~ /\+doc/ {
39        try_files $uri @proxy_to_app;
40    }
41    location / {
42        # workaround to pass all requests to / through to the named location below
43        error_page 418 = @proxy_to_app;
44        return 418;
45    }
46    location @proxy_to_app {
47        # proxy_pass http://localhost:3141;
48        # 指向对应的docker位置
49        proxy_pass http://devpi:3141;
50        proxy_set_header X-outside-url $scheme://$host:$server_port;
51        proxy_set_header X-Real-IP $remote_addr;
52    }
53}


然后我们把devpi和nginx配置到对应的compose.yml


 1services:
2  nginx_dev:
3    image: nginx:1.13.9-alpine
4    entrypoint: nginx
5    command: -g "daemon off;" -c /etc/nginx/nginx.conf
6    volumes:
7      - devpi.conf:/etc/nginx/conf.d/devpi.conf:ro
8      - /mnt/data/devpi/server/:/data/devpi/server/:ro
9    ports:
10      # 80443
11      - "80:80"
12      - "443:443"
13    mem_limit: 512m
14    networks:
15      - pypi
16
17  devpi:
18    image: devpi:4.6.0
19    volumes:
20      - /mnt/data:/data
21    ports:
22      - 3141:3141
23    mem_limit: 1g
24    networks:
25      - pypi
26
27networks:
28  pypi: 
29    driver: bridge


然后运行


1docker-compose up -d


就可以通过https方式访问了


1pip install -i https://pypi.abc.com/mdt/pypi/


内网发布


正如上面所提, 除了能够提供一流的本地下载体验外, devpi也提供了内部package的发布功能, 要使用这个功能, 需要几项条件:


  1. 本身项目需要按要求准备好对应的setup.py, 具体配置方式可以参考python packaging

  2. 安装有devpi的python环境

  3. 需要发布的devpi index

  4. 对应index的账号密码


假设我们要发布到 https://pypi.abc.com/mdt/pypi/


1# 进入对应的python虚拟环境, 这里用的virtualenvwrapper
2workon devpi
3# 切换到对应的index
4devpi use https://pypi.abc.com/mdt/pypi/
5# 登录
6devpi login mdt --password ${your_password}
7devpi upload --index mdt/pypi


然后就可以像平时安装package一样去安装了。

【声明】内容源于网络
0
0
脉策科技
我们是致力于大数据和人工智能领域的科技公司,为政府和大型企业提供数据平台、数据研究、人工智能、算法服务及系统解决方案。
内容 132
粉丝 0
脉策科技 上海脉策数据科技有限公司 我们是致力于大数据和人工智能领域的科技公司,为政府和大型企业提供数据平台、数据研究、人工智能、算法服务及系统解决方案。
总阅读280
粉丝0
内容132