같은 pip install을 실행했는데 한 프로젝트만 갑자기 깨질 때가 있습니다. 패키지를 설치한 Python과 프로그램을 실행한 Python이 다르거나, 여러 프로젝트가 한 환경을 같이 쓰고 있는 경우부터 확인해 볼 만해요. 개발 환경은 “패키지가 설치된 상태”보다 누가 다시 만들어도 같은 조건으로 실행할 수 있는 상태에 가깝습니다.
이 연재는 Ubuntu 24.04 LTS와 업데이트된 Rocky Linux 9.x를 기준으로 합니다. 공통 예제는 Python 3.12를 사용합니다. 최신 Python이라는 이유만으로 버전을 고르기보다, 프로젝트의 핵심 라이브러리가 지원하는 버전부터 확인하는 방식입니다.
Python 개발 환경 · 01 선택과 venv · 02 uv · 03 conda · 04 웹 개발 · 05 데이터·AI · 06 OCR·서비스 분리
이 글의 목차
먼저 나눌 것은 도구가 아니라 관리 범위
| 층 | 예시 | 주로 관리하는 곳 |
|---|---|---|
| 운영체제와 드라이버 | glibc, GPU 드라이버, 서비스·파일 권한 | OS 패키지·드라이버 설치 절차 |
| Python 실행기 | Python 3.12.x | OS 패키지, uv의 관리형 Python, conda |
| 프로젝트 패키지 | FastAPI, pandas, Pillow | venv 안의 pip, uv 프로젝트, conda 환경 |
| 외부 실행 파일·모델 | Tesseract, Poppler, OCR 언어 데이터, AI 모델 | OS 또는 conda 패키지·별도 모델 저장소 |
| 실행 설정과 데이터 | DB 주소, 입력 파일, 결과물, 로그 | 환경 변수·설정 파일·스토리지 |
venv는 이미 있는 Python으로 격리된 패키지 공간을 만듭니다. uv는 그 위에 Python 선택·의존성 명세·잠금·동기화 흐름을 묶고, conda는 Python과 함께 여러 비 Python 라이브러리도 환경 단위로 배포할 수 있습니다. 셋이 완전히 같은 일을 하는 대체품은 아니에요.
venv·uv·conda의 장점과 부담
| 도구 | 장점·맞는 용도 | 부담·주의점 |
|---|---|---|
| venv + pip | 표준 기능으로 구조가 단순함. 작은 스크립트, 기존 requirements 기반 서비스, 기본 원리 학습 | Python 실행기는 따로 준비. 잠금·업데이트 정책을 별도로 정해야 하고 OS 실행 파일은 격리하지 않음 |
| uv | Python·패키지·잠금 파일·개발 의존성을 함께 관리하기 편함. 웹 API, 배치, 팀 개발·CI | 명세와 잠금 파일의 역할을 익혀야 함. OS 라이브러리·GPU 드라이버·모델 파일까지 잠그지는 않음 |
| conda | Python 버전과 과학 계산용 네이티브 패키지를 환경 단위로 관리. 연구·분석·여러 바이너리 의존성이 있는 작업 | 환경 용량과 채널 관리 부담. YAML만으로는 정확한 버전 잠금이 되지 않으며 pip와 혼용 순서를 관리해야 함 |
위 비교는 선택 기준이지 속도 순위나 모든 프로젝트에 대한 정답은 아닙니다. Python 패키지의 wheel만으로 필요한 의존성이 충족된다면 AI 프로젝트도 uv나 venv로 구성할 수 있어요. 반대로 GDAL 같은 네이티브 라이브러리 조합이 중요한 웹 서비스라면 conda를 검토할 이유가 있습니다.
프로젝트가 이 정도라면 어디서 시작할까
- 파일 몇 개로 끝나는 개인 자동화: venv + pip로 시작하고 실행 방법·의존성을 기록합니다.
- 웹 API·배치처럼 팀이 같은 환경을 반복해서 만들 작업: uv + pyproject.toml + uv.lock을 우선 검토합니다.
- 과학 계산·지리 정보·네이티브 패키지 조합이 중심인 분석: conda-forge 기반 conda 환경을 검토합니다.
- GPU 추론·학습·OCR: 프레임워크와 드라이버·OS 실행 파일 요구사항을 확인한 뒤 CPU API와 GPU 작업자의 환경을 분리할지 정합니다.
1. 현재 Python과 OS를 확인한다
cat /etc/os-release
uname -m
command -v python3
python3 --version
df -h /
Rocky Linux 9의 기본 python3가 3.9라고 해서 시스템 경로를 3.12로 덮어쓸 필요는 없습니다. 프로젝트에서는 python3.12를 명시하면 됩니다. 이 연재는 /usr/bin/python3 변경이나 시스템 전역 sudo pip install을 사용하지 않습니다.
2. OS별로 Python 3.12를 준비한다
Ubuntu 24.04의 Python 3.12와 venv
sudo apt update
sudo apt install -y python3.12 python3.12-venv python3-pip git curl ca-certificates
python3.12 --version
Ubuntu에서는 venv에 필요한 모듈을 별도 패키지로 준비합니다. No module named venv 또는 ensurepip 관련 오류가 나오면 실행한 Python 버전과 venv 패키지가 맞는지 먼저 확인하세요. Ubuntu 24.04의 python3.12-venv 패키지를 기준으로 적었습니다.
Rocky Linux 9에서 Python 3.12와 pip 준비
sudo dnf install -y python3.12 python3.12-pip git curl ca-certificates
python3.12 --version
Rocky Linux 9에서는 Python 3.12 패키지가 제공되는 정상 AppStream 저장소를 사용합니다. 구형 9.x 설치나 저장소 고정 상태라면 OS 업데이트 정책부터 확인하세요. RHEL 계열의 병렬 Python 패키지 구성은 RHEL 9 Python 설치 문서에서도 확인할 수 있습니다.
3. 프로젝트마다 .venv를 만든다
mkdir -p ~/projects/venv-demo
cd ~/projects/venv-demo
python3.12 -m venv .venv
source .venv/bin/activate
python --version
python -m pip --version
python -c 'import sys; print(sys.executable); print(sys.prefix != sys.base_prefix)'
실행기 경로가 현재 프로젝트의 .venv/bin/python이고 마지막 값이 True인지 확인합니다. 활성화는 PATH에서 이 환경의 실행 파일을 먼저 찾게 하는 편의 기능이에요. 활성화하지 않고 .venv/bin/python을 직접 호출해도 됩니다. Python venv 문서가 이 동작을 설명합니다.
4. 패키지를 설치하고 설치 상태를 기록한다
printf '%s\n' 'requests>=2.32,<3' > requirements.in
python -m pip install -r requirements.in
python -m pip check
python -m pip freeze > requirements-linux-py312.txt
python -c 'import requests; print(requests.__version__)'
deactivate
requirements.in은 직접 선택한 의존성의 의도를 적은 파일이고, 여기서 만든 freeze 파일은 현재 환경에 설치된 버전 목록입니다. pip freeze만으로 모든 OS·아키텍처·Python 버전의 재현성이 보장되지는 않습니다. 해시 검증이나 플랫폼별 잠금까지 필요하면 별도의 잠금 도구·정책을 적용해야 합니다.
# 같은 OS·아키텍처·Python 계열의 별도 확인용 환경
python3.12 -m venv .venv-rebuild
.venv-rebuild/bin/python -m pip install -r requirements-linux-py312.txt
.venv-rebuild/bin/python -m pip check
.venv-rebuild/bin/python -c 'import requests; print(requests.__version__)'
.venv 폴더를 다른 서버로 복사하는 대신 명세로 다시 만듭니다. 환경 안의 스크립트에는 절대 경로가 들어갈 수 있고 바이너리 의존성도 호스트 조건을 타기 때문입니다. 프로젝트 코드와 데이터는 .venv 바깥에 둡니다.
OS가 pip 설치를 막는 이유
externally-managed-environment는 OS가 관리하는 Python 설치 영역에 pip로 변경하려는 상황에서 나올 수 있습니다. venv 안에서 실행하고 있는지 확인하는 것이 먼저입니다. 이 연재는 오류를 없애기 위해 --break-system-packages를 붙이는 방식을 사용하지 않습니다. 외부에서 관리되는 Python 환경 명세는 OS 패키지와 Python 패키지 관리자의 충돌을 다룹니다.
개발 환경도 격리하지 못하는 것
venv는 보안 샌드박스가 아닙니다. 실행한 코드는 사용자의 파일과 네트워크 권한을 그대로 가집니다. DB 서버·Redis·GPU 드라이버·시스템 라이브러리도 별도의 계층입니다. 프로젝트가 커지면 환경 파일뿐 아니라 이런 외부 조건을 README나 배포 설정에 기록해야 해요.
이제 같은 작업을 명세와 잠금 파일 중심으로 관리하는 02 uv으로 이어갑니다.
연재 예제 파일 내려받기 · venv·conda 명세와 uv·웹·데이터·OCR 예제 소스, 확인한 uv 잠금 파일을 묶었습니다. 각 프로젝트 디렉터리에서 실행하며 OS 패키지는 본문의 절차로 별도 준비합니다.


![[Python 개발 환경 06] OCR 프로젝트 구성: 실행 파일·언어팩·API와 워커 분리](https://blog.maruops.com/wp-content/uploads/2026/10/maruops-python-env-6-768x618.webp)
![[Python 개발 환경 05] 데이터 처리·AI 환경 설계: pandas·Jupyter·CPU와 GPU](https://blog.maruops.com/wp-content/uploads/2026/10/maruops-python-env-5-768x960.webp)
답글 남기기