사내 conda 채널을 만들려고 conda index 를 돌리면 오류가 연달아 난다.
ModuleNotFoundError: No module named 'yaml'
ImportError: failed to find libmagic / No module named 'libarchive'
OSError: libzstd.so: cannot open shared object file: No such file or directory
OSError: libbz2.so.1.0: cannot open shared object file
conda list 에는 yaml 이 분명히 있는데도 못 찾는다고 한다.
패키지 파일이 들어 있는 디렉터리를 훑어 각 패키지의 메타데이터를 읽고, 그 디렉터리에 repodata.json 을 만든다. conda 클라이언트는 이 파일을 보고 의존성을 푼다. 색인이 없으면 파일이 아무리 많아도 채널로 인식되지 않는다.
python -m conda_index /srv/conda/mirror
ls /srv/conda/mirror/linux-64/repodata.json
ls /srv/conda/mirror/noarch/repodata.json
색인은 플랫폼 하위 디렉터리마다 만들어진다. 채널 루트를 인자로 주면 그 아래를 모두 훑는다. 채널 전체 요약인 channeldata.json 은 루트에 생기며, 클라이언트 동작에는 필수가 아니다.
메타데이터를 읽으려면 패키지 압축을 풀어야 한다. .tar.bz2 는 bzip2, .conda 는 zstd 로 압축돼 있어 두 압축 라이브러리가 모두 필요하다. 위 오류들이 전부 압축·아카이브 라이브러리를 가리키는 이유가 이것이다.
거의 항상 돌고 있는 파이썬이 그 환경의 파이썬이 아니다. conda list 는 활성 환경을 보여 주지만, conda index 를 실행한 인터프리터는 base 환경이거나 시스템 파이썬일 수 있다.
어느 인터프리터가 도는지부터 확인한다.
which conda python
python -c "import sys; print(sys.executable); print(sys.path)"
conda info --envs
yaml 은 패키지 이름이 pyyaml 이고 import 이름이 yaml 이다. 이름이 달라 설치 여부를 잘못 판단하기도 한다.
conda list | grep -i yaml
python -c "import yaml; print(yaml.__file__)"
색인 도구는 별도 패키지로 분리돼 있다. 전용 환경을 하나 만들어 거기서만 돌리는 것이 가장 깔끔하다. 필요한 의존성이 함께 끌려온다.
conda create -n indexer -c conda-forge python=3.11 conda-index
conda activate indexer
python -m conda_index /srv/conda/mirror
개별로 채울 때는 다음이 필요하다.
conda install -c conda-forge pyyaml python-libarchive-c zstd libarchive conda-package-handling
python-libarchive-c 는 파이썬 바인딩이고 libarchive 는 그 바인딩이 찾는 네이티브 라이브러리다. 둘 중 하나만 있으면 ImportError 가 난다. 반드시 같은 환경에 넣는다.
libzstd.so · libbz2.so.1.0 은 파일이 있는데도 못 찾는 경우가 있다. conda 환경의 lib 디렉터리가 검색 경로에 없어서다.
먼저 있기는 한지 본다.
ls $CONDA_PREFIX/lib/libzstd.so* $CONDA_PREFIX/lib/libbz2.so*
python -c "import ctypes; ctypes.CDLL('libzstd.so')"
없으면 채운다.
conda install -c conda-forge zstd bzip2
있는데 못 찾으면 경로를 알려 준다.
export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATH
libbz2.so.1.0 이라는 정확한 이름을 찾는 코드가 있는데 환경에는 libbz2.so.1.0.8 만 있는 경우가 있다. 이때는 심볼릭 링크를 환경 안에 만든다. 시스템 /usr/lib64 를 건드리지 않는다.
ln -s libbz2.so.1.0.8 $CONDA_PREFIX/lib/libbz2.so.1.0
깨진 패키지 파일이 하나 섞여 있으면 그 파일에서 멈춘다. 전송이 중간에 끊긴 .part 잔여물이 흔한 범인이다.
find /srv/conda/mirror -name '*.part' -o -size -1k
for f in /srv/conda/mirror/linux-64/*.tar.bz2; do bzip2 -t "$f" || echo "BAD $f"; done
디렉터리 구조가 잘못돼도 색인은 만들어지지만 쓸 수 없는 채널이 된다. 채널 루트 바로 아래에 플랫폼 디렉터리와 noarch/ 가 있어야 한다.
패키지를 추가할 때마다 색인을 다시 만들어야 한다. 파일만 복사하고 색인을 빠뜨리면 클라이언트에는 그 패키지가 없는 것으로 보인다.
색인 작업은 패키지 수에 비례해 오래 걸린다. 수만 개 규모에서는 수십 분이 걸리므로, 변경분만 다시 훑도록 캐시 디렉터리를 유지한다.