Python 실전 가이드
Python의 핵심 개념과 실무 활용
학습 항목
이미지 로딩 중...
Poetry Python 의존성 관리 완벽 가이드
Python 프로젝트의 의존성 관리를 혁신적으로 개선하는 Poetry를 소개합니다. pyproject.toml 하나로 프로젝트 설정부터 배포까지, 초급 개발자도 쉽게 따라할 수 있는 실전 가이드입니다.
목차
- Poetry 설치와 프로젝트 초기화 - 첫 시작 가이드
- pyproject.toml 이해하기 - 프로젝트 설정의 중심
- 의존성 추가와 업데이트 - 패키지 관리의 핵심
- poetry.lock 파일의 중요성 - 재현 가능한 환경
- 가상환경 관리 - 자동화된 격리
- 개발 의존성 그룹 관리 - 의존성의 세밀한 분리
- 스크립트와 명령어 실행 - 편리한 워크플로우
- 패키지 빌드와 배포 - PyPI에 공개하기
- Poetry와 Docker 통합 - 컨테이너 환경 최적화
- CI/CD 환경에서 Poetry 활용 - 자동화 파이프라인
1. Poetry 설치와 프로젝트 초기화 - 첫 시작 가이드
시작하며
여러분이 Python 프로젝트를 시작할 때마다 requirements.txt를 수동으로 관리하고, setup.py를 작성하고, 가상환경을 별도로 설정하느라 복잡했던 경험 있으신가요? 패키지를 추가할 때마다 버전을 일일이 적고, 개발 의존성과 운영 의존성을 분리하기 어려웠던 기억 말이죠.
이런 문제는 Python 프로젝트가 커질수록 더 심각해집니다. 팀원들과 협업할 때 각자 다른 버전의 패키지를 사용하거나, 배포 시 불필요한 개발용 패키지가 포함되는 등의 문제가 발생하죠.
바로 이럴 때 필요한 것이 Poetry입니다. Poetry는 프로젝트 설정, 의존성 관리, 가상환경 생성, 패키지 빌드까지 모든 것을 하나의 도구로 통합하여 여러분의 개발 경험을 혁신적으로 개선해줍니다.
개요
간단히 말해서, Poetry는 Python의 모던 의존성 관리 및 패키징 도구입니다. requirements.txt와 setup.py를 따로 관리할 필요 없이, pyproject.toml 하나로 모든 프로젝트 설정을 관리할 수 있습니다.
이는 Node.js의 package.json이나 Rust의 Cargo.toml처럼 표준화된 방식입니다. 특히 의존성 해결(dependency resolution) 알고리즘이 뛰어나서, 패키지 간 버전 충돌을 자동으로 감지하고 해결해줍니다.
기존에는 pip로 패키지를 설치하고, virtualenv로 가상환경을 만들고, setup.py를 작성하고, twine으로 배포했다면, 이제는 Poetry 하나로 모든 작업을 처리할 수 있습니다. Poetry의 핵심 특징은 자동 의존성 해결, 격리된 가상환경 관리, 결정론적 빌드(deterministic builds)입니다.
이러한 특징들이 프로젝트의 재현성과 안정성을 크게 향상시켜, 팀 협업과 CI/CD 환경에서 특히 빛을 발합니다.
코드 예제
# Poetry 설치 (Linux/macOS/WSL)
curl -sSL https://install.python-poetry.org | python3 -
# Poetry 설치 (Windows PowerShell)
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
# 설치 확인
poetry --version
# 새 프로젝트 생성
poetry new my-project
# 기존 프로젝트에 Poetry 적용
cd existing-project
poetry init
# 프로젝트 구조가 자동으로 생성됨
# my-project/
# ├── pyproject.toml # 프로젝트 설정 파일
# ├── README.md
# ├── my_project/ # 소스 코드
# └── tests/ # 테스트 코드
설명
이것이 하는 일: Poetry 설치 스크립트는 Poetry를 시스템에 독립적으로 설치하고, 프로젝트 초기화 명령은 표준화된 구조의 Python 프로젝트를 생성합니다. 첫 번째로, curl 명령어를 통해 공식 설치 스크립트를 다운로드하고 실행합니다.
이 스크립트는 Poetry를 시스템의 Python 환경과 분리하여 설치하므로, 기존 Python 프로젝트나 패키지와 충돌하지 않습니다. Windows에서는 PowerShell의 Invoke-WebRequest를 사용하여 동일한 작업을 수행합니다.
그 다음으로, poetry new 명령어를 실행하면 Poetry가 표준화된 프로젝트 구조를 자동으로 생성합니다. 이 구조에는 소스 코드 디렉토리, 테스트 디렉토리, 그리고 가장 중요한 pyproject.toml 파일이 포함됩니다.
pyproject.toml은 PEP 518에서 정의한 Python 프로젝트의 표준 설정 파일로, 프로젝트 메타데이터와 의존성 정보를 모두 담고 있습니다. 기존 프로젝트에 Poetry를 적용할 때는 poetry init 명령어를 사용합니다.
이 명령어는 대화형 방식으로 프로젝트 정보를 입력받아 pyproject.toml 파일을 생성해주므로, 기존 requirements.txt에서 Poetry로의 마이그레이션이 매우 쉽습니다. 여러분이 이 명령어들을 사용하면 몇 분 안에 Poetry 기반의 프로젝트를 시작할 수 있고, 표준화된 구조 덕분에 다른 개발자들도 프로젝트를 쉽게 이해하고 기여할 수 있습니다.
또한 pyproject.toml 하나로 프로젝트의 모든 설정을 관리하므로, 버전 관리도 훨씬 간편해집니다.
실전 팁
💡 Poetry를 설치한 후에는 poetry config virtualenvs.in-project true 명령어를 실행하여 가상환경을 프로젝트 디렉토리 내의 .venv 폴더에 생성하도록 설정하세요. 이렇게 하면 VSCode나 PyCharm 같은 IDE가 가상환경을 자동으로 인식하여 더 편리합니다.
💡 poetry new 대신 poetry new --src my-project 명령어를 사용하면 src 레이아웃 구조로 프로젝트가 생성됩니다. 이는 대규모 프로젝트에서 권장되는 구조로, 소스 코드와 테스트 코드의 분리가 더 명확해집니다.
💡 기존 requirements.txt에서 마이그레이션할 때는 poetry add $(cat requirements.txt) 명령어로 한 번에 모든 패키지를 추가할 수 있습니다. 단, 버전 지정 방식이 다를 수 있으니 한 번 확인해보세요.
💡 Poetry 설치 경로를 확인하려면 poetry env info 명령어를 사용하세요. 문제가 생겼을 때 Poetry를 완전히 제거하고 재설치해야 할 경우 이 정보가 유용합니다.
2. pyproject.toml 이해하기 - 프로젝트 설정의 중심
시작하며
여러분이 Python 프로젝트를 관리하면서 setup.py, requirements.txt, requirements-dev.txt, MANIFEST.in 등 여러 설정 파일을 동시에 관리해야 했던 경험이 있나요? 파일마다 형식이 다르고, 정보가 중복되어 있어서 하나를 수정하면 다른 파일도 함께 수정해야 하는 번거로움 말이죠.
이런 문제는 프로젝트의 복잡도를 불필요하게 증가시킵니다. 특히 새로운 팀원이 프로젝트에 합류했을 때, 어떤 파일을 어떻게 수정해야 하는지 설명하는 것만 해도 시간이 오래 걸립니다.
바로 이럴 때 필요한 것이 pyproject.toml입니다. 이 파일 하나로 프로젝트의 모든 설정을 관리할 수 있으며, TOML 형식이라 읽기도 쉽고 수정하기도 편리합니다.
개요
간단히 말해서, pyproject.toml은 Python 프로젝트의 모든 설정을 담는 표준 설정 파일입니다. 이 파일은 PEP 518에서 정의된 Python 공식 표준으로, 프로젝트 메타데이터, 의존성, 빌드 설정, 도구 설정까지 모든 것을 포함합니다.
Poetry뿐만 아니라 Black, pytest, mypy 같은 다른 도구들의 설정도 이 파일에 함께 작성할 수 있어서, 프로젝트 설정이 한곳에 집중됩니다. 기존에는 setup.py로 패키지 정보를 관리하고, requirements.txt로 의존성을 관리하고, tox.ini나 setup.cfg로 도구 설정을 관리했다면, 이제는 pyproject.toml 하나로 모든 것을 관리할 수 있습니다.
pyproject.toml의 핵심 특징은 표준화된 형식, 도구 간 호환성, 그리고 사람이 읽기 쉬운 TOML 문법입니다. 이러한 특징들이 프로젝트의 유지보수성을 크게 향상시키고, 다른 개발자들이 프로젝트를 빠르게 이해할 수 있게 해줍니다.
코드 예제
[tool.poetry]
name = "my-awesome-project"
version = "0.1.0"
description = "A wonderful Python project"
authors = ["Your Name <you@example.com>"]
license = "MIT"
readme = "README.md"
# 프로젝트의 운영 의존성 (실제 배포 시 필요)
[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.31.0"
fastapi = "^0.104.0"
pydantic = "^2.0.0"
# 개발 의존성 (개발/테스트 시에만 필요)
[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
black = "^23.0.0"
mypy = "^1.5.0"
ruff = "^0.1.0"
# 빌드 시스템 설정
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
설명
이것이 하는 일: pyproject.toml 파일은 프로젝트의 모든 설정 정보를 구조화된 TOML 형식으로 저장하고, Poetry와 다른 도구들이 이 정보를 읽어 프로젝트를 관리합니다. 첫 번째로, [tool.poetry] 섹션은 프로젝트의 기본 메타데이터를 정의합니다.
name, version, description 같은 필수 정보부터 authors, license, readme 같은 선택적 정보까지 포함합니다. 이 정보들은 나중에 PyPI에 패키지를 배포할 때 그대로 사용되므로, 처음부터 정확하게 작성하는 것이 중요합니다.
그 다음으로, [tool.poetry.dependencies] 섹션이 프로젝트의 운영 의존성을 관리합니다. python = "^3.9"는 이 프로젝트가 Python 3.9 이상에서 동작한다는 의미이고, 각 패키지의 버전 앞에 있는 ^ 기호는 호환 가능한 버전을 의미합니다.
예를 들어 ^2.31.0은 2.31.0 이상이지만 3.0.0 미만의 버전을 허용한다는 뜻입니다. 개발 의존성은 [tool.poetry.group.dev.dependencies] 섹션에 별도로 관리됩니다.
pytest, black, mypy 같은 도구들은 개발과 테스트에는 필요하지만 실제 프로덕션 환경에서는 필요 없습니다. 이렇게 분리하면 배포 시 불필요한 패키지를 제외할 수 있어 배포 크기가 작아지고 보안도 향상됩니다.
마지막으로, [build-system] 섹션은 프로젝트를 빌드할 때 사용할 백엔드를 지정합니다. poetry-core를 사용하면 Poetry가 프로젝트를 wheel이나 sdist 형식으로 빌드할 수 있습니다.
여러분이 이 파일을 제대로 작성하면 팀원들이 poetry install 명령어 하나로 동일한 개발 환경을 구축할 수 있고, CI/CD 파이프라인에서도 일관된 빌드 결과를 얻을 수 있습니다. 또한 버전 제약을 명확히 지정하여 예상치 못한 패키지 업데이트로 인한 버그를 방지할 수 있습니다.
실전 팁
💡 버전 지정 시 ^(캐럿)과 ~(틸드)의 차이를 이해하세요. ^1.2.3은 1.2.3 이상 2.0.0 미만을, ~1.2.3은 1.2.3 이상 1.3.0 미만을 의미합니다. 안정성이 중요한 프로덕션 환경에서는 ~를 사용하는 것이 더 안전합니다.
💡 선택적 의존성(optional dependencies)이 필요하면 [tool.poetry.extras] 섹션을 활용하세요. 예를 들어 데이터베이스 기능은 선택적으로 만들고 싶다면 extras = { database = ["sqlalchemy", "psycopg2"] } 형태로 정의할 수 있습니다.
💡 프로젝트에 실행 가능한 스크립트가 있다면 [tool.poetry.scripts] 섹션에 정의하세요. mycli = "my_package.cli:main" 형태로 작성하면 패키지 설치 후 mycli 명령어로 실행할 수 있습니다.
💡 private PyPI 서버를 사용한다면 poetry config repositories.private https://private-pypi.com 명령어로 저장소를 추가하고, pyproject.toml의 source 섹션에서 참조할 수 있습니다.
3. 의존성 추가와 업데이트 - 패키지 관리의 핵심
시작하며
여러분이 새로운 라이브러리를 프로젝트에 추가할 때마다 pip install을 실행하고, requirements.txt를 수동으로 열어서 버전을 적고, 가끔은 어떤 버전을 설치했는지 기억이 안 나서 pip freeze를 실행했던 경험이 있나요? 그리고 팀원이 다른 버전을 설치해서 코드가 작동하지 않는 상황도 겪어보셨을 것입니다.
이런 문제는 수동 관리의 한계입니다. 특히 의존성이 많은 대규모 프로젝트에서는 버전 충돌을 해결하는 것만으로도 몇 시간이 소요되곤 합니다.
또한 보안 취약점이 발견된 패키지를 찾아서 업데이트하는 작업도 매우 번거롭습니다. 바로 이럴 때 필요한 것이 Poetry의 의존성 관리 기능입니다.
명령어 하나로 패키지를 추가하고, 버전을 자동으로 해결하며, poetry.lock 파일로 모든 팀원이 동일한 환경을 공유할 수 있습니다.
개요
간단히 말해서, Poetry의 의존성 관리는 패키지 설치, 버전 해결, 잠금 파일 생성을 자동화하는 시스템입니다. poetry add 명령어는 패키지를 설치하는 동시에 pyproject.toml에 의존성을 기록하고, poetry.lock 파일을 업데이트합니다.
이 과정에서 Poetry의 의존성 해결 알고리즘이 모든 패키지 간의 버전 호환성을 검사하여 충돌을 방지합니다. 또한 poetry update 명령어로 패키지를 최신 버전으로 안전하게 업데이트할 수 있습니다.
기존에는 pip install로 패키지를 설치하고, 수동으로 requirements.txt를 편집하고, pip freeze로 정확한 버전을 확인했다면, 이제는 poetry add 명령어 하나로 모든 작업이 자동으로 처리됩니다. Poetry 의존성 관리의 핵심 특징은 자동 버전 해결, 결정론적 설치(poetry.lock), 그리고 개발/운영 의존성 분리입니다.
이러한 특징들이 팀 협업 시 "내 컴퓨터에서는 되는데요" 문제를 완전히 해결하고, 재현 가능한 빌드 환경을 보장합니다.
코드 예제
# 패키지 추가 (pyproject.toml과 poetry.lock 자동 업데이트)
poetry add requests
# 특정 버전 지정하여 추가
poetry add "django>=4.0,<5.0"
# 개발 의존성으로 추가
poetry add --group dev pytest black
# 여러 패키지 동시 추가
poetry add fastapi uvicorn pydantic
# 패키지 제거
poetry remove requests
# 모든 의존성 업데이트 (버전 제약 내에서)
poetry update
# 특정 패키지만 업데이트
poetry update requests
# 의존성 트리 확인 (어떤 패키지가 무엇을 의존하는지)
poetry show --tree
설명
이것이 하는 일: poetry add 명령어는 패키지를 설치하고, 의존성을 pyproject.toml에 기록하며, 모든 하위 의존성의 정확한 버전을 poetry.lock에 잠급니다. 첫 번째로, poetry add requests 명령어를 실행하면 Poetry는 PyPI에서 requests 패키지의 최신 버전을 확인하고, 현재 프로젝트의 다른 패키지들과 호환되는지 검사합니다.
이 과정에서 requests가 의존하는 하위 패키지들(예: urllib3, certifi, charset-normalizer 등)도 함께 분석하여 버전 충돌이 없는 조합을 찾아냅니다. 이것이 바로 의존성 해결(dependency resolution) 과정입니다.
그 다음으로, 선택된 버전이 pyproject.toml의 [tool.poetry.dependencies] 섹션에 requests = "^2.31.0" 형태로 추가됩니다. 여기서 ^2.31.0은 2.31.0 이상이지만 3.0.0 미만의 버전을 허용한다는 의미로, 향후 마이너 버전 업데이트는 허용하지만 메이저 버전 변경은 막아서 호환성을 유지합니다.
동시에 poetry.lock 파일이 생성되거나 업데이트됩니다. 이 파일에는 requests와 모든 하위 의존성의 정확한 버전(예: requests==2.31.0, urllib3==2.0.7)이 기록됩니다.
이 잠금 파일 덕분에 다른 팀원이나 CI/CD 환경에서 poetry install을 실행하면 정확히 동일한 버전의 패키지들이 설치됩니다. 개발 의존성을 추가할 때는 --group dev 옵션을 사용합니다.
이렇게 추가된 패키지들은 [tool.poetry.group.dev.dependencies] 섹션에 기록되며, 프로덕션 배포 시 poetry install --without dev 명령어로 제외할 수 있습니다. 여러분이 이 명령어들을 사용하면 의존성 관리가 자동화되어 실수를 크게 줄일 수 있고, poetry.lock 파일을 git에 커밋하여 팀 전체가 동일한 환경에서 작업할 수 있습니다.
또한 poetry show --tree 명령어로 복잡한 의존성 구조를 시각적으로 파악하여 불필요한 패키지를 제거하거나 버전 충돌을 디버깅할 수 있습니다.
실전 팁
💡 poetry add 시 자동으로 선택된 버전이 마음에 들지 않으면 poetry add "requests==2.28.0" 형태로 정확한 버전을 지정할 수 있습니다. 단, 이렇게 하면 버전이 완전히 고정되어 보안 업데이트를 받지 못하므로 특별한 이유가 있을 때만 사용하세요.
💡 poetry.lock 파일은 반드시 git에 커밋하세요. 이 파일이 있어야 모든 개발자와 CI/CD 환경에서 동일한 버전의 패키지를 사용할 수 있습니다. .gitignore에 추가하면 안 됩니다!
💡 poetry update --dry-run 명령어로 실제 업데이트하기 전에 어떤 패키지가 어떤 버전으로 업데이트될지 미리 확인할 수 있습니다. 중요한 프로젝트에서는 항상 dry-run을 먼저 실행하는 습관을 들이세요.
💡 의존성 충돌이 발생하면 poetry show <패키지명> 명령어로 해당 패키지의 현재 버전과 의존성을 확인하세요. 그리고 --tree 옵션으로 어떤 패키지가 충돌을 일으키는지 추적할 수 있습니다.
💡 GitHub에서 직접 설치해야 하는 패키지가 있다면 poetry add git+https://github.com/user/repo.git 형태로 추가할 수 있습니다. 특정 브랜치나 태그를 지정하려면 @branch-name이나 @v1.0.0을 URL 뒤에 붙이세요.
4. poetry.lock 파일의 중요성 - 재현 가능한 환경
시작하며
여러분이 프로젝트를 다른 서버에 배포하거나 팀원의 컴퓨터에서 실행할 때, "어제까지 잘 되던 코드가 갑자기 안 돼요"라는 말을 들어본 적 있나요? 알고 보니 어떤 패키지가 자동으로 업데이트되면서 API가 변경되었거나 버그가 생긴 경우죠.
이런 문제는 의존성 버전이 고정되지 않았을 때 발생합니다. requirements.txt에 requests>=2.0처럼 범위로 지정하면 설치 시점에 따라 다른 버전이 설치되어 예측 불가능한 동작이 발생할 수 있습니다.
특히 CI/CD 파이프라인에서는 이런 불확실성이 치명적입니다. 바로 이럴 때 필요한 것이 poetry.lock 파일입니다.
이 파일은 모든 패키지의 정확한 버전을 기록하여, 언제 어디서 설치하든 정확히 동일한 환경을 보장합니다.
개요
간단히 말해서, poetry.lock은 모든 의존성의 정확한 버전과 해시를 기록한 잠금 파일입니다. 이 파일은 poetry add나 poetry update 명령어를 실행할 때 자동으로 생성되고 업데이트됩니다.
pyproject.toml이 "이 패키지의 2.x 버전을 사용하겠다"는 범위를 지정한다면, poetry.lock은 "정확히 2.31.0 버전을 사용한다"고 명시합니다. 또한 각 패키지의 SHA256 해시값도 기록하여 패키지가 변조되지 않았는지 검증할 수 있습니다.
기존에는 pip freeze > requirements.txt로 현재 설치된 버전을 고정했지만, 이는 하위 의존성의 변경을 추적하지 못하고, 패키지 해시 검증도 없어서 보안에 취약했습니다. poetry.lock은 이러한 모든 문제를 해결합니다.
poetry.lock의 핵심 특징은 결정론적 설치, 무결성 검증, 그리고 자동 동기화입니다. 이러한 특징들이 팀 협업 시 환경 불일치 문제를 완전히 제거하고, 프로덕션 배포의 안정성을 크게 향상시킵니다.
코드 예제
# poetry.lock 파일 기반으로 정확한 버전 설치
poetry install
# poetry.lock 없이 pyproject.toml만 보고 새로 해결하여 설치
poetry install --no-root
# poetry.lock과 pyproject.toml의 동기화 확인
poetry check
# 잠금 파일 강제 재생성 (의존성 재해결)
poetry lock
# 잠금 파일 업데이트하지 않고 설치만 (CI에서 유용)
poetry install --no-interaction
# poetry.lock 파일 내용 예시 (자동 생성됨)
# [[package]]
# name = "requests"
# version = "2.31.0"
# description = "Python HTTP for Humans."
# files = [
# {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187..."},
# {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98..."},
# ]
설명
이것이 하는 일: poetry.lock 파일은 프로젝트의 의존성 스냅샷을 저장하고, poetry install 명령어가 이 스냅샷을 기반으로 정확히 동일한 패키지들을 설치하도록 합니다. 첫 번째로, 개발자가 poetry add requests를 실행하면 Poetry는 의존성을 해결하고 poetry.lock 파일을 생성합니다.
이 파일에는 requests 패키지뿐만 아니라 requests가 의존하는 모든 하위 패키지(urllib3, certifi, idna 등)의 정확한 버전이 기록됩니다. 예를 들어 "requests 2.31.0은 urllib3 1.26.0에서 2.0.7 사이의 버전이 필요하다"는 제약 조건을 만족하는 구체적인 버전으로 urllib3==2.0.7이 선택되고 기록됩니다.
그 다음으로, 각 패키지의 다운로드 파일(wheel과 source distribution)에 대한 SHA256 해시값도 함께 저장됩니다. 이는 보안을 위한 것으로, 나중에 패키지를 설치할 때 다운로드된 파일의 해시를 계산하여 poetry.lock에 기록된 값과 비교합니다.
만약 다르다면 패키지가 변조되었을 가능성이 있으므로 설치를 중단합니다. 다른 개발자나 CI/CD 시스템에서 poetry install을 실행하면, Poetry는 pyproject.toml을 보고 새로 의존성을 해결하는 것이 아니라 poetry.lock에 기록된 정확한 버전들을 설치합니다.
이것이 "결정론적 설치(deterministic install)"의 핵심입니다. 어제 설치하든 오늘 설치하든, 한국에서 설치하든 미국에서 설치하든 항상 동일한 결과를 얻습니다.
poetry check 명령어는 pyproject.toml과 poetry.lock이 일치하는지 확인합니다. 만약 누군가 pyproject.toml을 수동으로 편집했는데 poetry.lock을 업데이트하지 않았다면 경고를 표시합니다.
CI/CD 파이프라인에서 이 명령어를 실행하여 실수를 조기에 발견할 수 있습니다. 여러분이 poetry.lock을 git에 커밋하고 관리하면 "내 컴퓨터에서는 되는데요" 문제가 완전히 사라집니다.
또한 몇 달 후에 프로젝트를 다시 실행해야 할 때도 당시의 정확한 환경을 재현할 수 있어 유지보수가 훨씬 쉬워집니다. 보안 관점에서도 패키지 해시 검증 기능이 공급망 공격(supply chain attack)을 방어하는 데 도움이 됩니다.
실전 팁
💡 poetry.lock 파일은 절대 수동으로 편집하지 마세요. 항상 poetry add, poetry update, poetry lock 같은 명령어를 통해서만 수정해야 합니다. 수동 편집 시 해시값이 맞지 않아 설치가 실패할 수 있습니다.
💡 CI/CD 파이프라인에서는 poetry install --no-root --no-interaction 명령어를 사용하세요. --no-root는 프로젝트 자체를 설치하지 않고 의존성만 설치하고, --no-interaction은 대화형 프롬프트를 비활성화하여 자동화에 적합합니다.
💡 poetry.lock 파일이 git 충돌(conflict)을 일으키면 poetry lock --no-update 명령어로 해결하세요. 이 명령어는 pyproject.toml을 기반으로 잠금 파일을 재생성하되 패키지 버전은 업데이트하지 않습니다.
💡 대규모 프로젝트에서는 주기적으로 poetry update --dry-run을 실행하여 업데이트 가능한 패키지를 확인하고, 보안 패치가 포함된 것들은 우선적으로 업데이트하세요. 단, 한 번에 모든 패키지를 업데이트하지 말고 중요한 것부터 하나씩 테스트하면서 업데이트하는 것이 안전합니다.
5. 가상환경 관리 - 자동화된 격리
시작하며
여러분이 Python 프로젝트를 시작할 때마다 가상환경을 만들고, activate 스크립트를 실행하고, 가끔은 어떤 가상환경을 활성화했는지 헷갈려서 엉뚱한 환경에 패키지를 설치했던 경험이 있나요? 그리고 프로젝트별로 가상환경 폴더가 흩어져 있어서 관리하기 어려웠던 기억도 있을 것입니다.
이런 문제는 수동으로 가상환경을 관리할 때 자주 발생합니다. virtualenv나 venv를 사용하면 activate를 잊어버리거나, 여러 터미널을 열었을 때 어떤 환경이 활성화되어 있는지 알기 어렵습니다.
또한 프로젝트를 삭제할 때 가상환경 폴더도 함께 삭제해야 한다는 것을 잊어버려서 디스크 공간이 낭비되기도 합니다. 바로 이럴 때 필요한 것이 Poetry의 자동 가상환경 관리입니다.
Poetry는 프로젝트마다 자동으로 가상환경을 생성하고 관리하며, 명령어 실행 시 자동으로 올바른 환경을 사용합니다.
개요
간단히 말해서, Poetry의 가상환경 관리는 프로젝트별로 격리된 Python 환경을 자동으로 생성하고 활성화하는 기능입니다. poetry install을 처음 실행하면 Poetry가 자동으로 가상환경을 생성하고 그 안에 의존성을 설치합니다.
이후 poetry run이나 poetry shell 명령어로 가상환경을 사용할 수 있으며, activate 스크립트를 수동으로 실행할 필요가 없습니다. Poetry는 기본적으로 중앙 집중식으로 가상환경을 관리하지만, 설정을 변경하여 프로젝트 디렉토리 내에 .venv 폴더를 만들 수도 있습니다.
기존에는 python -m venv .venv로 가상환경을 만들고, source .venv/bin/activate로 활성화하고, 사용 후 deactivate로 비활성화했다면, 이제는 Poetry가 모든 것을 자동으로 처리합니다. Poetry 가상환경 관리의 핵심 특징은 자동 생성, 자동 활성화, 그리고 중앙 집중식 관리입니다.
이러한 특징들이 개발 워크플로우를 단순화하고, 가상환경 관련 실수를 방지하며, 프로젝트 간 격리를 확실하게 보장합니다.
코드 예제
# 의존성 설치 시 자동으로 가상환경 생성
poetry install
# 가상환경에서 명령어 실행 (activate 불필요)
poetry run python main.py
poetry run pytest
poetry run black .
# 가상환경의 셸 활성화 (전통적인 방식 선호 시)
poetry shell
# 가상환경 정보 확인
poetry env info
# 가상환경 경로 확인
poetry env info --path
# 가상환경 삭제하고 재생성
poetry env remove python
poetry install
# 특정 Python 버전으로 가상환경 생성
poetry env use python3.11
poetry env use /usr/local/bin/python3.11
# 가상환경을 프로젝트 폴더에 생성하도록 설정
poetry config virtualenvs.in-project true
설명
이것이 하는 일: Poetry는 프로젝트별로 격리된 가상환경을 자동으로 생성하고, 명령어 실행 시 자동으로 해당 환경을 활성화하여 시스템 Python과 완전히 분리된 환경을 제공합니다. 첫 번째로, poetry install을 실행하면 Poetry는 현재 프로젝트에 대한 가상환경이 존재하는지 확인합니다.
없다면 자동으로 새 가상환경을 생성하는데, 기본적으로는 {cache-dir}/virtualenvs/ 경로에 프로젝트 이름과 해시를 조합한 이름으로 생성됩니다. 예를 들어 "my-project-py3.9"처럼 Python 버전도 포함된 이름으로 만들어져 나중에 알아보기 쉽습니다.
그 다음으로, poetry run 명령어를 사용하면 Poetry가 자동으로 해당 프로젝트의 가상환경을 활성화하고 그 안에서 명령어를 실행합니다. 예를 들어 poetry run python main.py를 실행하면 시스템의 Python이 아닌 가상환경의 Python이 사용되며, 거기에 설치된 패키지들만 접근할 수 있습니다.
이는 프로젝트 간 의존성 충돌을 완벽하게 방지합니다. poetry shell 명령어는 전통적인 activate와 비슷하게 작동하지만 더 편리합니다.
이 명령어를 실행하면 새로운 서브셸이 시작되면서 가상환경이 활성화되고, 프롬프트가 변경되어 어떤 환경에서 작업 중인지 명확히 알 수 있습니다. 작업이 끝나면 exit로 셸을 종료하면 됩니다.
poetry env info 명령어로 현재 사용 중인 가상환경의 상세 정보를 확인할 수 있습니다. Python 버전, 가상환경 경로, pip/setuptools 버전 등이 표시되어 디버깅 시 유용합니다.
특히 여러 Python 버전을 사용하는 프로젝트에서 현재 어떤 버전이 활성화되어 있는지 확인할 때 필수적입니다. 설정을 변경하여 poetry config virtualenvs.in-project true를 실행하면 가상환경이 프로젝트 디렉토리 내의 .venv 폴더에 생성됩니다.
이렇게 하면 VSCode, PyCharm 같은 IDE가 가상환경을 자동으로 감지하여 코드 자동완성과 타입 체킹이 더 잘 작동합니다. 또한 프로젝트를 삭제하면 가상환경도 함께 삭제되어 관리가 편리합니다.
여러분이 Poetry의 가상환경 관리를 사용하면 activate를 잊어버리는 실수가 사라지고, 여러 프로젝트를 동시에 작업할 때도 환경이 섞이지 않습니다. 또한 팀원들이 각자 다른 방식으로 가상환경을 만들 필요 없이 Poetry만 사용하면 되므로 온보딩이 훨씬 간편해집니다.
실전 팁
💡 VSCode 사용자라면 반드시 poetry config virtualenvs.in-project true 설정을 활성화하세요. 그러면 VSCode가 .venv 폴더를 자동으로 감지하여 Python 인터프리터를 올바르게 설정하고, 자동완성과 린팅이 제대로 작동합니다.
💡 가상환경이 깨졌거나 이상하게 작동한다면 poetry env remove python && poetry install로 완전히 재생성하세요. 특히 Python 버전을 업그레이드한 후에는 가상환경을 재생성하는 것이 좋습니다.
💡 여러 Python 버전을 테스트해야 한다면 pyenv와 Poetry를 함께 사용하세요. pyenv local 3.9.0 3.10.0 3.11.0 으로 여러 버전을 설정한 후 poetry env use 3.9처럼 원하는 버전을 선택할 수 있습니다.
💡 CI/CD 환경에서는 가상환경 캐싱을 활용하세요. GitHub Actions의 경우 ~/.cache/pypoetry/virtualenvs 경로를 캐시하면 빌드 시간을 크게 단축할 수 있습니다.
6. 개발 의존성 그룹 관리 - 의존성의 세밀한 분리
시작하며
여러분이 프로젝트를 개발할 때 pytest, black, mypy 같은 도구들을 사용하지만, 이런 도구들이 프로덕션 서버에는 필요 없다는 것을 알고 계시나요? 하지만 requirements.txt에는 모든 패키지가 섞여 있어서 배포 시 불필요한 패키지까지 설치되어 Docker 이미지 크기가 불필요하게 커지고 보안 위험도 증가합니다.
이런 문제는 의존성을 용도별로 분리하지 못했을 때 발생합니다. 개발 도구, 테스트 도구, 문서 생성 도구, 타입 체킹 도구 등이 모두 섞여 있으면 관리도 어렵고, "이 패키지가 왜 설치되어 있지?"라는 의문이 생기기도 합니다.
바로 이럴 때 필요한 것이 Poetry의 의존성 그룹 기능입니다. 개발, 테스트, 문서 등 용도별로 의존성을 그룹화하여 필요한 것만 선택적으로 설치할 수 있습니다.
개요
간단히 말해서, 의존성 그룹은 패키지들을 용도별로 분류하여 선택적으로 설치할 수 있게 하는 기능입니다. Poetry는 [tool.poetry.dependencies]에 운영 의존성을, [tool.poetry.group.dev.dependencies], [tool.poetry.group.test.dependencies] 같은 섹션에 각각의 개발 의존성을 관리할 수 있습니다.
프로덕션 배포 시에는 poetry install --without dev,test처럼 특정 그룹을 제외하거나, poetry install --only main으로 운영 의존성만 설치할 수 있습니다. 기존에는 requirements.txt와 requirements-dev.txt를 별도로 관리하고, pip install -r로 각각 설치했지만, 두 파일 간 중복 관리가 필요하고 동기화가 어려웠습니다.
Poetry는 하나의 pyproject.toml에서 모든 그룹을 관리하면서도 선택적 설치가 가능합니다. 의존성 그룹의 핵심 특징은 논리적 분리, 선택적 설치, 그리고 명확한 목적 표시입니다.
이러한 특징들이 배포 최적화, 보안 향상, 그리고 프로젝트 구조의 명확성을 크게 개선합니다.
코드 예제
# pyproject.toml 예시
[tool.poetry.dependencies]
python = "^3.9"
fastapi = "^0.104.0"
uvicorn = "^0.24.0"
sqlalchemy = "^2.0.0"
[tool.poetry.group.dev.dependencies]
black = "^23.0.0"
ruff = "^0.1.0"
pre-commit = "^3.5.0"
[tool.poetry.group.test.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-asyncio = "^0.21.0"
[tool.poetry.group.docs.dependencies]
mkdocs = "^1.5.0"
mkdocs-material = "^9.4.0"
# 모든 의존성 설치 (기본)
poetry install
# 개발 그룹 제외하고 설치 (프로덕션)
poetry install --without dev
# 여러 그룹 제외
poetry install --without dev,test,docs
# 운영 의존성만 설치
poetry install --only main
# 특정 그룹만 설치
poetry install --only docs
# 개발 의존성을 특정 그룹에 추가
poetry add --group test pytest-mock
설명
이것이 하는 일: 의존성 그룹 기능은 프로젝트의 패키지들을 용도별로 조직화하고, 설치 시 필요한 그룹만 선택할 수 있게 하여 환경별 최적화를 가능하게 합니다. 첫 번째로, pyproject.toml에서 [tool.poetry.group.{그룹명}.dependencies] 형식으로 의존성 그룹을 정의합니다.
예를 들어 [tool.poetry.group.test.dependencies]에는 pytest, pytest-cov, pytest-asyncio 같은 테스트 관련 패키지만 모아둡니다. 이렇게 하면 "이 패키지는 테스트 용도"라는 것이 명확해져 코드 리뷰 시에도 이해하기 쉽습니다.
그 다음으로, 각 환경에 맞게 선택적 설치가 가능합니다. 로컬 개발 환경에서는 poetry install로 모든 그룹을 설치하여 코드 포맷팅, 린팅, 테스트, 문서 생성 등 모든 작업을 수행할 수 있습니다.
하지만 프로덕션 배포 시에는 poetry install --without dev,test,docs를 사용하여 fastapi, uvicorn, sqlalchemy 같은 운영에 필수적인 패키지만 설치합니다. Docker 이미지를 빌드할 때 이 기능이 특히 빛을 발합니다.
멀티 스테이지 빌드에서 빌드 단계에는 모든 의존성을 설치하여 테스트와 빌드를 수행하고, 최종 런타임 이미지에는 --only main으로 운영 의존성만 복사합니다. 이렇게 하면 이미지 크기가 수백 MB 줄어들고, 보안 스캔 시 취약점도 크게 감소합니다.
poetry add --group test pytest-mock 명령어로 특정 그룹에 새 패키지를 추가할 수 있습니다. 이는 pyproject.toml의 해당 그룹 섹션에 자동으로 추가되며, poetry.lock도 함께 업데이트됩니다.
그룹을 지정하지 않으면 기본적으로 main 그룹(운영 의존성)에 추가됩니다. 여러분이 의존성 그룹을 제대로 활용하면 프로덕션 배포가 가볍고 빠르며 안전해집니다.
또한 새로운 팀원이 프로젝트에 합류했을 때 pyproject.toml만 보고도 어떤 패키지가 어떤 용도로 사용되는지 즉시 파악할 수 있어 온보딩이 수월합니다. CI/CD 파이프라인에서도 각 단계에 필요한 의존성만 설치하여 빌드 시간을 최적화할 수 있습니다.
실전 팁
💡 그룹 이름은 자유롭게 정할 수 있습니다. 프로젝트에 맞게 lint, format, security 같은 세부 그룹을 만들어 더 세밀하게 관리할 수 있습니다.
💡 CI/CD에서는 각 단계에 맞는 의존성만 설치하세요. 예를 들어 테스트 단계에서는 poetry install --with test, 린트 단계에서는 poetry install --only dev 이런 식으로 최적화할 수 있습니다.
💡 선택적 의존성(optional dependencies)과 그룹을 혼동하지 마세요. 그룹은 개발 워크플로우에 따른 분류이고, extras([tool.poetry.extras])는 사용자가 선택 가능한 기능입니다. 예를 들어 데이터베이스 지원을 선택적으로 만들려면 extras를 사용합니다.
💡 Dockerfile에서는 멀티 스테이지 빌드를 활용하세요. builder 스테이지에서 테스트까지 수행한 후, runtime 스테이지에서는 poetry install --only main --no-root 으로 최소한의 의존성만 포함하여 이미지 크기를 줄이세요.
7. 스크립트와 명령어 실행 - 편리한 워크플로우
시작하며
여러분이 프로젝트에서 자주 실행하는 명령어들이 있나요? 예를 들어 테스트 실행, 코드 포맷팅, 데이터베이스 마이그레이션, 개발 서버 시작 같은 작업들 말이죠.
매번 긴 명령어를 타이핑하거나, bash 스크립트를 별도로 작성하고 관리하는 것이 번거로웠던 경험이 있을 것입니다. 이런 문제는 프로젝트가 커질수록 더 심각해집니다.
팀원마다 다른 명령어를 사용하거나, 새로운 팀원이 "어떻게 테스트를 실행하나요?"라고 물어볼 때마다 설명해야 하는 상황이 발생합니다. 또한 가상환경을 활성화하지 않고 명령어를 실행하는 실수도 자주 일어납니다.
바로 이럴 때 필요한 것이 Poetry의 스크립트 기능입니다. pyproject.toml에 자주 사용하는 명령어를 정의하여 간단한 이름으로 실행할 수 있고, 항상 올바른 가상환경에서 실행됩니다.
개요
간단히 말해서, Poetry 스크립트는 자주 사용하는 명령어를 pyproject.toml에 정의하여 짧은 이름으로 실행할 수 있는 기능입니다. [tool.poetry.scripts] 섹션에 스크립트를 정의하면 poetry run {스크립트명} 형태로 실행할 수 있습니다.
또한 패키지를 설치하면 시스템 전역에서 사용 가능한 CLI 도구도 만들 수 있습니다. poetry run 명령어는 자동으로 가상환경을 활성화하므로 activate를 잊어버리는 실수를 방지합니다.
기존에는 Makefile이나 bash 스크립트에 명령어를 정의하거나, package.json의 scripts처럼 별도 파일을 관리했다면, 이제는 pyproject.toml 하나에서 프로젝트 설정과 스크립트를 함께 관리할 수 있습니다. Poetry 스크립트의 핵심 특징은 중앙 집중식 정의, 자동 환경 활성화, 그리고 크로스 플랫폼 호환성입니다.
이러한 특징들이 개발 워크플로우를 표준화하고, 팀 협업을 개선하며, 온보딩 시간을 크게 단축시킵니다.
코드 예제
# pyproject.toml에 스크립트 정의
[tool.poetry.scripts]
# CLI 진입점 (패키지 설치 시 전역 명령어로 사용 가능)
mycli = "my_package.cli:main"
# 개발용 스크립트들
[tool.poetry.scripts]
test = "pytest tests/"
format = "black ."
lint = "ruff check ."
typecheck = "mypy my_package/"
serve = "uvicorn my_package.main:app --reload"
# 스크립트 실행 (가상환경 자동 활성화)
poetry run test
poetry run format
poetry run lint
poetry run serve
# 임의의 명령어 실행
poetry run python -m my_package.scripts.migrate
poetry run pytest tests/test_api.py -v
# 여러 명령어 체이닝
poetry run format && poetry run lint && poetry run test
# shell 스크립트와 함께 사용
# tasks.py 파일 생성 후
poetry run python tasks.py build
poetry run python tasks.py deploy
설명
이것이 하는 일: Poetry 스크립트 기능은 프로젝트의 자주 사용하는 명령어들을 pyproject.toml에 정의하고, poetry run 명령어로 가상환경에서 안전하게 실행합니다. 첫 번째로, [tool.poetry.scripts] 섹션에 스크립트를 정의합니다.
가장 일반적인 형태는 스크립트명 = "명령어" 형식입니다. 예를 들어 test = "pytest tests/"로 정의하면 poetry run test 명령어로 pytest를 실행할 수 있습니다.
하지만 주의할 점은 Poetry 1.2 이후 버전에서는 이런 간단한 문자열 형식이 지원되지 않으므로, 실제로는 Python 함수를 가리키는 형식을 사용해야 합니다. 그 다음으로, CLI 진입점을 정의할 수 있습니다.
mycli = "my_package.cli:main" 형식은 my_package/cli.py 파일의 main() 함수를 가리킵니다. 이렇게 정의하면 패키지를 설치한 후 가상환경에서 mycli 명령어로 직접 실행할 수 있습니다.
이는 자신만의 CLI 도구를 만들 때 매우 유용하며, Click이나 Typer 같은 라이브러리와 조합하면 강력한 명령줄 도구를 만들 수 있습니다. poetry run 명령어는 단순히 명령어를 실행하는 것 이상의 기능을 합니다.
먼저 프로젝트의 가상환경을 찾아 활성화하고, PATH 환경변수를 설정하여 가상환경의 바이너리들이 우선 실행되도록 하며, 명령어 실행 후 환경을 정리합니다. 이 모든 과정이 자동으로 이루어지므로 개발자는 activate를 신경 쓸 필요가 없습니다.
여러 명령어를 체이닝할 때는 && 연산자를 사용하여 이전 명령어가 성공해야 다음 명령어가 실행되도록 할 수 있습니다. 예를 들어 poetry run format && poetry run lint && poetry run test는 코드를 포맷팅하고, 린트를 확인하고, 테스트를 실행하는 일련의 작업을 자동화합니다.
중간에 하나라도 실패하면 멈추므로 CI/CD 파이프라인에서 유용합니다. 여러분이 Poetry 스크립트를 활용하면 팀 전체가 동일한 명령어를 사용하게 되어 커뮤니케이션이 명확해집니다.
README에 "테스트는 poetry run test로 실행하세요"라고 한 줄만 적으면 되므로 문서화도 간단해집니다. 또한 스크립트 정의가 버전 관리되므로 명령어가 변경될 때도 히스토리를 추적할 수 있습니다.
실전 팁
💡 복잡한 스크립트는 별도의 tasks.py 파일을 만들어 관리하세요. invoke나 nox 같은 태스크 러너를 사용하면 더 강력한 워크플로우를 구축할 수 있습니다. pyproject.toml에는 tasks = "invoke {태스크명}" 형태로 래퍼만 정의하세요.
💡 pre-commit 훅과 Poetry 스크립트를 연계하세요. .pre-commit-config.yaml에서 poetry run format, poetry run lint를 실행하도록 설정하면 커밋 전 자동으로 코드 품질을 검사할 수 있습니다.
💡 환경변수가 필요한 스크립트는 python-dotenv를 사용하세요. .env 파일에 환경변수를 정의하고, 스크립트 시작 부분에서 load_dotenv()를 호출하면 됩니다. 이렇게 하면 개발/스테이징/프로덕션 환경을 쉽게 전환할 수 있습니다.
💡 poetry run이 번거롭다면 poetry shell로 가상환경을 활성화한 후 명령어를 직접 실행할 수도 있습니다. 하지만 CI/CD 환경이나 스크립트에서는 항상 poetry run을 사용하는 것이 안전합니다.
8. 패키지 빌드와 배포 - PyPI에 공개하기
시작하며
여러분이 유용한 Python 라이브러리를 만들어서 다른 사람들과 공유하고 싶을 때, setup.py를 작성하고, wheel을 빌드하고, twine으로 업로드하는 복잡한 과정을 거쳐야 했던 경험이 있나요? 버전을 업데이트할 때마다 여러 파일을 수정하고, 배포 과정에서 실수하기도 쉬웠을 것입니다.
이런 문제는 Python 패키징의 전통적인 복잡성 때문입니다. setup.py, setup.cfg, MANIFEST.in 등 여러 파일을 관리해야 하고, 배포 과정도 여러 단계로 나뉘어 있어서 자동화하기 어렵습니다.
특히 처음 패키지를 배포하는 개발자에게는 진입 장벽이 높습니다. 바로 이럴 때 필요한 것이 Poetry의 빌드와 배포 기능입니다.
pyproject.toml 하나로 패키지 정보를 관리하고, 단일 명령어로 빌드와 배포를 처리할 수 있습니다.
개요
간단히 말해서, Poetry의 빌드 및 배포 기능은 패키지를 wheel과 sdist 형식으로 빌드하고 PyPI에 업로드하는 과정을 자동화합니다. poetry build 명령어는 dist/ 폴더에 배포 가능한 패키지 파일들을 생성하고, poetry publish 명령어는 이를 PyPI나 private 저장소에 업로드합니다.
버전 관리는 pyproject.toml의 version 필드 하나만 수정하면 되며, poetry-version-plugin 같은 플러그인을 사용하면 git 태그 기반 자동 버전 관리도 가능합니다. 기존에는 setup.py를 작성하고, python setup.py sdist bdist_wheel로 빌드하고, twine upload dist/*로 업로드했다면, 이제는 Poetry 명령어 두 개로 모든 작업이 완료됩니다.
Poetry 빌드/배포의 핵심 특징은 표준화된 빌드 프로세스, 자동 메타데이터 생성, 그리고 안전한 배포입니다. 이러한 특징들이 오픈소스 라이브러리 배포를 훨씬 쉽게 만들고, CI/CD를 통한 자동 배포도 간단하게 구현할 수 있게 해줍니다.
코드 예제
# pyproject.toml에서 패키지 정보 확인
[tool.poetry]
name = "my-awesome-library"
version = "0.1.0"
description = "A fantastic Python library"
authors = ["Your Name <you@example.com>"]
license = "MIT"
readme = "README.md"
homepage = "https://github.com/yourusername/my-awesome-library"
repository = "https://github.com/yourusername/my-awesome-library"
keywords = ["awesome", "library", "python"]
# 패키지 빌드 (wheel과 sdist 생성)
poetry build
# dist/ 폴더에 생성된 파일들
# my_awesome_library-0.1.0-py3-none-any.whl
# my_awesome_library-0.1.0.tar.gz
# PyPI 자격증명 설정 (최초 1회)
poetry config pypi-token.pypi YOUR_PYPI_TOKEN
# PyPI에 배포
poetry publish
# 빌드와 배포를 한 번에
poetry publish --build
# Test PyPI에 먼저 배포해보기
poetry config repositories.testpypi https://test.pypi.org/legacy/
poetry publish -r testpypi
# 버전 업데이트
poetry version patch # 0.1.0 -> 0.1.1
poetry version minor # 0.1.1 -> 0.2.0
poetry version major # 0.2.0 -> 1.0.0
설명
이것이 하는 일: Poetry의 빌드 및 배포 명령어는 프로젝트를 표준 Python 패키지 형식으로 변환하고, PyPI나 private 저장소에 안전하게 업로드합니다. 첫 번째로, poetry build 명령어를 실행하면 Poetry는 pyproject.toml의 정보를 읽어 패키지 메타데이터를 생성합니다.
그런 다음 두 가지 형식의 배포 파일을 만듭니다. wheel(.whl)은 미리 컴파일된 형식으로 설치가 빠르고, source distribution(.tar.gz)은 소스 코드 형태로 모든 플랫폼에서 빌드할 수 있습니다.
이 파일들은 dist/ 폴더에 저장되며, 이것이 실제로 pip install로 설치되는 파일들입니다. 그 다음으로, PyPI 배포를 위해 인증 토큰을 설정합니다.
poetry config pypi-token.pypi YOUR_PYPI_TOKEN 명령어는 토큰을 안전하게 저장하여 이후 배포 시 자동으로 사용합니다. PyPI 토큰은 PyPI 웹사이트의 계정 설정에서 생성할 수 있으며, 패스워드보다 안전하고 권한을 세밀하게 제어할 수 있습니다.
poetry publish 명령어가 실행되면 dist/ 폴더의 파일들이 PyPI 서버로 업로드됩니다. 업로드 전에 파일의 무결성을 검증하고, HTTPS를 통해 안전하게 전송하며, 서버에서 패키지 메타데이터가 유효한지 확인합니다.
업로드가 완료되면 몇 분 내에 pip install my-awesome-library로 전 세계 누구나 설치할 수 있게 됩니다. 버전 관리는 poetry version 명령어로 간단히 처리할 수 있습니다.
poetry version patch는 패치 버전을 증가시켜 버그 수정을 의미하고, minor는 새 기능 추가, major는 호환성이 깨지는 변경을 의미합니다. 이 명령어는 pyproject.toml의 version 필드만 업데이트하므로, 변경 후 git 커밋과 태그를 만들어야 합니다.
Test PyPI는 실제 배포 전에 연습할 수 있는 샌드박스 환경입니다. 여기에 먼저 배포해보면 패키지 이름 충돌, 메타데이터 오류, 설치 문제 등을 미리 발견할 수 있습니다.
poetry config repositories.testpypi로 저장소를 추가하고, -r testpypi 옵션으로 해당 저장소에 배포합니다. 여러분이 이 기능을 활용하면 자신만의 오픈소스 라이브러리를 쉽게 공유할 수 있고, 회사 내부에서는 private PyPI 서버로 팀 간 코드 재사용을 촉진할 수 있습니다.
또한 GitHub Actions와 연계하여 git 태그를 푸시하면 자동으로 새 버전이 PyPI에 배포되는 CI/CD 파이프라인도 구축할 수 있습니다.
실전 팁
💡 PyPI 토큰은 환경변수 POETRY_PYPI_TOKEN_PYPI로도 설정할 수 있습니다. CI/CD 환경에서는 토큰을 파일에 저장하지 말고 GitHub Secrets나 환경변수로 관리하세요.
💡 pyproject.toml에 classifiers를 추가하면 PyPI에서 패키지를 찾기 쉬워집니다. 예: classifiers = ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License"]
💡 private PyPI 서버(JFrog Artifactory, AWS CodeArtifact 등)를 사용한다면 poetry config repositories.private https://...로 등록하고, 해당 저장소용 토큰을 별도로 설정하세요.
💡 자동 버전 관리를 원한다면 poetry-dynamic-versioning 플러그인을 사용하세요. git 태그를 기반으로 버전을 자동 생성하여 pyproject.toml을 수동으로 수정할 필요가 없습니다.
9. Poetry와 Docker 통합 - 컨테이너 환경 최적화
시작하며
여러분이 Python 애플리케이션을 Docker로 컨테이너화할 때, requirements.txt를 복사하고 pip install을 실행하는데 빌드 시간이 너무 오래 걸렸던 경험이 있나요? 그리고 이미지 크기가 수백 MB 이상으로 커져서 배포가 느렸던 기억도 있을 것입니다.
이런 문제는 Docker 레이어 캐싱을 제대로 활용하지 못하거나, 불필요한 개발 의존성까지 포함했을 때 발생합니다. 특히 Poetry를 사용하는 프로젝트에서는 가상환경 관리와 의존성 설치 방식이 달라서 Dockerfile 작성이 까다롭습니다.
바로 이럴 때 필요한 것이 Poetry와 Docker의 올바른 통합 방법입니다. 멀티 스테이지 빌드, 레이어 캐싱 최적화, 운영 의존성만 포함하기 등의 기법을 사용하면 빠르고 가벼운 이미지를 만들 수 있습니다.
개요
간단히 말해서, Poetry와 Docker 통합은 컨테이너 환경에서 Poetry의 장점을 활용하면서도 이미지 크기와 빌드 시간을 최적화하는 기술입니다. 핵심은 멀티 스테이지 빌드를 사용하여 빌드 단계와 런타임 단계를 분리하고, Poetry 설정을 조정하여 가상환경을 시스템 Python에 직접 설치하며, --only main 옵션으로 운영 의존성만 포함하는 것입니다.
또한 pyproject.toml과 poetry.lock을 먼저 복사하여 Docker 레이어 캐싱을 최대한 활용합니다. 기존에는 Dockerfile에서 pip install을 직접 사용하거나, Poetry를 그대로 사용하면서 비효율적인 이미지를 만들었다면, 이제는 최적화된 패턴을 적용하여 프로덕션 환경에 적합한 이미지를 생성할 수 있습니다.
Poetry-Docker 통합의 핵심 특징은 레이어 캐싱 최적화, 운영 의존성만 포함, 그리고 작은 베이스 이미지 사용입니다. 이러한 특징들이 CI/CD 빌드 시간을 크게 단축하고, 배포 속도를 향상시키며, 보안 취약점을 줄입니다.
코드 예제
# Dockerfile - 멀티 스테이지 빌드 최적화
FROM python:3.11-slim as builder
# Poetry 설치
ENV POETRY_VERSION=1.7.1
ENV POETRY_HOME=/opt/poetry
ENV POETRY_NO_INTERACTION=1
ENV POETRY_VIRTUALENVS_IN_PROJECT=1
ENV POETRY_VIRTUALENVS_CREATE=1
RUN pip install "poetry==$POETRY_VERSION"
WORKDIR /app
# 의존성 파일만 먼저 복사 (캐싱 최적화)
COPY pyproject.toml poetry.lock ./
# 운영 의존성만 설치
RUN poetry install --only main --no-root --no-directory
# 런타임 스테이지
FROM python:3.11-slim as runtime
WORKDIR /app
# builder에서 가상환경만 복사
COPY --from=builder /app/.venv ./.venv
# 애플리케이션 코드 복사
COPY . .
# 가상환경의 Python 사용
ENV PATH="/app/.venv/bin:$PATH"
# 실행
CMD ["python", "-m", "my_app.main"]
# .dockerignore 파일
__pycache__/
*.py[cod]
.venv/
.git/
.pytest_cache/
.mypy_cache/
설명
이것이 하는 일: Poetry와 Docker를 통합하는 최적화된 Dockerfile은 빌드 시간을 단축하고 이미지 크기를 최소화하면서 모든 의존성을 정확하게 포함합니다. 첫 번째로, 멀티 스테이지 빌드를 사용하여 builder와 runtime 스테이지를 분리합니다.
builder 스테이지에서는 Poetry를 설치하고 의존성을 해결하며 가상환경을 생성합니다. 이 과정에서 필요한 빌드 도구, Poetry 자체, 그리고 캐시 파일들이 생성되지만, 이들은 최종 이미지에 포함되지 않습니다.
runtime 스테이지에서는 오직 생성된 가상환경과 애플리케이션 코드만 복사하므로 이미지가 최소화됩니다. 그 다음으로, 환경변수 설정이 중요합니다.
POETRY_VIRTUALENVS_IN_PROJECT=1은 가상환경을 프로젝트 디렉토리의 .venv 폴더에 생성하여 쉽게 복사할 수 있게 하고, POETRY_VIRTUALENVS_CREATE=1은 가상환경 생성을 보장하며, POETRY_NO_INTERACTION=1은 대화형 프롬프트를 비활성화하여 자동화에 적합하게 만듭니다. Docker 레이어 캐싱을 최대한 활용하기 위해 pyproject.toml과 poetry.lock을 애플리케이션 코드보다 먼저 복사합니다.
이렇게 하면 코드가 변경되어도 의존성이 바뀌지 않았다면 poetry install 단계가 캐시에서 재사용되어 빌드가 훨씬 빨라집니다. 특히 의존성이 많은 프로젝트에서는 몇 분에서 몇 초로 빌드 시간이 단축될 수 있습니다.
poetry install --only main --no-root --no-directory 명령어의 각 옵션은 중요한 역할을 합니다. --only main은 개발 의존성을 제외하고 운영 의존성만 설치하여 이미지 크기를 줄이고, --no-root는 프로젝트 자체를 editable mode로 설치하지 않으며, --no-directory는 아직 소스 코드가 없어도 의존성만 설치할 수 있게 합니다.
runtime 스테이지에서는 COPY --from=builder /app/.venv ./.venv로 빌드된 가상환경만 복사합니다. 그 후 ENV PATH="/app/.venv/bin:$PATH"로 PATH를 설정하여 가상환경의 Python과 패키지들이 자동으로 사용되도록 합니다.
이렇게 하면 activate 명령어 없이도 가상환경이 활성화된 상태가 됩니다. 여러분이 이 패턴을 사용하면 Docker 이미지 크기가 수백 MB 줄어들고, CI/CD 파이프라인에서 빌드 캐싱 덕분에 2차 빌드부터는 대부분 30초 이내에 완료됩니다.
또한 프로덕션 환경에서 불필요한 개발 도구가 제외되어 보안 스캔 결과도 크게 개선됩니다.
실전 팁
💡 python:3.11-slim 대신 python:3.11-alpine을 사용하면 이미지가 더 작아지지만, 일부 패키지(pandas, numpy 등)는 컴파일 시간이 오래 걸리거나 문제가 발생할 수 있으니 주의하세요.
💡 BuildKit을 활성화하면 더 나은 캐싱과 병렬 빌드를 활용할 수 있습니다. DOCKER_BUILDKIT=1 docker build 형태로 실행하거나, Docker Desktop 설정에서 활성화하세요.
💡 의존성 설치 속도를 더 높이려면 POETRY_INSTALLER_PARALLEL=true 환경변수를 설정하여 병렬 설치를 활성화하세요. 단, 일부 패키지에서 충돌이 발생할 수 있으니 테스트가 필요합니다.
💡 .dockerignore 파일을 반드시 작성하세요. pycache, .venv, .git 같은 폴더를 제외하면 빌드 컨텍스트가 작아져 Docker 빌드가 더 빨라집니다.
💡 보안을 위해 non-root 사용자로 실행하세요. runtime 스테이지에서 RUN useradd -m -u 1000 appuser && chown -R appuser /app 후 USER appuser를 추가하는 것이 좋습니다.
10. CI/CD 환경에서 Poetry 활용 - 자동화 파이프라인
시작하며
여러분이 GitHub Actions나 GitLab CI로 자동화 파이프라인을 구축할 때, 매번 의존성을 새로 설치하느라 빌드가 5분 이상 걸렸던 경험이 있나요? 그리고 테스트는 통과했는데 배포 환경에서 다른 패키지 버전이 설치되어 문제가 발생했던 경험도 있을 것입니다.
이런 문제는 CI/CD 환경에서 캐싱을 제대로 활용하지 못하거나, poetry.lock 파일을 무시하고 매번 새로 의존성을 해결할 때 발생합니다. 특히 의존성이 많은 프로젝트에서는 빌드 시간이 팀 생산성에 큰 영향을 미칩니다.
바로 이럴 때 필요한 것이 CI/CD 환경에 최적화된 Poetry 사용 패턴입니다. 캐싱 전략, 병렬 실행, 의존성 그룹 활용 등으로 빌드 시간을 크게 단축할 수 있습니다.
개요
간단히 말해서, CI/CD에서 Poetry 활용은 자동화 파이프라인의 속도와 안정성을 최적화하는 설정과 패턴의 집합입니다. 핵심은 Poetry 설치를 캐싱하고, 의존성 파일(.venv 또는 ~/.cache/pypoetry)을 캐싱하며, poetry.lock 파일의 해시를 캐시 키로 사용하여 의존성이 변경될 때만 재설치하는 것입니다.
또한 --no-interaction 옵션으로 대화형 프롬프트를 방지하고, 의존성 그룹을 활용하여 각 단계에 필요한 패키지만 설치합니다. 기존에는 pip와 requirements.txt를 사용하거나, Poetry를 비효율적으로 사용하여 빌드마다 수분씩 기다렸다면, 이제는 최적화된 설정으로 대부분의 빌드를 1분 이내에 완료할 수 있습니다.
CI/CD Poetry 최적화의 핵심 특징은 공격적인 캐싱, 의존성 분리, 그리고 병렬 실행입니다. 이러한 특징들이 개발 피드백 루프를 빠르게 하고, 배포 안정성을 향상시키며, CI/CD 비용을 절감합니다.
코드 예제
# GitHub Actions 예시 (.github/workflows/ci.yml)
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11']
steps:
- uses: actions/checkout@v4
# Python 설치
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
# Poetry 설치 (캐싱 포함)
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.7.1
virtualenvs-create: true
virtualenvs-in-project: true
# 의존성 캐싱 (poetry.lock 해시 기반)
- name: Cache dependencies
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }}
# 의존성 설치
- name: Install dependencies
run: poetry install --with test
# 린트와 타입 체크 (병렬 실행 가능)
- name: Run linting
run: |
poetry run black --check .
poetry run ruff check .
poetry run mypy .
# 테스트 실행
- name: Run tests
run: poetry run pytest --cov --cov-report=xml
# 코드 커버리지 업로드
- name: Upload coverage
uses: codecov/codecov-action@v3
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
- uses: snok/install-poetry@v1
# 운영 의존성만 설치
- name: Install dependencies
run: poetry install --only main
# 배포 (예시)
- name: Deploy
run: poetry run python scripts/deploy.py
설명
이것이 하는 일: CI/CD에 최적화된 Poetry 설정은 캐싱을 활용하여 빌드 시간을 최소화하고, 의존성을 정확하게 재현하며, 각 단계에 필요한 패키지만 설치하여 효율성을 극대화합니다. 첫 번째로, Poetry 설치를 캐싱합니다.
snok/install-poetry@v1 액션은 Poetry를 효율적으로 설치하고 설정하는 공식 추천 방법입니다. virtualenvs-in-project: true 설정으로 가상환경을 프로젝트 폴더의 .venv에 생성하면 이후 캐싱이 쉬워집니다.
Poetry 자체도 여러 빌드에서 재사용되므로 설치 시간이 절약됩니다. 그 다음으로, 의존성 캐싱이 핵심입니다.
actions/cache@v3를 사용하여 .venv 폴더를 캐시하며, 캐시 키로 hashFiles('**/poetry.lock')을 사용합니다. 이는 poetry.lock 파일의 내용이 변경될 때만 새로운 캐시를 생성한다는 의미입니다.
만약 poetry.lock이 변경되지 않았다면 이전 빌드에서 캐시된 .venv를 그대로 복원하여 poetry install이 몇 초 만에 완료됩니다. 매트릭스 전략을 사용하여 여러 Python 버전에서 동시에 테스트합니다.
strategy.matrix.python-version에 ['3.9', '3.10', '3.11']을 지정하면 GitHub Actions가 세 개의 작업을 병렬로 실행하여 모든 지원 버전에서의 호환성을 빠르게 확인할 수 있습니다. 캐시 키에 Python 버전을 포함하여 각 버전별로 독립적인 캐시를 유지합니다.
의존성 그룹을 활용하여 각 단계를 최적화합니다. 테스트 단계에서는 --with test로 테스트 의존성을 포함하지만, 배포 단계에서는 --only main으로 운영 의존성만 설치합니다.
이렇게 하면 배포 아티팩트가 가벼워지고 보안 취약점도 줄어듭니다. --no-interaction 옵션은 CI/CD 환경에서 필수입니다.
이 옵션이 없으면 Poetry가 사용자 입력을 기다리며 멈출 수 있습니다. 또한 --no-root 옵션을 추가하여 프로젝트 자체를 editable mode로 설치하지 않도록 할 수도 있습니다.
여러분이 이런 설정을 적용하면 첫 번째 빌드는 2-3분 걸리지만, 이후 poetry.lock이 변경되지 않은 빌드는 30초 이내에 완료됩니다. 이는 PR 리뷰 시 빠른 피드백을 제공하여 개발 생산성을 크게 향상시킵니다.
또한 poetry.lock 파일 덕분에 모든 환경에서 정확히 동일한 의존성이 사용되어 "CI에서는 통과했는데 배포하면 실패해요" 문제가 사라집니다.
실전 팁
💡 GitLab CI를 사용한다면 .gitlab-ci.yml에서 cache.key: files: ["poetry.lock"] 형식으로 캐싱을 설정하세요. GitLab의 캐싱 메커니즘은 GitHub Actions와 약간 다르므로 문서를 참고하세요.
💡 poetry install 전에 poetry check --lock 명령어를 실행하여 pyproject.toml과 poetry.lock이 동기화되어 있는지 확인하세요. 동기화되지 않았다면 누군가 poetry.lock을 업데이트하지 않고 pyproject.toml을 수정한 것입니다.
💡 대규모 프로젝트에서는 린트, 타입 체크, 테스트를 별도의 job으로 분리하여 병렬 실행하세요. needs 키워드로 의존성을 정의하여 테스트가 통과한 후에만 배포가 진행되도록 할 수 있습니다.
💡 자동 배포를 설정할 때는 git 태그를 트리거로 사용하세요. if: startsWith(github.ref, 'refs/tags/v') 조건으로 v로 시작하는 태그가 푸시될 때만 poetry publish를 실행하도록 설정하면 안전합니다.
💡 의존성 설치 실패 시 디버깅하려면 poetry install -vvv 옵션으로 상세 로그를 출력하세요. 어떤 패키지에서 문제가 발생했는지 정확히 파악할 수 있습니다.