pip install이 error: externally-managed-environment로 막힌 이유
문제 발생
새로 받은 Ubuntu 24.04 서버에서 늘 하던 대로 pip install requests를 쳤는데, 설치는커녕 빨간 글씨가 한가득 나왔습니다.
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
...
note: If you believe this is a mistake, please contact your Python installation or OS
distribution provider. You can override this, at the risk of breaking your Python
installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.예전 서버에서는 잘 되던 명령이었습니다. --user를 붙여 봐도 똑같이 막혔고, 결국 메시지 끝에 적힌 --break-system-packages를 붙여서 넘겼습니다. 그렇게 몇 번 쓰다 보니 어느 날 시스템에 깔린 Python 도구 하나가 갑자기 ImportError를 내며 실행되지 않았습니다.
원인 분석
배포판이 "이 Python은 내가 관리한다"고 표시해 둔 겁니다. 이 동작은 PEP 668이 정한 규칙입니다. PEP 668에 따르면 pip 같은 Python 전용 설치 도구는 패키지를 설치하기 전에 두 가지를 확인해야 합니다. 가상환경 밖에서 실행 중인지(sys.prefix == sys.base_prefix), 그리고 sysconfig의 stdlib 경로에 EXTERNALLY-MANAGED 파일이 있는지입니다. 둘 다 참이면 에러를 내고 멈춰야 한다고요. 실제로 이 서버의 /usr/lib/python3.12/EXTERNALLY-MANAGED를 열어 보니, 위 에러에 나온 안내 문구가 그대로 들어 있었습니다. 에러 메시지는 pip가 지어낸 게 아니라 배포판이 이 파일에 적어 둔 안내였던 겁니다.
막는 이유는 시스템 도구가 같은 Python을 쓰기 때문입니다. PEP 668의 동기 부분이 이걸 구체적으로 설명합니다. 배포판의 /usr/bin/python3는 사용자가 쓰는 명령이면서 동시에 배포판에 포함된 Python 소프트웨어가 의존하는 인터프리터입니다. 가상환경 밖에서 pip로 설치한 패키지는 배포판의 Python 소프트웨어에도 보이고, 그게 배포판이 깔아 둔 패키지보다 새로우면서 호환되지 않는 버전이면 배포판 소프트웨어를 망가뜨릴 수 있다고요. 문서는 pip 명령 하나로 Fedora의 dnf를 망가뜨려 복구하기 어려워질 수 있다는 예까지 듭니다. 제가 겪은 ImportError가 바로 이 경우였습니다.
--user까지 막히는 이유도 여기 있습니다. PEP 668은 이 문제가 sudo pip install 같은 시스템 전체 설치뿐 아니라 pip install --user 같은 홈 디렉터리 설치에도 똑같이 해당한다고 적습니다. 두 위치 모두 /usr/bin/python3의 sys.path에 잡히기 때문입니다. 시스템 전체 설치는 더 나쁩니다. 문서에 따르면 sudo pip uninstall로 되돌리려다 배포판 패키지 관리자가 깔아 둔 패키지를 지울 수도 있고, 단순히 패키지를 업그레이드할 때도 pip가 OS가 깔아 둔 옛 버전을 지우려 할 수 있습니다.
같은 컴퓨터라도 Python에 따라 결과가 다릅니다. 이 서버에는 배포판 Python 3.12 말고 /usr/local에 따로 설치된 3.13도 있었는데, 그쪽 stdlib 경로에는 EXTERNALLY-MANAGED 파일이 없어서 같은 pip install이 그대로 통과했습니다. "어떤 서버에서는 되고 어떤 서버에서는 안 된다"는 혼란은 대개 지금 어떤 python과 pip가 불리고 있는지가 달라서 생깁니다.
해결 방안
- 프로젝트에서 쓸 라이브러리는 가상환경에 설치합니다. 에러 메시지가 첫 번째로 권하는 방법입니다. PEP 668이 검사하는 조건 중 하나가 "가상환경 밖인가"라서, 가상환경 안에서는
EXTERNALLY-MANAGED파일이 있어도 막지 않습니다. 직접 확인해 보니 venv 안의 Python도stdlib경로는 여전히/usr/lib/python3.12라서 파일은 그대로 보였지만,sys.prefix != sys.base_prefix가 참이라 pip가 설치를 진행했습니다.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install requests가상환경 자체에 대한 이야기는 예전 글 "가상환경을 안 쓰고 라이브러리를 설치했다가 다른 프로젝트가 깨진 이유"에 정리해 두었습니다. 배포판 안내문에 적힌 대로, venv 만들기가 실패하면 먼저 python3-full 패키지가 설치돼 있는지 확인합니다.
-
가상환경을 만들었는데도 같은 에러가 나면, 불린
pip를 확인합니다. 활성화를 잊었거나 다른 터미널에서 실행하면pip는 여전히 시스템 것입니다.command -v pip와python -m pip --version으로 경로를 보면 바로 알 수 있습니다. 활성화 없이 쓰고 싶다면 Python 공식 문서 설명대로 가상환경 안의 인터프리터를 전체 경로로 부르면 됩니다. 활성화는 그bin디렉터리를PATH앞에 붙이는 것뿐이라,.venv/bin/pip install ...이나.venv/bin/python app.py도 똑같이 동작합니다. Dockerfile에서도 같은 원리로 venv를 만든 뒤ENV PATH="/opt/venv/bin:$PATH"를 두면, 이후의pip와python이 모두 venv 것으로 잡힙니다. 직접PATH만 바꿔서 실행해 보니pip가 venv 안의 것으로 바뀌었습니다. -
명령줄 도구는
pipx로 설치합니다.httpie,black,poetry처럼 라이브러리가 아니라 터미널에서 쓰는 프로그램을 설치하려던 거라면 가상환경을 직접 관리할 필요가 없습니다. 에러 메시지의 세 번째 안내가 이겁니다. pipx 문서에 따르면 pipx는 Python 애플리케이션마다 별도의 가상환경을 만들어 설치하기 때문에, 의존성이 서로 충돌하지 않고 지우면 흔적이 남지 않습니다.pipx install black처럼 쓰면black명령은 어디서든 쓸 수 있고 시스템 Python은 건드리지 않습니다. -
시스템 전체에 필요하면 배포판 패키지로 설치합니다. 서버에 깔린 다른 시스템 도구가 그 라이브러리를 써야 하는 경우라면, 안내문의 첫 문장대로
apt install python3-requests처럼 배포판 패키지를 찾습니다. 배포판 패키지 관리자가 버전을 맞춰 주니 시스템 Python과 충돌하지 않습니다. 대신 배포판이 고른 버전이라 최신이 아닐 수 있습니다. 최신 버전이 꼭 필요하다면 1번으로 돌아가는 게 맞습니다. -
--break-system-packages는 정말 버려도 되는 환경에서만 씁니다. 메시지 자체가 이 옵션은 Python 설치나 OS를 망가뜨릴 위험을 감수하는 것이라고 적어 둡니다. 저처럼 몇 번 쓰다 시스템 도구가 깨지면, 어떤 패키지가 배포판 것이고 어떤 게 pip로 덮어쓴 것인지 가려내는 데 시간이 더 듭니다. macOS도 예외가 아닙니다. Homebrew 문서에 따르면 Homebrew는 현재 Python을 PEP 668에 따른 externally managed 상태로 표시하고, 프로젝트 의존성은 가상환경에, 명령줄 앱은pipx로 설치하라고 안내합니다. 운영체제가 어디든 "시스템 Python에는 직접 설치하지 않는다"가 이제 기본 규칙이라고 보면 됩니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.