1 CI/CD에서 Poetry 사용 원칙
CI/CD 환경에서 Poetry를 사용할 때 핵심 원칙:
poetry.lock을 기준으로 설치 — 재현 가능한 빌드 보장- 캐시 활용 — 빌드 시간 단축
- 가상환경 생성 여부 제어 — Docker에서는 불필요할 수 있음
- 환경변수로 설정 — 설정 파일 대신 환경변수 사용
2 GitHub Actions
2.1 기본 설정
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
- name: Cache dependencies
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
restore-keys: |
venv-${{ runner.os }}-${{ matrix.python-version }}-
- name: Install dependencies
run: poetry install --no-interaction
- name: Run tests
run: poetry run pytest --cov
- name: Run linter
run: poetry run ruff check .2.2 캐싱 전략
Poetry 캐시의 핵심은 poetry.lock의 해시를 캐시 키로 사용하는 것이다.
2.3 자동 PyPI 배포
# .github/workflows/publish.yml
name: Publish to PyPI
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Poetry
uses: snok/install-poetry@v1
- name: Build and publish
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
run: |
poetry build
poetry publish3 GitLab CI
3.1 기본 설정
# .gitlab-ci.yml
image: python:3.11-slim
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
POETRY_VIRTUALENVS_IN_PROJECT: "true"
cache:
key:
files:
- poetry.lock
paths:
- .venv/
- .cache/pip/
stages:
- test
- build
- deploy
before_script:
- pip install poetry
- poetry install --no-interaction
test:
stage: test
script:
- poetry run pytest --cov
- poetry run ruff check .
build:
stage: build
script:
- poetry build
artifacts:
paths:
- dist/
deploy:
stage: deploy
only:
- tags
script:
- poetry publish --username __token__ --password $PYPI_TOKEN4 Docker 통합
4.1 기본 Dockerfile
FROM python:3.11-slim
# Poetry 설치
ENV POETRY_VERSION=1.8.0
RUN pip install "poetry==$POETRY_VERSION"
# 가상환경 생성 비활성화 (Docker 자체가 격리 환경)
ENV POETRY_VIRTUALENVS_CREATE=false
WORKDIR /app
# 의존성 파일만 먼저 복사 (Docker 레이어 캐시 활용)
COPY pyproject.toml poetry.lock ./
# 의존성 설치 (개발 의존성 제외)
RUN poetry install --only main --no-interaction --no-ansi
# 소스코드 복사
COPY src/ src/
CMD ["python", "-m", "my_project"]4.2 멀티스테이지 빌드 (권장)
빌드 도구를 최종 이미지에서 제거하여 이미지 크기를 줄인다.
# === Build stage ===
FROM python:3.11-slim AS builder
ENV POETRY_VERSION=1.8.0
RUN pip install "poetry==$POETRY_VERSION"
ENV POETRY_VIRTUALENVS_IN_PROJECT=true
WORKDIR /app
COPY pyproject.toml poetry.lock ./
RUN poetry install --only main --no-interaction --no-ansi
# === Runtime stage ===
FROM python:3.11-slim AS runtime
WORKDIR /app
# 빌드 스테이지에서 가상환경만 복사
COPY --from=builder /app/.venv /app/.venv
# PATH에 가상환경 추가
ENV PATH="/app/.venv/bin:$PATH"
COPY src/ src/
# Poetry 없이 직접 실행
CMD ["python", "-m", "my_project"]4.3 poetry export 방식 (Poetry 없이 배포)
Docker 이미지에 Poetry를 설치하지 않고, requirements.txt로 변환하여 pip으로 설치한다.
# 로컬에서 미리 실행:
# poetry export -f requirements.txt --without-hashes -o requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ src/
CMD ["python", "-m", "my_project"]
힌트
poetry export 방식은 이미지가 가장 가볍고 빌드가 빠르다. 단, requirements.txt를 최신 상태로 유지해야 하는 부담이 있다. CI에서 자동 생성하면 이 문제를 해결할 수 있다.
4.4 Docker 레이어 캐시 최적화
핵심은 의존성 파일을 소스코드보다 먼저 복사하는 것이다.
5 Docker Compose 예시
# docker-compose.yml
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
volumes:
- ./src:/app/src # 개발 시 코드 변경 즉시 반영
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
db:
image: postgres:15
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb6 개발용 vs 프로덕션용 Docker
# === 공통 베이스 ===
FROM python:3.11-slim AS base
ENV POETRY_VERSION=1.8.0
RUN pip install "poetry==$POETRY_VERSION"
ENV POETRY_VIRTUALENVS_CREATE=false
WORKDIR /app
COPY pyproject.toml poetry.lock ./
# === 프로덕션 ===
FROM base AS production
RUN poetry install --only main --no-interaction
COPY src/ src/
CMD ["python", "-m", "my_project"]
# === 개발 ===
FROM base AS development
RUN poetry install --no-interaction # dev 의존성 포함
COPY . .
CMD ["poetry", "run", "pytest", "--watch"]7 실무 체크리스트
CI/CD 설정 시:
[ ] poetry.lock을 Git에 커밋했는가?
[ ] 캐시 키에 poetry.lock 해시를 사용하는가?
[ ] --no-interaction 플래그를 사용하는가?
[ ] 비밀값(토큰 등)은 환경변수/시크릿으로 관리하는가?
Docker 설정 시:
[ ] 의존성 파일을 소스보다 먼저 COPY하는가? (레이어 캐시)
[ ] 프로덕션에서 dev 의존성을 제외하는가? (--only main)
[ ] Poetry 버전을 고정하는가? (ENV POETRY_VERSION=...)
[ ] 멀티스테이지 빌드로 이미지 크기를 줄이는가?
8 요약
| 환경 | 핵심 설정 |
|---|---|
| GitHub Actions | snok/install-poetry + actions/cache + poetry.lock 해시 키 |
| GitLab CI | POETRY_VIRTUALENVS_IN_PROJECT=true + cache.key.files |
| Docker (기본) | POETRY_VIRTUALENVS_CREATE=false + 레이어 캐시 |
| Docker (멀티스테이지) | builder에서 .venv 생성 → runtime에 복사 |
| Docker (export) | poetry export → pip install -r requirements.txt |