«استقرار از Git» واقعاً یعنی چه
در بیشتر تاریخ این صنعت، استقرار یعنی کسی دنبالهای از کارها را دستی انجام میداد: build محلی، کپی فایلها روی سرور، اجرای یک migration، restart یک پروسه، و امید به اینکه چیزی جا نمانده باشد. هر مرحله فرصتی بود برای اینکه کمی متفاوت از دفعه قبل انجام شود — و فاصله میان «روی ماشین من کار میکند» و یک سایت خراب در محیط تولید معمولاً دقیقاً در همین مراحل زندگی میکرد.
استقرار با git این دنباله را با یک قاعده جایگزین میکند: branch منبع حقیقت است و هرچه روی آن باشد همان چیزی است که اجرا میشود. شما هیچ چیزی آپلود نمیکنید. push میکنید و پلتفرم هر بار دقیقاً همان بیلد را انجام میدهد. نکته اصلی تکرارپذیری است، نه راحتی.
بین push شما و اپلیکیشن زنده چه میگذرد
زنجیره کوتاه است و دانستنش ارزش دارد، چون وقتی چیزی خراب میشود میخواهید بدانید کدام حلقه را باید نگاه کنید.
push شما به مخزن میرسد و مخزن به ما اطلاع میدهد. ما بررسی میکنیم که آیا همان مخزن و همان branch به یک اپلیکیشن وصل است یا نه؛ اگر باشد، یک بیلد شروع میشود. بیلد در یک sandbox ایزوله اجرا میشود — کد شما هرگز یک پروسه را با کد کس دیگری به اشتراک نمیگذارد — و از روی Dockerfile شما یک image کانتینری تولید میکند. فقط وقتی image آماده شد، پلتفرم نسخه جدید را راه میاندازد و نسخه قدیمی را بازنشسته میکند. اگر بیلد شکست بخورد، هیچ چیز جایگزین نمیشود: نسخه قبلی همچنان به ترافیک سرویس میدهد، و این همان رفتاری است که ساعت 2 بامداد میخواهید.
دسترسی از روی طراحی کوتاهعمر است: اعتبارنامهای که برای خواندن مخزن شما استفاده میشود بهجای اینکه ذخیره شود، در زمان استقرار ساخته میشود، بنابراین توکنی که در دیتابیس ما نشسته باشد نمیتواند بیشتر از عمر مفیدش باقی بماند.
مخزن شما به چه چیزی نیاز دارد
عمدتاً به یک چیز: یک **Dockerfile**. این همان دستورالعملی است که کد شما را به یک image قابل اجرا تبدیل میکند — image پایه، وابستگیها، مرحله build و دستور اجرا. اگر پروژه شما هنوز چنین فایلی ندارد، نوشتنش یک کار یکباره است و همان فایل روی لپتاپ شما هم کار میکند.
دو جزئیات بیشترین وقت را برای آدمها ذخیره میکند. اول، اپلیکیشن شما باید روی پورتی که به پلتفرم اعلام کردهاید گوش بدهد و روی همه اینترفیسها (`0.0.0.0`) و نه فقط روی `localhost` — کانتینری که به localhost bind میشود از بیرون خودش قابل دسترسی نیست. دوم، هر چیز محرمانه (آدرس دیتابیس، کلیدهای API) جایش در متغیرهای محیطی است، نه داخل image: imageها دوباره ساخته و جابهجا میشوند، و رازی که داخل یک image پخته شده باشد رازی است که نمیتوانید بچرخانیدش.
یک پروژه چندسرویسی از راه یک فایل Compose به همین شکل کار میکند — هر سرویسی که image از پیش ساختهشده ندارد به یک Dockerfile قابل build نیاز دارد، و کل stack بههممتصل بالا میآید.
branchها: محیط تولید را از کار روزمره دور نگه دارید
اینجا جایی است که تیمها آسیب میبینند، و راهحل یک تصمیم است نه یک قابلیت. اگر محیط تولید به branchی وصل باشد که رویش توسعه میدهید، هر commit نیمهتمام منتشر میشود. محیط تولید را به branchی وصل کنید که فقط وقتی واقعاً قصد دارید در آن merge میکنید — معمولاً `main` در حالی که کار روزمره روی branchهای feature انجام میشود، یا یک branch اختصاصی `production` اگر `main` جایی است که رویش تکرار میکنید.
آزمون ذهنی مفید: «اگر همین الان push کنم، از اینکه بازدیدکنندهها آن را ببینند راحتم؟» اگر برای branch وصلشده پاسخ حتی یک بار «نه» باشد، branch اشتباه است، نه فرایند.
یک جریان انتشار که محیط تولید را کسلکننده نگه میدارد
# gundelik is: feature dalinda
git checkout -b feature/yeni-fiyatlandirma
git commit -am "pricing page"
git push origin feature/yeni-fiyatlandirma # deploy TETIKLEMEZ
# yayina hazir oldugunda
git checkout main
git merge feature/yeni-fiyatlandirma
git push origin main # deploy BU push ile baslar
وقتی یک push دیده نمیشود
استقرار تا وقتی که بیصدا هیچ کاری نکند شبیه جادو به نظر میرسد، پس به همان ترتیبی که زنجیره اجرا میشود عیبیابی کنید.
از انتها شروع کنید: اصلاً بیلدی شروع شد؟ اگر برای push شما هیچ بیلدی ظاهر نشد، حلقهای که شکسته اتصال است — مخزن یا branch همانی نیست که وصل شده، یا یکپارچگی دسترسیاش را از دست داده است (یک نصب لغوشده، مخزنی که تغییر نام داده یا منتقل شده). اگر بیلد شروع شد و شکست خورد، لاگ بیلد دقیقاً میگوید کجا؛ رایجترین دلایل یک مرحله در Dockerfile است که بهخاطر فایلی که `.dockerignore` شما کنارش میگذارد فقط بهصورت محلی کار میکند، یا نصب یک وابستگی که به اعتبارنامهای نیاز دارد که بیلد آن را ندارد. اگر بیلد موفق بود اما هنوز نسخه قدیمی را میبینید، تقریباً بهطور قطع دارید به یک پاسخ کششده نگاه میکنید نه به اپلیکیشن قدیمی — پیش از آنکه به استقرار شک کنید، صفحه را با یک cache-buster درخواست کنید یا هدر وضعیت کش را بررسی کنید.
یک حالت غیربدیهی که دانستنش میارزد: اجرای دوباره یک استقرار برای commitی که پیشتر شکست خورده، بهخودیخود آن را درست نمیکند. commit ورودی است؛ اگر ورودی تغییر نکرده باشد، نتیجه هم تغییر نمیکند. بهجای تلاش دوباره روی همان commit، یک اصلاح push کنید — حتی یک commit خالی.
بررسی وضعیت و اجبار یک استقرار از ترمینال
# calisan uygulamanin durumu
cdnctl container apps list --account <uuid>
# son deploy ne yapti
cdnctl container apps logs --account <uuid> --app <app_uuid>
# elle yeniden dagit (ayni commit)
cdnctl container apps deploy --account <uuid> --app <app_uuid>
وقتی کسلکننده شد، چه چیزی به دست میآورید
دستاورد واقعی استقرار با git سرعت نیست، این است که استقرار دیگر یک رویداد نیست. وقتی انتشار برابر یک push است، تغییرهای کوچک بهتنهایی بیرون میروند بهجای اینکه در یک انتشار ماهانه پرریسک روی هم انباشته شوند — و تغییرهای کوچک همانهایی هستند که میتوانید عیبیابیشان کنید، چون وقتی چیزی خراب میشود دقیقاً میدانید کدام commit مسبب بوده است.
همچنین بازگشت به عقب را از یک وضعیت اضطراری به یک عملیات عادی تبدیل میکند: image قبلی هنوز آنجاست و برگشتن هم مثل هر استقرار دیگری است. تیمهایی که روزانه منتشر میکنند شجاعتر از تیمهایی که ماهانه منتشر میکنند نیستند؛ آنها هر استقرار را آنقدر کوچک کردهاند که دیگر جالب توجه نباشد.
پرسشهای پرتکرار
آیا به Dockerfile نیاز دارم یا پلتفرم میتواند حدس بزند اپلیکیشنم را چطور build کند؟
به یک Dockerfile نیاز دارید. ما بیلد را برای شما حدس نمیزنیم — این فایل درباره image پایه، وابستگیها و دستور اجرا صریح است، و دقیقاً به همین دلیل بیلد بازتولیدپذیر است. همان فایل روی ماشین خود شما هم بهشکل یکسان build میشود.
در حالی که نسخه جدید build میشود، چه بر سر اپلیکیشن در حال اجرا میآید؟
همچنان سرویس میدهد. نسخه جدید فقط پس از اینکه image با موفقیت ساخته شد جایگزین نسخه قدیمی میشود؛ یک بیلد ناموفق محیط تولید را دقیقاً همانطور که بود باقی میگذارد.
میتوانم بدون push استقرار کنم — مثلاً برای اجرای دوباره آخرین نسخه؟
بله. یک استقرار را میتوان بهصورت دستی از پنل یا با cdnctl و با همان commit راهاندازی کرد. این کار پس از تغییر یک متغیر محیطی مفید است، چون تغییر متغیر commit جدیدی نمیسازد.
چطور رازها را بیرون از مخزن نگه دارم؟
آنها را در متغیرهای محیطی روی اپلیکیشن بگذارید، نه در Dockerfile و نه در کد. هر چیزی که داخل یک image پخته شود با همان image سفر میکند و بدون build دوباره قابل چرخاندن نیست.
push کردم اما هیچ اتفاقی نیفتاد. اول کجا را نگاه کنم؟
بررسی کنید اصلاً بیلدی شروع شده یا نه. نبودن بیلد یعنی مشکل اتصال (branch اشتباه، دسترسی لغوشده، مخزن تغییرنامداده). بیلد ناموفق شما را به لاگ بیلد ارجاع میدهد. بیلد موفق همراه با سایتی که قدیمی به نظر میرسد معمولاً یعنی دارید یک پاسخ کششده را میبینید.