PyPI mirror 서버 구축하기 with devpi-server

2 minute read

devpi는 궁극적으로 프로덕션과 같은 외부 환경에 패키지를 배포하기 전에 개발 단계에서 사용자와 개발자 간 패키지를 공유하기 위한 메커니즘을 가진다. 또한 PyPI에 빠르고 신뢰할 만한 패키지 캐시를 제공하는 툴이다. devpi를 활용하여 PyPI가 다운되어도 전혀 영향을 받지 않는 환경을 마련할 수 있으며, 오프라인 상황에서도 파이썬 패키지에 접근할 수 있다. mirror 서버를 구축할 수 있다는 얘기이다.

devpi는 서버와 클라이언트 측의 핵심 devpi 시스템으로 구성된 3개의 패키지를 제공하고 있다.


  • devpi-server

    pypi.org의 기존 캐싱 인덱스뿐만 아니라 pypi.org로부터 패키지를 상속받아 커스터마이징할 수 있는 사용자 및 팀 기반의 인덱스를 제공

  • devpi-web

    웹 환경과 검색 인터페이스를 제공하는 devpi-server용 플러그인

  • devpi-client

    사용자 생성, 인덱스 사용, 인덱스 업로드 및 설치를 위한 하위 커맨드와 tox를 호출하기 위한 test 커맨드가 포함된 커맨드라인 툴


devpi-server 설정

devpi-server는 무엇보다도 PyPI에 대한 캐싱 프록시 서버 역할을 한다.

내 EC2 인스턴스에 virtualenv를 구동한 후 그 안에서 devpi-server를 띄우자.

(devpi) $ pip install devpi-server


설치 후 서버를 시작하기 전에 init 커맨드로 devpi 초기화를 해준다.

(devpi) $ devpi-init


초기화하면 아래와 같은 구조로 .devpi 디렉토리가 생성된다.

.devpi
└── server
    ├── .nodeinfo
    ├── .serverversion
    └── .sqlite


이제 devpi 서버를 구동한다. IP를 허용해주는 --host 옵션을 빼먹지 말자.

(devpi) $ devpi-server --start --host=0.0.0.0
2019-12-12 04:41:26,962 INFO  NOCTX Loading node info from /home/ubuntu/.devpi/server/.nodeinfo
2019-12-12 04:41:26,964 INFO  NOCTX wrote nodeinfo to: /home/ubuntu/.devpi/server/.nodeinfo
/home/ubuntu/devpi/lib/python3.6/site-packages/devpi_server/bgserver.py:31: UserWarning: Use of --start, --stop, --status and --log is deprecated. You should use a process manager of your OS, for example: systemd for Linux, Windows Services, launchd for macOS or http://supervisord.org/
Also see the devpi-gen-config command to create example configuration files for such services.
  "Use of --start, --stop, --status and --log is deprecated. "
starting background devpi-server at http://localhost:3141
/home/ubuntu/.devpi/server/.xproc/devpi-server$ /home/ubuntu/devpi/bin/devpi-server
process 'devpi-server' started pid=23797
devpi-server process startup detected
logfile is at /home/ubuntu/.devpi/server/.xproc/devpi-server/xprocess.log

devpi-server의 기본 포트는 3141이다. 포트에 대한 귀여운 유래가 있는데, 공식 문서에 따르면 원주율 PI(3.141592…)에서 따왔다고 한다. devpiPI가 들어있으니까.


devpi-server repository에서 설치 - 로컬


테스트를 위해 virtualenv를 하나 더 만들고 그 안에서 PyPI 퍼블릭 repo가 아닌, 내 EC2 인스턴스에서 구동되고 있는 devpi repo에서 패키지를 설치해볼 것이다.

pip install [패키지명] 으로 설치하면 파이썬 공식 repo인 files.pythonhosted.org/packages/...를 바라보고 패키지를 설치한다.

(playground) python -m pip install --upgrade pip
(playground) pip install flask
Downloading
https://files.pythonhosted.org/packages/9b/93/628509b8d5dc749656a9641f4caf13540e2cdec85276964ff8f43bbb1d3b/Flask-1.1.1-py2.py3-none-any.whl (94kB)


-i 옵션으로 앞에서 구동한 devpi repo에서 패키지를 설치해보자. 접속하는 URL이 다르다.

(playground) pip install -i http://localhost:3141/root/pypi/+simple/ flask
Downloading
http://localhost:3141/root/pypi/%2Bf/45e/b5a6fd193d6cf/Flask-1.1.1-py2.py3-none-any.whl (94kB)


devpi-server repository에서 설치 - EC2

EC2 내부에서는 테스트가 성공했으므로 내 로컬에서도 테스트를 해보는데 trusted host 관련 에러가 발생했다. 찾아보니 커맨드에 --trusted-host 옵션을 주거나, pip.conf 파일을 생성해서 자동으로 참조하도록 하면 된다.


  • macOS 환경
$ mkdir -p ~/.pip && cat > ~/.pip/pip.conf << EOF

[global]
index-url = http://54.180.29.144:3141/root/pypi/+simple/
trusted-host = 54.180.29.144
[search]
index = http://54.180.29.144:3141/root/pypi/


  • Unix 환경
$ vim $HOME/Library/Application Support/pip/pip.conf

[global]
index-url = http://54.180.29.144:3141/root/pypi/+simple/
trusted-host = 54.180.29.144
[search]
index = http://54.180.29.144:3141/root/pypi/


  • Windows 환경
%APPDATA%\pip\pip.ini

[global]
index-url = http://54.180.29.144:3141/root/pypi/+simple/
trusted-host = 54.180.29.144
[search]
index = http://54.180.29.144:3141/root/pypi/


아래는 PyPIdevpi의 패키지 다운로드 속도를 비교한 결과이다. 물리적인 거리가 멀기도 하고, 서양권 근무 시작과 겹쳐서 그런지 한국 시각으로 저녁~밤이 되면 유난히 다운로드 속도가 느려진다. 그래서 저녁 8시에 두 repository에 대해 가장 용량이 큰 두 파이썬 패키지로 비교해보았다.

그림1

다운로드 속도가 무려 평균 86.1%나 절감이 되었다. 저렇게 큰 패키지도 처음 볼 뿐더러 속도차가 이렇게나 많이 날 줄은 몰랐다. 공식 문서에 따르면, 30분마다 캐싱을 한다고 하는데 내부적으로 캐싱 프로세스가 어떻게 이루어지는지에 대해서는 아직 명확하게 파악하지 못했다. 이 부분을 더 공부하면서 mirror 서버 서비스에 대해 깊게 알아봐야겠다.

Categories:

Updated: