requirements.txt란?
requirements.txt는 Python project에서 필요한 package 목록을 적어두는 파일이다.
Ubuntu server, Ubuntu desktop, macOS에서 Python project를 배포하거나 실행할 때 가장 흔하게 사용하는 의존성 관리 방식 중 하나이다.
예를 들어 project에서 requests, numpy, pandas를 사용한다면 다음처럼 작성할 수 있다.
requests
numpy
pandas
다른 사람이 이 project를 실행하려면 같은 package를 설치해야 한다.
이때 package를 하나씩 직접 설치하는 대신 requirements.txt를 사용하면 한 번에 설치할 수 있다.
python3 -m pip install -r requirements.txt
즉 requirements.txt는 다음 문제를 해결한다.
이 project를 실행하려면 어떤 Python package가 필요한가?
어떤 version의 package를 설치해야 하는가?
다른 환경에서도 같은 의존성을 재현할 수 있는가?
기본 사용 흐름
Ubuntu 기준의 일반적인 흐름은 다음과 같다.
sudo apt update
sudo apt install python3 python3-pip python3-venv
python3 -m venv .venv
source .venv/bin/activate
python -m pip install requests numpy pandas
python -m pip freeze > requirements.txt
macOS에서는 먼저 Python 3가 설치되어 있는지 확인한다.
python3 --version
python3 -m pip --version
Python 3가 없다면 Homebrew로 설치할 수 있다.
brew install python
그다음 흐름은 Ubuntu와 거의 같다.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install requests numpy pandas
python -m pip freeze > requirements.txt
이후 다른 Ubuntu 또는 macOS 환경에서는 다음 명령어로 같은 package를 설치한다.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
보통 repository에는 source code와 함께 requirements.txt를 commit한다.
하지만 .venv directory는 commit하지 않는다.
commit: requirements.txt
ignore: .venv/
requirements.txt 작성법
가장 단순한 형태는 package 이름만 쓰는 것이다.
requests
numpy
pandas
이렇게 쓰면 설치 시점에 pip가 설치 가능한 최신 version을 선택한다. 간단한 실험 code에서는 충분할 수 있지만, 실제 project에서는 version을 명시하는 것이 더 안정적이다.
version 고정
특정 version을 정확히 고정하려면 ==를 사용한다.
requests==2.32.3
numpy==2.1.3
pandas==2.2.3
이 방식은 재현성이 좋다. 다른 컴퓨터나 서버에서도 같은 version을 설치하기 때문이다.
다만 너무 오래 고정해두면 보안 patch나 bug fix를 놓칠 수 있다. 그래서 주기적으로 package version을 점검하고 업데이트해야 한다.
version 범위 지정
항상 정확한 version만 써야 하는 것은 아니다. 필요에 따라 version 범위를 지정할 수 있다.
| 문법 | 의미 |
|---|---|
package==1.2.3 | 정확히 1.2.3 설치 |
package>=1.2.0 | 1.2.0 이상 설치 |
package<=2.0.0 | 2.0.0 이하 설치 |
package>=1.2.0,<2.0.0 | 1.2.0 이상, 2.0.0 미만 설치 |
package~=1.2.0 | 호환 가능한 release 범위 설치 |
예를 들어 다음은 requests를 2.31.0 이상, 3.0.0 미만으로 설치한다.
requests>=2.31.0,<3.0.0
library를 만드는 경우에는 너무 강하게 version을 고정하면 사용자가 다른 package와 함께 쓰기 어려울 수 있다. 반대로 application을 배포하는 경우에는 재현성을 위해 더 강하게 고정하는 경우가 많다.
pip freeze
현재 environment에 설치된 package 목록은 pip freeze로 확인할 수 있다.
python -m pip freeze
출력 예시는 다음과 같다.
certifi==2024.8.30
charset-normalizer==3.4.0
idna==3.10
numpy==2.1.3
pandas==2.2.3
python-dateutil==2.9.0.post0
pytz==2024.2
requests==2.32.3
six==1.16.0
tzdata==2024.2
urllib3==2.2.3
이 결과를 파일로 저장하면 requirements.txt가 된다.
python -m pip freeze > requirements.txt
주의할 점은 pip freeze가 직접 설치한 package뿐 아니라 의존성으로 함께 설치된 package까지 모두 출력한다는 것이다.
예를 들어 requests만 설치해도 certifi, charset-normalizer, idna, urllib3 같은 package가 함께 기록될 수 있다.
이 목록은 실행 환경을 정확히 재현하는 데는 좋지만, 사람이 읽기에는 다소 길어질 수 있다.
직접 관리하는 requirements.txt
작은 project에서는 직접 필요한 package만 적어두는 방식도 많이 사용한다.
requests>=2.31.0,<3.0.0
numpy>=2.0.0,<3.0.0
pandas>=2.2.0,<3.0.0
이 방식은 project가 실제로 직접 사용하는 package를 파악하기 쉽다. 하지만 하위 의존성 version까지 완전히 고정하지는 않으므로, 시간이 지나면 설치 결과가 달라질 수 있다.
정리하면 다음과 같다.
| 방식 | 장점 | 단점 |
|---|---|---|
pip freeze 결과 저장 | 환경 재현성이 좋음 | 파일이 길고 직접 의존성이 잘 보이지 않음 |
| 필요한 package만 직접 작성 | 읽기 쉽고 관리가 단순함 | 하위 의존성까지 완전히 고정되지는 않음 |
application 배포나 실험 재현이 중요하면 pip freeze 기반이 유리하다.
학습용 예제나 작은 script는 직접 관리해도 충분한 경우가 많다.
file 이름과 위치
관례적으로 project root에 requirements.txt를 둔다.
my_project/
main.py
requirements.txt
설치할 때는 project root에서 다음 명령어를 실행한다.
python -m pip install -r requirements.txt
파일 이름을 다르게 만들 수도 있다. 예를 들어 개발용 의존성을 분리할 수 있다.
requirements.txt
requirements-dev.txt
requirements.txt에는 실행에 필요한 package를 적고,
requirements-dev.txt에는 test, lint, formatting 도구를 적는다.
# requirements-dev.txt
pytest
ruff
black
설치할 때는 파일 이름을 지정한다.
python -m pip install -r requirements-dev.txt
comment 사용
requirements.txt에서는 #으로 comment를 작성할 수 있다.
# HTTP client
requests>=2.31.0,<3.0.0
# data analysis
numpy>=2.0.0,<3.0.0
pandas>=2.2.0,<3.0.0
package가 많아지면 용도별로 comment를 달아두는 것이 좋다. 나중에 어떤 package가 왜 필요한지 파악하기 쉬워진다.
가상환경과 함께 사용하기
requirements.txt는 가상환경과 함께 사용할 때 가장 자연스럽다.
Ubuntu에서 venv module이 없다면 먼저 설치한다.
sudo apt update
sudo apt install python3-venv
macOS에서는 보통 Python 3 설치에 venv가 포함되어 있다.
설치 여부는 다음처럼 확인한다.
python3 -m venv --help
그다음 project마다 가상환경을 만든다.
python3 -m venv .venv
Ubuntu와 macOS shell에서는 다음처럼 활성화한다.
source .venv/bin/activate
활성화되면 prompt 앞에 (.venv)가 붙는다.
(.venv) user@ubuntu:~/my_project$
macOS에서는 prompt가 다음처럼 보일 수 있다.
(.venv) user@macbook my_project %
그다음 package를 설치한다.
python -m pip install -r requirements.txt
가상환경을 사용하면 project별로 package version을 분리할 수 있다. 전역 Python 환경에 package를 계속 설치하면 project마다 필요한 version이 충돌할 수 있다.
requirements.txt 업데이트
새 package를 추가했다면 requirements.txt도 함께 업데이트해야 한다.
예를 들어 fastapi를 설치했다고 하자.
python -m pip install fastapi
현재 환경 전체를 고정하려면 다시 freeze한다.
python -m pip freeze > requirements.txt
직접 관리하는 방식이라면 파일에 한 줄을 추가한다.
fastapi>=0.115.0,<1.0.0
중요한 점은 code에서 새 package를 사용하기 시작했다면 의존성 파일도 같이 변경해야 한다는 것이다.
그렇지 않으면 다른 사람이 project를 실행할 때 ModuleNotFoundError가 발생할 수 있다.
설치 확인
의존성이 제대로 설치되었는지 확인하려면 새로운 가상환경에서 다시 설치해보는 것이 가장 확실하다.
python3 -m venv .venv-test
source .venv-test/bin/activate
python -m pip install -r requirements.txt
python main.py
test가 있는 project라면 test까지 실행한다.
pytest
이 과정은 배포 전 확인에도 유용하다. 내 컴퓨터에서는 이미 설치되어 있어서 동작하지만, 새 환경에서는 빠진 package 때문에 실패하는 경우가 많기 때문이다.
자주 발생하는 문제
ModuleNotFoundError
다음 error는 필요한 package가 설치되지 않았을 때 발생한다.
ModuleNotFoundError: No module named 'requests'
먼저 가상환경이 활성화되어 있는지 확인한다.
which python
which pip
python --version
python -m pip --version
가상환경이 활성화되어 있다면 보통 .venv 경로가 출력된다.
/home/user/my_project/.venv/bin/python
/home/user/my_project/.venv/bin/pip
그다음 requirements.txt를 다시 설치한다.
python -m pip install -r requirements.txt
pip와 python이 다른 환경을 가리키는 경우
Ubuntu와 macOS에서는 system Python, user Python, virtual environment Python이 섞일 수 있다.
환경이 꼬였을 때는 pip 대신 python -m pip 형태를 쓰면 더 명확하다.
python -m pip install -r requirements.txt
python -m pip freeze
이 방식은 현재 실행 중인 python에 연결된 pip를 사용한다.
externally-managed-environment error
Ubuntu 23.04 이후 환경, 최신 Debian 계열, 일부 macOS Python 환경에서는 전역 환경에 pip install을 실행할 때 다음과 비슷한 error가 날 수 있다.
error: externally-managed-environment
이 error는 system Python 환경을 pip로 직접 변경하지 말라는 의미이다. 해결 방법은 전역 설치 대신 가상환경을 사용하는 것이다.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
대부분의 project에서는 이 방식이 가장 안전하다.
Ubuntu apt와 macOS Homebrew
Ubuntu의 apt, macOS의 Homebrew, Python의 pip는 역할이 다르다.
| 도구 | 용도 |
|---|---|
apt | Ubuntu system package 설치 |
brew | macOS system package 또는 개발 도구 설치 |
pip | Python package 설치 |
예를 들어 Python 실행 환경과 venv module은 apt로 설치한다.
sudo apt install python3 python3-pip python3-venv
macOS에서 Python 자체가 필요하면 Homebrew로 설치할 수 있다.
brew install python
반면 project에서 사용하는 Python library는 가상환경 안에서 pip로 설치한다.
python -m pip install requests
platform별 package 문제
일부 package는 운영체제나 Python version에 따라 설치 가능 여부가 다를 수 있다. 이 경우 marker를 사용할 수 있다.
uvloop; sys_platform == "linux"
이 줄은 Linux 환경에서만 uvloop를 설치한다.
Docker에서 사용하기
Docker image를 Ubuntu 기준으로 만들 수도 있다.
이 경우에도 requirements.txt를 image 안으로 복사한 뒤 package를 설치한다.
예를 들어 project 구조가 다음과 같다고 하자.
my_project/
main.py
requirements.txt
Dockerfile
Ubuntu base image를 사용하는 Dockerfile 예시는 다음과 같다.
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
python3 \
python3-pip \
python3-venv \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN python3 -m venv /opt/venv \
&& /opt/venv/bin/python -m pip install --upgrade pip \
&& /opt/venv/bin/python -m pip install -r requirements.txt
ENV PATH="/opt/venv/bin:$PATH"
COPY . .
CMD ["python", "main.py"]
Ubuntu container에서도 system Python에 직접 pip install을 하기보다 가상환경을 만들어 설치하는 편이 좋다.
최신 Ubuntu/Debian 계열에서는 system Python이 externally managed 환경으로 취급될 수 있기 때문이다.
image를 build한다.
docker build -t my-python-app .
container를 실행한다.
docker run --rm my-python-app
일부 package는 compile에 필요한 system dependency가 필요할 수 있다.
예를 들어 C extension을 build해야 한다면 build-essential이나 관련 개발 package를 추가로 설치해야 할 수 있다.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
python3 \
python3-pip \
python3-venv \
build-essential \
&& rm -rf /var/lib/apt/lists/*
Docker에서는 requirements.txt를 먼저 복사하고 설치한 뒤 source code를 복사하는 순서가 유리하다.
의존성이 바뀌지 않으면 Docker layer cache를 재사용할 수 있기 때문이다.
requirements.txt와 pyproject.toml
최근 Python project에서는 pyproject.toml을 사용하는 경우도 많다.
pyproject.toml은 package metadata, build 설정, dependency 설정을 함께 담을 수 있다.
하지만 requirements.txt는 여전히 단순하고 널리 쓰인다.
특히 script, 작은 application, Docker image, server 배포 환경에서는 다음 형태가 자주 사용된다.
COPY requirements.txt .
RUN python -m pip install -r requirements.txt
즉 requirements.txt는 복잡한 project 관리 도구를 쓰지 않아도 의존성을 전달할 수 있는 가장 기본적인 파일이다.
정리
requirements.txt는 Python project의 의존성을 기록하는 파일이다.
핵심 명령어는 다음 두 가지이다.
python -m pip freeze > requirements.txt
python -m pip install -r requirements.txt
실제 project에서는 다음 원칙을 지키면 좋다.
project root에 requirements.txt를 둔다.
.venv는 commit하지 않는다.
Ubuntu에서는 python3-venv를 설치한 뒤 가상환경을 만든다.
macOS에서는 python3가 있는지 확인하고 없으면 Homebrew 등으로 설치한다.
Docker는 Ubuntu base image에서도 venv를 만들어 설치한다.
새 package를 추가하면 requirements.txt도 업데이트한다.
재현성이 중요하면 version을 고정한다.
환경이 헷갈리면 python -m pip를 사용한다.
작은 project에서는 필요한 package만 직접 적어도 충분하다.
배포나 실험 재현이 중요하다면 pip freeze로 version을 고정하고, 새 환경에서 설치가 되는지 확인하는 것이 좋다.