یکی از چالشهای پایدار در مهندسی نرمافزار مدرن، سندرم «روی ماشین من کار میکند» است. با پیچیدهتر شدن پروژههای پایتون، مدیریت وابستگیها بین محیطهای توسعه محلی و پایپلاینهای یکپارچهسازی و استقرار مداوم (CI/CD) به شدت حیاتی میشود. محیطهای ناسازگار منجر به تستهای ناپایدار، شکست در استقرار و اتلاف ساعتهای مهندسی میشوند.
در این مقاله، بررسی میکنیم که چگونه میتوان Python Poetry را برای مدیریت وابستگیها با Docker برای جداسازی محیط ترکیب کرد. با بهرهگیری از این ابزارها در کنار هم، میتوانیم یک جریان کاری قدرتمند ایجاد کنیم که تضمین میکند محیط توسعه محلی شما دقیقاً مراحل تولید و CI/CD را بازآفرینی میکند.
مشکل مدیریت وابستگیهای استاندارد
به طور سنتی، توسعهدهندگان از requirements.txt یا pip برای مدیریت بستهها استفاده میکنند. اگرچه این روش ساده است، اما اغلب وابستگیهای سطح سیستم (مانند کامپایلرهای C یا کتابخانههای خاص) و رفتارهای خاص سیستمعامل را نادیده میگیرد. Poetry با استفاده از فایل pyproject.toml و یک فایل قفل (poetry.lock) مشکل حل وابستگی را حل میکند، اما همچنان روی سیستمعامل میزبان اجرا میشود. اگر رانر CI/CD شما از Ubuntu 22.04 استفاده میکند اما شما روی macOS توسعه میدهید، تفاوتهای ظریف در وابستگیهای باینری یا نسخههای کتابخانه میتواند باعث بروز مشکلات شود.
برای جداسازی واقعی محیطها، به کانتینرسازی نیاز داریم. Docker لایهای انتزاعی ارائه میدهد که سیستمعامل، کتابخانهها و کد برنامه را در بر میگیرد و سازگاری را صرفنظر از ماشین میزبان زیرین تضمین میکند.
ساختار پروژه و پیکربندی
بیایید با تنظیم ساختار استاندارد پروژه پایتون با استفاده از Poetry شروع کنیم. ابتدا پروژه خود را مقداردهی اولیه کنید:
poetry new my-reproducible-app
cd my-reproducible-app
وابستگیهای پروژه خود را اضافه کنید. برای این مثال، فرض میکنیم به requests و pytest نیاز داریم:
poetry add requests
poetry add --group dev pytest
از نظر حیاتی، Poetry یک فایل poetry.lock ایجاد میکند. این فایل هر نسخه خاص از هر وابستگی را قفل میکند و تضمین میکند که هر کسی که مخزن را کلون میکند، دقیقاً همان نسخههای بسته را دریافت میکند.
ساخت محیط Docker
اکنون، بیایید یک Dockerfile ایجاد کنیم که از فایل قفل تولید شده توسط Poetry استفاده کند. نکته کلیدی این است که از نصب وابستگیها در هر بیلد خودداری کنیم. ما از بیلدهای چندمرحلهای یا کش لایهای دقیق استفاده میکنیم تا بیلدها سریع باقی بمانند.
در اینجا یک Dockerfile بهینهشده برای توسعه آورده شده است:
FROM python:3.11-slim AS base
WORKDIR /app
# Install Poetry inside the container
RUN pip install --no-cache-dir poetry
# Copy only the lockfile first to leverage Docker layer caching
COPY pyproject.toml poetry.lock ./
# Install dependencies into a virtual environment
RUN poetry config virtualenvs.in-project true \
&& poetry install --no-interaction --no-ansi
# Copy the rest of the application code
COPY . .
# Command to run the application or tests
CMD ["poetry", "run", "python", "-m", "my_app"]
استفاده از poetry install بدون پرچم --no-dev را مشاهده کنید. برای توسعه محلی، میخواهیم تمام وابستگیهای توسعه (مانند لاینترها و اجراکنندههای تست) در دسترس باشند. با این حال، برای CI/CD، این مورد را کمی تغییر خواهیم داد.
جداسازی وابستگیهای CI/CD
پایپلاینهای CI/CD نیازمندیهای متفاوتی نسبت به توسعه محلی دارند. شما معمولاً نمیخواهید پیامهای تعاملی داشته باشید و ممکن است در کانتینر نهایی به پلاگینهای IDE یا ابزارهای لاینتینگ محلی نیاز نداشته باشید. ما میتوانیم این مورد را با ارسال آرگومانهای بیلد یا استفاده از سرویسهای Docker Compose جداگانه مدیریت کنیم.
برای مرحلهای شبیه به تولید در پایپلاین CI/CD شما (مثلاً GitHub Actions یا GitLab CI)، میتوانید از یک بیلد چندمرحلهای برای حذف وابستگیهای توسعه غیرضروری استفاده کنید:
FROM python:3.11-slim AS builder
WORKDIR /app
COPY pyproject.toml poetry.lock ./
RUN pip install --no-cache-dir poetry \
&& poetry config virtualenvs.in-project true \
&& poetry install --no-dev --no-interaction --no-ansi
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /app/.venv .venv
COPY --from=builder /app /app
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "my_app"]
این رویکرد تضمین میکند که تصویر نهایی که در تولید یا تست یکپارچهسازی اجرا میشود، سبک است و تنها شامل وابستگیهای زمان اجرا میشود که سطح حمله و اندازه تصویر را کاهش میدهد.
جریان کاری عملی برای توسعهدهندگان
برای روانتر کردن این جریان کاری، ترمینال محلی خود را پیکربندی کنید تا محیط مجازی Poetry به طور خودکار استفاده شود. وقتی poetry shell را اجرا میکنید، محیط را در داخل پروژه فعال میکند. ترکیب شده با Docker، میتوانید تستهای محلی خود را در داخل کانتینر اجرا کنید تا از برابری اطمینان حاصل کنید:
docker-compose run --rm app poetry run pytest
این دستور کانتینر تعریف شده در پیکربندی Docker Compose شما را راهاندازی میکند، تستها را اجرا میکند و سپس کانتینر را حذف میکند. این تضمین میکند که نتایج تست شما تحت تأثیر بستههای نصب شده به صورت سراسری روی ماشین شما قرار نمیگیرند.
نتیجهگیری
با یکپارچهسازی Poetry برای حل دقیق وابستگیها با Docker برای جداسازی محیطی، توسعهدهندگان میتوانند اصطکاک بین محیطهای محلی و CI/CD را حذف کنند. این تنظیم نه تنها قابلیت اطمینان پایپلاینهای CI/CD شما را بهبود میبخشد، بلکه فرآیند آنبوردینگ (Onboarding) برای اعضای جدید تیم را نیز ساده میکند. دیگر نیازی به عیبیابی باگهای خاص محیط نیست—فقط اجرای کد تمیز و تکرارپذیر.
پذیرش این الگو گام بزرگی به سمت عملیاتهای DevOps بالغ است. از امروز با کانتینرسازی محیط توسعه خود شروع کنید و شاهد افزایش اعتماد به استقرار خود باشید.