PyPI 설치 (1): pipx/uv 설치와 Constraint 파일의 원리
Apache Airflow Official Documentation (in-repo snapshot) — Apache Software Foundation installation/installing-from-pypi.rst, 'Installation via pipx/uv' ~ 'Fixing Constraints at release time' (L1-262)
이 모듈을 다 읽으면
- Airflow가 '라이브러리이면서 애플리케이션'이라는 이중성 때문에 constraint 파일이 왜 필요한지 설명할 수 있다
- constraint URL의 구성 요소(AIRFLOW_VERSION, PYTHON_VERSION)를 조합해 올바른 URL을 만들 수 있다
- constraint를 유지하면서 provider나 의존성을 개별적으로 업그레이드/다운그레이드하는 절차를 설명할 수 있다
PyPI를 통한 Airflow 설치는 pip(또는 uv)와 constraint 파일 조합만 공식 지원된다. constraint 파일은 Airflow가 '의존성을 열어두는 라이브러리'이면서 '고정하는 애플리케이션'이어야 하는 모순을 해결하기 위해 릴리스 시점마다 검증된 의존성 조합을 별도 브랜치/태그로 관리한 것이다. 이 모듈은 constraint의 필요성, URL 구성 규칙, 그리고 이를 유지하며 의존성을 유연하게 조정하는 방법을 다룬다.
pipx/uv로 빠르게 설치·실행하기
로컬 개발/테스트 목적이라면 `pipx run "apache-airflow==<version>" standalone`으로 PyPI에서 직접 실행할 수 있다. Astral `uv`를 사용한다면 `uv tool install "apache-airflow==<version>"`으로 설치하거나, 아예 설치 없이 `uvx apache-airflow standalone`으로 바로 실행하는 지름길도 있다.
실제 환경에 설치할 때 공식 지원되는 도구는 pip과 uv뿐이다. poetry나 pip-tools에서도 부분적 성공 사례가 있지만, 이들은 pip과 동일한 워크플로(특히 constraint vs requirements 관리 방식)를 공유하지 않아 공식 지원 대상이 아니다. 이 도구들을 쓰려면 constraint를 각 도구가 요구하는 형식/워크플로로 직접 변환해야 한다. uv는 `uv pip`로 pip 방식을 따르므로 유사하게 동작한다.
핵심 포인트
- pipx run "apache-airflow==<version>" standalone / uvx apache-airflow standalone으로 즉시 실행 가능하다
- 공식 지원 설치 도구는 pip과 uv뿐이며, poetry/pip-tools는 constraint 워크플로 차이로 비공식 지원이다
왜 Constraint가 필요한가
Airflow 설치가 까다로운 근본 이유는 Airflow가 '라이브러리'이면서 동시에 '애플리케이션'이기 때문이다. 라이브러리는 보통 의존성을 열어두고, 애플리케이션은 보통 의존성을 고정한다. Airflow는 둘 다 해야 하는 모순적 상황에 있다. 그래서 `pyproject.toml`에는 의존성을 최대한 열어두어 사용자가 필요한 버전을 자유롭게 설치할 수 있게 하되, 이 때문에 단순히 `pip install apache-airflow`만 실행하면 때때로 동작하지 않거나 사용 불가능한 조합이 설치될 수 있다.
이를 해결하기 위해 릴리스 시점에 실제로 테스트를 통과한 의존성 조합을 constraint 파일로 고정해 별도 관리한다. Airflow 3.1부터는 constraint 파일에 pytest, moto 등 테스트 전용 개발 의존성은 포함되지 않는다.
핵심 포인트
- Airflow는 라이브러리(의존성 개방)와 애플리케이션(의존성 고정)의 요구를 동시에 만족해야 하는 특수한 위치에 있다
- pyproject.toml은 의존성을 열어두므로 constraint 없이 pip install apache-airflow만 하면 설치가 실패하거나 깨질 수 있다
- Airflow 3.1부터 constraint 파일에는 pytest, moto 같은 개발 전용 의존성이 포함되지 않는다
재현 가능한 설치와 Constraint URL 구조
재현 가능한 설치를 위해 `constraints-main`, `constraints-2-0`, `constraints-2-1` 같은 고아(orphan) 브랜치에 constraint 파일 세트를 관리하고, 릴리스마다 태그(예: `constraints-<version>`)를 만든다. Python 지원 버전마다 별도의 constraint 파일이 존재한다.
URL 템플릿은 다음과 같다.
https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt
`AIRFLOW_VERSION`은 릴리스 버전(예: 3.3.1) 또는 개발 버전을 가리키는 `main`, `2-0` 같은 값을 쓸 수 있다. `PYTHON_VERSION`은 3.10, 3.11처럼 Python 버전을 지정한다. 예시 설치 명령:
pip install "apache-airflow[celery]==<version>" \
--constraint "https://raw.githubusercontent.com/apache/airflow/constraints-<version>/constraints-3.10.txt"
이 재현 가능한 설치가 보장하는 것은 '올바른 Python 버전'과 'provider가 필요로 하는 OS 레벨 의존성'이 갖춰져 있다는 전제 하에 최초 설치 단계가 항상 성공한다는 점이다. 일부 provider는 라이브러리 컴파일을 위한 `build-essential`이나 DB 클라이언트 라이브러리 같은 별도 OS 의존성을 요구할 수 있으며, 이는 설치 실패 시 사용자가 직접 파악해 설치해야 한다.
핵심 포인트
- constraint는 constraints-<version> 태그로 관리되며 Python 버전별로 별도 파일이 존재한다
- URL은 https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt 형태로 조합한다
- 재현 가능한 설치가 보장하는 것은 첫 설치 성공뿐이며, 일부 provider는 build-essential 등 별도 OS 의존성을 추가로 요구할 수 있다
Constraint를 유지하며 의존성 개별 업그레이드/다운그레이드하기
재현 가능한 설치 이후에도 provider나 기타 의존성을 최신 버전(보안 수정 포함)으로 올리거나, 호환성 때문에 이전 버전으로 내리는 것이 막히지 않는다. 다만 이런 개별 설치/업그레이드는 constraint 없이 별도 pip 명령으로 수행해야 한다. 이때 반드시 `apache-airflow` 패키지도 현재 버전으로 함께 pin해서 명령에 포함시켜야 한다 — 그렇지 않으면 pip의 의존성 해석 과정에서 Airflow 자체 버전이 의도치 않게 오르거나 내려갈 수 있다.
pip install "apache-airflow[celery]==<version>" --constraint "<url>"
pip install "apache-airflow==<version>" apache-airflow-providers-google==10.1.1
`pip check` 명령으로 설치된 패키지 집합이 서로 충돌 없이 일관적인지 확인할 수 있다. 종료 코드가 0이고 'No broken requirements found'가 출력되면 충돌이 없다는 뜻이다.
직접 관리하는 의존성이 늘어나면, `pip freeze > my-constraints.txt`로 자신만의 constraint 파일을 만들어 이후 재현 가능한 설치에 재사용할 수 있다. 이 커스텀 constraint 파일은 자신의 저장소나 서버에 호스팅해 원격에서도 사용할 수 있다.
핵심 포인트
- provider/의존성 개별 업그레이드는 constraint 없이 별도 pip 명령으로 하되, apache-airflow 버전을 함께 pin해야 의도치 않은 core 버전 변경을 막는다
- pip check로 종료코드 0과 'No broken requirements found'를 확인하면 의존성 충돌이 없다는 뜻이다
- pip freeze > my-constraints.txt로 자신만의 constraint 파일을 만들어 재사용/원격 호스팅할 수 있다
릴리스 시점 Constraint는 원칙적으로 고정된다
릴리스된 버전별 constraint 파일은 릴리스 시점에 '고정(fixed)'되며, Airflow 설치 자체를 막는 치명적 문제가 발견되는 예외적 상황이 아니면 이후에 변경되지 않는다. 즉 이후 Airflow 의존성의 새 버전이 나오더라도 — 설령 그것이 치명적 보안 수정을 포함하더라도 — 이미 릴리스된 버전의 constraint 파일 자체는 갱신되지 않는다. 의존성 자동 업그레이드는 새로운 Airflow 버전이 릴리스될 때만 이루어지도록 설계되어 있다.
따라서 최신 릴리스된 의존성을 계속 따라잡는 가장 쉬운 방법은 최신 Airflow 버전으로 업그레이드를 유지하는 것이다. 릴리스 사이 기간에는 사용자가 직접 의존성을 올리고 자신의 constraint를 관리해야 한다.
핵심 포인트
- 릴리스된 버전의 constraint 파일은 원칙적으로 변경되지 않으며, 설치 자체를 막는 치명적 문제일 때만 예외적으로 갱신된다
- 의존성의 보안 수정조차 이미 릴리스된 버전의 constraint를 자동으로 갱신시키지는 않는다
- 최신 의존성을 유지하는 가장 쉬운 방법은 Airflow 자체를 최신 버전으로 업그레이드하는 것이다