در دنیای توسعه پایتون، سفر از یک محیط محلی تا استقرار در تولید، پر از کابوسهای «روی ماشین من کار میکند» است. اگرچه اکوسیستم پایتون پیشرفتهای قابل توجهی داشته است، اما چالش پابرجا و اصلی همچنان حل وابستگیها و یکپارچگی فایل قفل (Lockfile) باقی مانده است. هنگام ساخت پایپلاینهای CI/CD، تکیه صرف بر فایل requirements.txt که توسط pip freeze تولید میشود، دستورالعملی برای فاجعه است. در این پست، بررسی میکنیم که چگونه با بهرهگیری از pip-tools و Poetry میتوان به ساختهای قطعی (Deterministic) دست یافت، تعارضهای فایل قفل را حل کرد و اطمینان حاصل کرد که محیط تولید شما دقیقاً به همان اندازه که محیط توسعه محلی شما قابل تکرار است، قابل تکرار باشد.
مشکل فایل قفل در CI/CD
مدیریت سنتی وابستگیها اغلب شامل دستور «freeze» است که وضعیت دقیق بستههای نصب شده را ثبت میکند. با این حال، این فایلها قابل تغییر هستند. اگر یک توسعهدهنده بستهای را به صورت محلی بهروزرسانی کند، فایل requirements.txt تغییر میکند که ممکن است باگهای ظریفی را به پایپلاین وارد کند. از نظر مهمتر، pip install فرآیند حل وابستگیها را به صورت پویا در حین نصب انجام میدهد. در یک محیط CI، این بدان معناست که کد یکسان میتواند بستههای باینری یا درختهای وابستگی متفاوتی را تولید کند اگر شرایط شبکه یا وضعیت مخازن بستهها بین ساختها کمی تغییر کند.
برای حل این مشکل، ما به جداسازی دغدغهها نیاز داریم: ابزاری برای نوشتن وابستگیها (محدودیتها) و ابزاری دیگر برای قفل کردن آنها. اینجاست که pip-tools و Poetry درخشش مییابند و به عنوان دروازهبانهایی عمل میکنند که اطمینان حاصل میکنند محیط استیجینگ شما دقیقاً با محیط تولید شما مطابقت دارد.
استراتژی الف: pip-tools برای رویکرد عملگرایانه
pip-tools یک راهحل سبکوزن است که به طور خاص برای جداسازی فایل ورودی از فایل قفل شده طراحی شده است. این ابزار از رویکردی اعلانی استفاده میکند که در آن شما وابستگیهای خود را در requirements.in (منبع قابل ویرایش) تعریف میکنید و آنها را به requirements.txt (فایل قفل غیرقابل تغییر) کامپایل میکنید. این اطمینان را ایجاد میکند که مرحله کامپایل قطعی است.
روند کار شامل اجرای pip-compile برای تولید فایل قفل است. این فایل هر وابستگی مستقیم و وابستگیهای وابسته (Transitive) را به یک نسخه خاص و هش (Checksum) قفل میکند. در پایپلاین CI/CD شما، فقط از این فایل قفل نصب میکنید و کاملاً موتور حل وابستگیها را دور میزنید.
# requirements.in
django>=4.2
psycopg2-binary==2.9.6
# اجرای کامپایل به صورت محلی برای تولید requirements.txt
pip-compile requirements.in
# در CI/CD، نصب دقیقاً از فایل قفل
pip-sync requirements.txt
دستور pip-sync به ویژه در پایپلاینهای تولید قدرتمند است. این دستور فقط نصب نمیکند، بلکه همگامسازی میکند. اگر محیط نصب شده حاوی بستهای باشد که در فایل قفل ذکر نشده است، آن را حذف میکند. این امر تضمین میکند که وضعیت محیطی پاکیزه هر بار که پایپلاین اجرا میشود، حفظ شود.
استراتژی ب: Poetry برای جریانهای کاری متمرکز بر پروژه
Poetry تجربهای مدرنتر و یکپارچهتر ارائه میدهد. این ابزار پروژه خود را به عنوان واحد توزیع در نظر میگیرد و هم وابستگیها و هم محیطهای مجازی را مدیریت میکند. فایل pyproject.toml در Poetry به عنوان منبع حقیقت عمل میکند که متادیتا، پیکربندی ساخت و تعاریف وابستگی را ترکیب میکند.
برخلاف pip-tools، Poetry وابستگیها را با استفاده از یک حلکننده وابستگی پیچیده حل میکند که تلاش میکند قبل از تولید فایل poetry.lock، تعارضهای نسخه را به حداقل برساند. این فایل قفل برای قابلیت اطمینان CI/CD به اندازه فایل قفل pip-tools حیاتی است.
# pyproject.toml
[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31.0"
django = "^4.2.5"
[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
در یک محیط CI، روند کار کمی تغییر میکند. به جای مراحل جداگانه کامپایل و نصب، Poetry مدیریت حل وابستگیها را بر عهده میگیرد. میتوانید پایپلاین را طوری پیکربندی کنید که فایل قفل را به صراحت نصب کند، اطمینان حاصل کنید که حتی اگر نسخه جدیدی از یک بسته امروز منتشر شود، CI شما آن را دریافت نمیکند مگر اینکه فایل قفل به صراحت بهروزرسانی شود.
# اسکریپت پایپلاین CI (Bash)
# نصب Poetry
curl -sSL https://install.python-poetry.org | python3 -
# اطمینان از استفاده از فایل قفل
poetry install --no-root --no-interaction
# بررسی یکپارچگی فایل قفل
poetry check
پل زدن به شکاف: مدیریت تعارضهای فایل قفل
با وجود نقاط قوت آنها، تعارضهای فایل قفل رخ میدهند. این معمولاً زمانی اتفاق میافتد که دو وابستگی به نسخههای ناسازگار از یک سومین وابستگی وابسته نیاز دارند. در دنیای واقعی، این اغلب به صورت خطای «عدم تطابق نسخه» در حین ساخت CI ظاهر میشود.
هنگام استفاده از pip-tools، میتوانید با افزودن محدودیتهای نسخه خاص به فایل requirements.in خود برای اجبار به نسخه سازگار، این مشکل را حل کنید و سپس مجدداً کامپایل نمایید. برای Poetry، باید از دستور poetry update --no-interaction package_name برای بهروزرسانی انتخابی یک وابستگی یا درخت آن، یا از پرچم poetry lock --no-update برای اطمینان از اینکه فایل قفل دقیقاً با pyproject.toml مطابقت دارد بدون اینکه تلاش شود نسخههای جدیدی حل شوند، استفاده کنید.
برای محیطهای تولید با ریسک بالا، بهترین روش این است که فایل قفل را به عنوان کد در نظر بگیرید. درخواستهای ادغام (Merge requests) نباید فقط فایل منبع (requirements.in یا pyproject.toml) را بهروزرسانی کنند، بلکه باید فایل قفل حاصل را نیز شامل شوند. این اطمینان را ایجاد میکند که تصمیم حل وابستگیها قبل از ادغام در شاخه اصلی، توسط همکاران بررسی شود.
نتیجهگیری
دستیابی به استقرار آماده برای تولید در پایتون، بیش از لیست کردن وابستگیها را میطلبد. این امر فرآیندی سختگیرانه را میخواهد که در آن حل وابستگیها از نصب جدا شده است. چه کنترل صریح و سبکوزن pip-tools را انتخاب کنید و چه مدیریت جامع پروژه Poetry را، هدف یکسان باقی میماند: ساختهای قطعی و قابل تکرار.
با یکپارچهسازی این ابزارها در پایپلاینهای CI/CD خود، بازی حدس و گمان حل وابستگیها را از بین میبرید. شما اطمینان حاصل میکنید که آنچه را تست میکنید، دقیقاً همان چیزی است که استقرار میدهید، که ساعتها زمان عیبیابی را ذخیره کرده و از اختلالات حیاتی ناشی از ارتقای نسخههای غیرمنتظره جلوگیری میکند. در دورانی که امنیت و پایداری زنجیره تأمین در اولویت است، مدیریت وابستگیها با فایلهای قفل یک انتخاب نیست، بلکه ضروری است.