آنچه در این مقاله میخوانید [پنهانسازی]
Blue-Green Deployment یعنی نگه داشتن دو نسخه زنده از اپلیکیشن (Blue و Green) و هدایت ترافیک بین آنها تا انتشار بدون قطعی انجام شود. نسخه جدید روی محیط Green بالا میآید، کاملا تست میشود و سپس با یک تغییر در Load Balancer یا Router، ترافیک در چند ثانیه به Green منتقل میشود. اگر مشکلی دیدید، با همان سرعت به Blue برمیگردید.
Blue-Green Deployment دقیقا چیست و چه مشکلی را حل میکند؟
در این الگو دو محیط کاملا مشابه دارید: Blue (در حال سرویسدهی) و Green (نسخه جدید). انتشار به جای جایگزینی در همان سرورها، با روشن کردن محیط دوم و سوئیچ ترافیک انجام میشود. نتیجه: بدون قطعی، بدون انتظار برای راهاندازی مجدد، و با یک رولبک سریع در صورت بروز مشکل.
این روش برای سرویسهای حساس به قطعی، تیمهایی که میخواهند ریسک انتشار را کم کنند، و محصولاتی که نیاز به تایید کامل قبل از بازدید کاربران دارند مناسب است.
اجزای کلیدی و نحوه کار
- دو محیط همسان: پیکربندی، نسخه سیستمعامل/تصویر کانتینر، وابستگیها و متغیرهای محیطی باید تا حد ممکن یکسان باشد.
- Load Balancer/Router: تنها نقطهای که ترافیک را به Blue یا Green هدایت میکند. سوئیچ باید اتمیک و سریع باشد.
- Health Check و Readiness: تا زمانی که Green سالم و آماده نیست، ترافیک نباید به آن برسد.
- Observability: مانیتورینگ، لاگ و ترِیس برای تایید سلامت و آماده بودن برای رولبک.
چه زمانی Blue-Green انتخاب مناسبی است؟
- نیاز به انتشار بدون قطعی و رولبک فوری دارید.
- میخواهید نسخه جدید را با داده واقعی، اما بدون ترافیک کاربر، بررسی کنید.
- بودجه/منابع اجرای دو محیط همزمان را دارید (حداقل در لحظه انتشار).
- وابستگیهای حالتدار (مانند دیتابیس یا صف) را میتوانید سازگار یا مشترک مدیریت کنید.
اگر هزینه حفظ دو محیط برایتان بالاست، یا مهاجرت دیتابیس ناسازگار است، شاید Rolling یا Canary مناسبتر باشد (مقایسه در ادامه آمده است).
مراحل اجرا (چک لیست عملی)
- همسانسازی محیطها: زیرساخت، نسخهها، متغیرهای محیطی و Secrets را یکسان کنید تا environment drift رخ ندهد.
- بالا آوردن Green: نسخه جدید را روی Green مستقر کنید؛ Readiness/Health check الزامی است.
- تست قبل از سوئیچ: smoke test، تست API و سنجش معیارهای سلامت (خطا، تاخیر، مصرف منابع).
- گرم کردن Green: پر کردن کش، اجرای Migrationهای غیرمسدودکننده، Pre-warm کردن کانکشنها.
- سوئیچ ترافیک: تنظیم Load Balancer به سمت Green؛ ترجیحا اتمیک و قابل اسکریپت شدن.
- پایش پس از سوئیچ: چند دقیقه تا چند ساعت، با معیار از پیش تعریفشده (SLO)، سلامت را پایش کنید.
- رولبک در صورت نیاز: با همان مکانیزم سوئیچ، به Blue برگردید؛ تغییرات ناسازگار را معکوس نکنید مگر با برنامه.
- پاکسازی: پس از اطمینان، Blue را آزاد یا برای انتشار بعدی بهروزرسانی کنید.
مثال عملی با Kubernetes (Service selector)
هدف: یک سرویس وب را با دو Deployment (blue/green) اجرا کنیم و با تغییر selector سرویس، ترافیک را بدون قطعی جابهجا کنیم.
پیشنیاز: خوشه Kubernetes، دسترسی kubectl، و یک Load Balancer/Ingress برای سرویس.
Deployment ها
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-blue
namespace: app
labels:
app: web
version: blue
spec:
replicas: 3
selector:
matchLabels:
app: web
version: blue
template:
metadata:
labels:
app: web
version: blue
spec:
containers:
- name: web
image: nginx:stable
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 5
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-green
namespace: app
labels:
app: web
version: green
spec:
replicas: 3
selector:
matchLabels:
app: web
version: green
template:
metadata:
labels:
app: web
version: green
spec:
containers:
- name: web
image: nginx:stable
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 5
Service با selector قابل سوئیچ
apiVersion: v1
kind: Service
metadata:
name: web
namespace: app
spec:
selector:
app: web
version: blue # ابتدا به Blue متصل است
ports:
- port: 80
targetPort: 80
type: ClusterIP
سوئیچ ترافیک به Green
# اطمینان از آماده بودن پادهای Green
kubectl -n app rollout status deploy/web-green
# بررسی Endpointهای فعلی سرویس
kubectl -n app get endpoints web -o wide
# سوئیچ اتمیک selector سرویس به Green
kubectl -n app patch service web -p '{"spec":{"selector":{"app":"web","version":"green"}}}'
# تایید اینکه Endpointها به پادهای Green اشاره میکنند
kubectl -n app get endpoints web -o wide
روش بررسی نتیجه: با همان آدرس Ingress/Load Balancer درخواست بدهید و در مانیتورینگ نرخ خطا، تاخیر و لاگها را ببینید. برای رولبک همین فرمان patch را با version: blue اجرا کنید.
سوئیچ با Nginx/Load Balancer (نمونه مینیمال)
در سناریوهای غیرکانتینری یا خارج از K8s، میتوانید دو بالاکننده جدا داشته باشید و با reload سریع Nginx سوئیچ کنید.
upstream app_blue {
server 10.0.1.10:80;
server 10.0.1.11:80;
}
upstream app_green {
server 10.0.2.10:80;
server 10.0.2.11:80;
}
server {
listen 80;
# مقصد پیشفرض: Blue
set $pool app_blue;
location / {
proxy_pass http://$pool;
proxy_set_header Host $host;
}
}
برای سوئیچ، مقدار متغیر $pool را به app_green تغییر دهید و Nginx را بدون قطعی reload کنید:
sudo nginx -t && sudo nginx -s reloadنکته: این فقط الگوی ساده است؛ در عمل بهتر است با فایل جداگانه یا اتوماسیون CI/CD مقدار را کنترل کنید تا خطای انسانی کم شود.
مدیریت دیتابیس و مهاجرت بدون قطعی
چالش اصلی Blue-Green دیتابیس است؛ چون معمولا یک نمونه مشترک بین Blue و Green دارید. راهحل پایدار، الگوی expand-and-contract است:
- گسترش (Backward-compatible): ستون/ایندکس جدید را اضافه کنید یا API را طوری تغییر دهید که نسخه قدیم و جدید هر دو کار کنند. هیچ فیلدی را هنوز حذف یا محدود نکنید.
- استقرار Green: کد جدید را طوری بنویسید که با هر دو طرح داده سازگار باشد. در صورت نیاز از dual-write (نوشتن در دو فیلد/جدول) استفاده کنید.
- مهاجرت داده در پسزمینه: داده قدیمی را به ساختار جدید منتقل کنید؛ سرعت مهاجرت را با مانیتورینگ بار دیتابیس کنترل کنید.
- انقباض: پس از اینکه فقط نسخه جدید فعال شد و پایدار ماند، فیلدها/مسیرهای قدیمی را حذف کنید.
نکات حیاتی:
- قفلهای طولانیمدت یا مهاجرتهای مسدودکننده را در ساعات کمترافیک اجرا نکنید.
- برای نشست کاربر از ذخیرهساز مشترک مثل Redis استفاده کنید تا با سوئیچ جلسهها از بین نروند.
- Queue/Jobها را هماهنگ کنید: اگر Worker نسخه قدیم دارید، فرمت پیام را سازگار نگه دارید یا Workers را Blue/Green جدا کنید.
خطاهای رایج و چطور پیشگیری کنیم
- عدم تطابق محیطها (Environment Drift): تمام تغییرات پیکربندی را کدنویسی کنید (IaC) و روی هر دو محیط اعمال کنید.
- Health check ناکافی: فقط بررسی پورتی که باز است کافی نیست؛ readiness باید وابستگیها (DB/Cache) را نیز بسنجد.
- وابستگیهای حالتدار: نشست داخل حافظه اپلیکیشن باعث از دست رفتن ورود کاربر میشود؛ از Session Store مشترک استفاده کنید.
- گرم نکردن Green: نبود کش یا JIT گرم میتواند تاخیر اولیه را زیاد کند؛ پیش از سوئیچ، ترافیک مصنوعی بدهید.
- مهاجرت ناسازگار DB: حذف فیلد قدیمی قبل از سوئیچ باعث خطای نسخه Blue میشود؛ حتما الگوی expand-and-contract را رعایت کنید.
- نبود مسیر روشن رولبک: از همان مکانیزمی که سوئیچ را انجام میدهد برای بازگشت فوری استفاده کنید؛ تست رولبک را قبل از انتشار تمرین کنید.
مقایسه کوتاه با Rolling Update و Canary
| روش | نحوه انتشار | ریسک | هزینه زیرساخت | کنترل تدریجی ترافیک |
|---|---|---|---|---|
| Blue-Green | دو محیط کامل؛ سوئیچ اتمیک | کم (رولبک سریع) | بیشتر (دو محیط همزمان) | معمولا یکمرحلهای؛ قابل ترکیب با Canary |
| Rolling | جایگزینی تدریجی Pods/سرورها | متوسط (نسخهها همزمان فعال) | کمتر | تدریجی، اما با نسخههای مخلوط |
| Canary | ارسال درصدی ترافیک به نسخه جدید | کم تا متوسط (کنترل دقیق) | متوسط | بسیار خوب (پلهای/خودکار) |
بررسی نتیجه و رولبک سریع
- پیش از سوئیچ، معیارهای قبولی مشخص کنید: نرخ خطای 5xx، تاخیر P95، نرخ تایید تراکنش.
- پس از سوئیچ، این معیارها را در بازه زمانی تعریفشده پایش کنید. در صورت عبور از آستانه، بلافاصله به Blue برگردید.
- برای رولبک، همان دستور/مکانیزم سوئیچ را برعکس اجرا کنید (مثلا تغییر selector سرویس یا reload پیکربندی LB).
گام بعدی چیست؟
از یک سرویس کوچک و نسبتا Stateless شروع کنید: Health check استاندارد اضافه کنید، ذخیرهساز نشست مشترک پیادهسازی کنید، و در CI/CD مرحله ساخت محیط Green، اجرای تستهای دود، سوئیچ و رولبک را اسکریپت کنید. پس از چند چرخه موفق، این الگو را به سرویسهای حیاتیتر گسترش دهید.







