파이썬 패키지 저장소는 파이썬 패키지를 호스팅하여 개발자가 라이브러리를 게시하고 배포할 수 있는 중앙 웹 사이트입니다. PyPI(Python Package Index)를 호스팅하거나 미러링하여 네트워크 내에서 Python 패키지에 빠르고 신뢰할 수 있는 액세스를 제공하는 것이 중요합니다. 특히 네트워크 대역폭이 제한되었거나 인터넷 연결이 불안정한 환경에서는 더욱 중요합니다.
전제 조건
- 관리 권한이 있는 Red Hat 또는 Rocky Linux 8 시스템이 있어야 합니다.
- 필요한 패키지를 다운로드하려면 인터넷에 액세스해야 합니다.
- PyPI 저장소를 위한 충분한 저장 공간(1TB)이 필요할 수 있으며, 해당 패키지를 저장할 데이터 파티션을 설정할 수 있습니다.
실행 단계
— Bandersnatch 사용
- 필수 패키지 설치: python3, pip, virtualenv이 설치되어 있는지 확인해주세요.
sudo dnf install python2 python3 python3-pip python3-virtualenv vim -y
python3 -m venv venv
source venv/bin/activate
- Bandersnatch 설치: Bandersnatch는 PyPI를 미러링하는 도구입니다.
pip install --upgrade pip
pip install dataclasses
pip install bandersnatch
- Bandersnatch 구성: 초기 구성 파일을 생성하고 편집하세요.
a. 구성 파일을 생성하려면 처음으로 bandersnatch 미러 명령을 실행하십시오.
밴더스내치 미러
2024–07–14 00:04:36,297 경고: 설정 파일 ‘/etc/bandersnatch.conf’이 누락되어 기본 설정이 생성되었습니다.
2024–07-14 00:04:36,297 경고: 설정 파일을 검토한 후 ‘bandersnatch’를 다시 실행해주세요.
b. 거울 데이터를 저장할 디렉토리에 대한 구성 파일 매개변수를 업데이트하세요. 제 경우에는 데이터 파티션을 만드는 것이죠. 여러분의 설정은 다를 수 있어요.
vim /etc/bandersnatch.conf
...
directory = /data/
...
파일을 저장하세요.
명령을 다시 실행하면 bandersnatch mirror가 실행됩니다.
bandersnatch mirror
2024-07-14 00:09:40,793 INFO: 선택된 스토리지 백엔드: 파일 시스템
2024-07-14 00:09:40,860 ERROR: swift_plugin = bandersnatch_storage_plugins.swift:SwiftStorage 진입점 로드 불가능: 'keystoneauth1' 모듈을 찾을 수 없음
2024-07-14 00:09:40,911 INFO: 미러 디렉토리 설정 중: /data/web/simple
2024-07-14 00:09:40,912 INFO: 미러 디렉토리 설정 중: /data/web/packages
2024-07-14 00:09:40,913 INFO: 미러 디렉토리 설정 중: /data/web/local-stats/days
2024-07-14 00:09:40,913 INFO: 생성 파일이 누락되었습니다. 상태 파일을 다시 초기화합니다.
2024-07-14 00:09:40,914 INFO: status 파일 /data/status 누락됨. 처음부터 다시 시작합니다.
2024-07-14 00:09:40,914 INFO: https://pypi.org와 동기화 중.
2024-07-14 00:09:40,914 INFO: 현재 미러 일련번호: 0
2024-07-14 00:09:40,914 INFO: 모든 패키지 동기화 중.
명령이 다시 실행되어 모든 패키지가 pypi 웹사이트에서 다운로드됩니다.
이 데이터를 웹 서버로 복사하거나 웹 서버를 설정해보세요.
- 웹 서버 설치: 아파치 httpd 웹 서버를 설치합니다.
sudo dnf install httpd
sudo systemctl start httpd
sudo systemctl enable httpd
- 웹 서버 구성: 웹 서버를 PyPI 미러가 저장된 디렉토리로 지정합니다.
sudo vim /etc/httpd/conf.d/pypi_repo.conf
Alias /pypi /var/www/html/pypi
<Directory /var/www/html/pypi>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
sudo systemctl restart httpd
- 클라이언트가 로컬 저장소를 사용하도록 구성하기: 클라이언트 기기에서 pip를 사용하여 로컬 PyPI 미러를 사용하도록 구성합니다.
mkdir -p ~/.config/pip
cat << EOF > ~/.config/pip/pip.conf
[global]
index-url = http://mywebserver.example.com/pypi/simple
EOF
Bandersnatcher의 문제는 선택적 미러링을 할 수 없다는 것입니다. 왜냐하면 pypi 서버로부터 전체 내용을 가져오기 때문입니다. 이 문제를 해결하기 위해 개발자가 모든 선택적 다운로드를 위한 라이브러리 minirepo를 제공했고, 이를 아래에서 나열해보겠습니다.
— Minirepo과 pypi-server를 사용 중
안녕하세요! 라즈베리 파이를 설정한 사람의 정보를 바탕으로 이 라이브러리들을 테스트하고 있는데, 재미있는 일이 있었어요. 여러 오류를 마주쳤지만 그 덕분에 코드에서 버그를 발견하고 고칠 수 있었어요. 저의 수정 사항은 여기에서 확인할 수 있어요. 필요하시면 제 수정 사항을 자유롭게 적용해 보세요.
- Python3 호환성 문제
- XML 구문 분석 오류 문제
파이썬 파이프 파이프 파프리리바 리프 파이사이사이 사이브
이제 처음으로 minirepo를 실행하면 json 형식의 .minirepo 파일 이름을 요청합니다.
minirepo
/******** Minirepo ********/
Traceback (most recent call last):
File "/root/venv/lib64/python3.6/site-packages/minirepo.py", line 206, in get_config
config = json.load(open(config_file))
FileNotFoundError: [Errno 2] No such file or directory: '/root/.minirepo'
위의 텍스트를 친근한 톤으로 한국어로 번역하면 다음과 같습니다.
파일을 생성해 봅시다.
cat << EOF > /root/.minirepo
{
"processes": 10,
"package_types": [
"bdist_egg",
"bdist_wheel",
"sdist"
],
"extensions": [
"bz2",
"egg",
"gz",
"tgz",
"whl",
"zip"
],
"python_versions": [
"3.0",
"3.1",
"3.2",
"3.3",
"3.4.10",
"3.5.7",
"3.6.9",
"any",
"cp27",
"py2",
"py2.py3",
"py27",
"source"
],
"repository": "/data"
}
EOF
이제 실행해 봅시다.
minirepo
(venv) [root@localhost ~]# minirepo
/******** Minirepo ********/
extensions = ['bz2', 'egg', 'gz', 'tgz', 'whl', 'zip']
package_types = ['bdist_egg', 'bdist_wheel', 'sdist']
processes = 10
python_versions = ['3.0', '3.1', '3.2', '3.3', '3.4.10', '3.5.7', '3.6.9', 'any', 'cp27', 'py2', 'py2.py3', 'py27', 'source']
repository = /data
설정 파일 사용 중 /root/.minirepo
<!-- TIL 수평 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-4877378276818686"
data-ad-slot="1549334788"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
파이썬 코드를 이용하여 pypi 웹사이트를 파싱하고 패키지를 다운로드할 것입니다.
.......
[zzzutils 다운로드](/simple/zzzutils/)
[zzz-web 다운로드](/simple/zzz-web/)
[zzzymobbe 다운로드](/simple/zzzymobbe/)
[zzzz 다운로드](/simple/zzzz/)
[zzzZZZzzz 다운로드](/simple/zzzzzzzzz/)
</body>
</html>
/tmp/tmpvt3vfas8/worker.2565 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2566 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2567 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2568 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2569 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2570 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2571 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2572 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2573 파일에서 워커 시작...
/tmp/tmpvt3vfas8/worker.2574 파일에서 워커 시작...
2024-07-14 12:58:06,098:경고: 다운로드 완료: jira_test-0.0.1.tar.gz Ok pid:2567 0% [1/55510.0]
2024-07-14 12:58:06,127:경고: 다운로드 완료: nvitop-1.3.2.tar.gz Ok pid:2565 0% [1/55509.0]
이제 PyPi 패키지를 로컬 저장소에 복제했으며, 클라이언트에 설치된 pip를 통해 해당 패키지를 직접 설치할 수 있습니다. 이제 pypiserver가 등장합니다. pypiserver는 로컬 패키지 인덱스를 제공하여 네트워크를 통해 저장소에서 패키지를 찾을 수 있도록 하는 역할을 합니다.
우리는 도커를 사용하여 pypi 서버를 배포할 것입니다.
<!-- TIL 수평 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-4877378276818686"
data-ad-slot="1549334788"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
services:
pypi-server:
image: pypiserver/pypiserver:latest
ports:
- 8082:8080
volumes:
- type: volume
source: pypi-server
target: /data
command: -P . -a . /data/
restart: always
volumes:
pypi-server:
![How to Set Up Your Own Local PyPi Repository Server for Python Package Management](/TIL/assets/img/2024-07-14-HowtoSetUpYourOwnLocalPyPiRepositoryServerforPythonPackageManagement_1.png)
![Reference](https://miro.medium.com/v2/resize:fit:960/0*6KpBJVtYreNzCL3G.gif)
# 참고 문헌
<!-- TIL 수평 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-4877378276818686"
data-ad-slot="1549334788"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
[1] https://bandersnatch.readthedocs.io/en/latest/
[2] https://vuyisile.com/pypi-in-a-box-using-a-raspberry-pi-as-a-portable-pypi-server/