WIUNIX ACADEMY
انتشار blue/green با Docker Compose؛ از healthcheck تا برگشت مسیر
صفحهٔ 2 از 3؛ قبل از ادامه، مراحل قبلی و چیزهایی رو که لازم داری مرور کن.
آموزش متناسب با محیط تو
کجا اجرا میکنی؟
سیستمعامل و نسخهٔ سرورت رو انتخاب کن تا مراحل، دستورها و راهحلهای همون محیط رو ببینی.
آموزش متناسب با مقادیر تو
تنظیمات این آموزش
مقادیر نمونه رو با مشخصات سرورت عوض کن تا متن و دستورها با هم تغییر کنن. رمز، کلید خصوصی و توکن اینجا وارد نکن. مقدارها فقط توی همین زبانه میمونن و به سرور یا لینک اشتراکگذاری فرستاده نمیشن. قبل از اجرا، DNS، گواهیها و تنظیمات دسترسی شبکه رو روی سرورت بررسی کن.
اگر آیپی، دامنه یا پورتهای نمونه با سرورت فرق دارن، بخش تنظیمات پایین رو باز کن. مقدارها رو عوض کن و «اعمال در آموزش» رو بزن؛ بعد دستورهای تازه رو کپی کن.
تنظیم مقادیر برای محیط من5 مقدار قابلتغییر
قدم بعدی
با image مشخص، blue و پراکسی رو بالا بیاریم
digest ثبتشدهٔ manifest چندمعماری در ۲۰۲۶-۱۱-۰۵ از فرادادهٔ Docker Official Image بررسی شده: Nginx پایدار 1.30.6 روی Alpine. اسم stable-alpine برای شناخت کاناله؛ digest محتوا رو ثابت میکنه، حتی اگر بعداً tag جابهجا بشه. pull و بررسی digest کاریه که خواننده انجام میده، نه ادعای اجرای image روی همهٔ سیستمها و معماریها توسط نویسنده.
اول یک hard link از مسیر blue به active.conf میسازیم. کل پوشهٔ پراکسی mount میشه تا renameهای بعدی دیده بشن؛ bind کردن یک فایل تنها ممکنه inode قبلی رو نگه داره. هر دو فایل Compose رو اعتبارسنجی کن، کانتینر متوقف و شبکهٔ green رو بساز و بعد blue و پراکسی رو با شرط سلامت شروع کن. --wait فقط وضعیت running یا healthcheck تعریفشده رو میسنجه؛ نسخهای که از ورودی پاسخ میده رو جدا میبینیم.
ماشین آزمایشی لینوکس؛ همان نشست Bash مجاز
sudo ln -- '/srv/academy-bluegreen-demo/proxy/versions/blue.route' '/srv/academy-bluegreen-demo/proxy/active.conf' || exit 1
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' config --quiet || exit 1
docker_lab compose -p 'academybg-green' -f '/srv/academy-bluegreen-demo/green.yml' config --quiet || exit 1
docker_lab pull 'nginx:stable-alpine@sha256:0e52bd054126cdc040b1276c0af347aeb02a41b9cfe305d6094767ac30e97949' || exit 1
docker_lab image inspect 'nginx:stable-alpine@sha256:0e52bd054126cdc040b1276c0af347aeb02a41b9cfe305d6094767ac30e97949' --format '{{json .RepoDigests}}' || exit 1
docker_lab compose -p 'academybg-green' -f '/srv/academy-bluegreen-demo/green.yml' create || exit 1
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' up -d --wait --wait-timeout 45 || exit 1
marker=$(curl --noproxy '*' --fail --silent --show-error --max-time 3 'http://127.0.0.1:18080/release') || exit 1
test "$marker" = BLUE || exit 1
printf 'Gateway release: %s\n' "$marker"هر دو فایل معتبرن، green هنوز شروع نشده، شرط سلامت blue و پراکسی موفقه و ورودی BLUE برمیگردونه. خطا یعنی نمونهٔ نیمهتمام رو بررسی کن.
قدم بعدی
green رو شروع کنیم و از سمت پراکسی هم ببینیمش
blue و پراکسی رو روشن نگه دار. فقط پروژهٔ green رو شروع کن و برای healthcheck خودش صبر کن. بعد متن نسخه رو یک بار از پورت loopback خودش و یک بار از داخل کانتینر پراکسی و نام green-app بگیر. بررسی دوم، وصلنبودن شبکهٔ خارجی یا alias اشتباه رو پیدا میکنه؛ healthcheck محلی نمیتونه اینها رو ثابت کنه.
این درخواستهای کوچک فقط آمادگی HTTP همین نمونه رو میسنجن. اگر وابستگی بعداً خراب بشه، Nginx خودکار به blue برنمیگرده. healthcheck هم سازگاری migration، درستبودن نوشتن داده یا بیخطر بودن retry رو ثابت نمیکنه. فقط بهخاطر دیدن healthy، ترافیک واقعی رو جابهجا نکن.
ماشین آزمایشی لینوکس؛ همان نشست Bash مجاز
docker_lab compose -p 'academybg-green' -f '/srv/academy-bluegreen-demo/green.yml' up -d --wait --wait-timeout 45 || exit 1
marker=$(curl --noproxy '*' --fail --silent --show-error --max-time 3 'http://127.0.0.1:18082/release') || exit 1
test "$marker" = GREEN || exit 1
marker=$(docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' exec -T gateway wget -T 3 -q -O - http://green-app/release) || exit 1
test "$marker" = GREEN || exit 1green سالمه و هم مستقیم و هم از شبکهٔ پراکسی GREEN میده؛ blue برای برگشت همچنان موجوده.
قدم بعدی
مسیر green رو انتخاب کنیم، بسنجیم و reload بدیم
در این نمونهٔ اختصاصی، اپراتور دیگری همزمان فایلها رو ویرایش نمیکنه. یک hard link تازه و rename داخل همون پوشه، active.conf روی دیسک رو اتمی عوض میکنه و برچسب SELinux فایل بررسیشده حفظ میشه. انتخاب فایل هنوز به معنی تغییر پراکسیِ در حال اجرا نیست. قبل از درخواست reload، Nginx با -t تنظیم انتخابشده رو بررسی میکنه.
اگر اعتبارسنجی شکست بخوره، پنل مسیر blue رو روی دیسک برمیگردونه و بدون reload متوقف میشه. اگر بعد از اعتبارسنجی، فرمان reload خطا داد، هر دو نسخه رو روشن نگه دار و از بخش برگشت ادامه بده؛ ممکنه فایل دیسک و وضعیت اجرا متفاوت باشن. موفقشدن ارسال سیگنال هم هنوز نمیگه همهٔ درخواستها به green میرسن؛ بعدش درخواست تازه میفرستیم.
ماشین آزمایشی لینوکس؛ همان نشست Bash مجاز
sudo ln -- '/srv/academy-bluegreen-demo/proxy/versions/green.route' '/srv/academy-bluegreen-demo/proxy/active.conf.next' || exit 1
sudo mv -T -- '/srv/academy-bluegreen-demo/proxy/active.conf.next' '/srv/academy-bluegreen-demo/proxy/active.conf' || exit 1
if ! docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' exec -T gateway nginx -t; then
sudo ln -- '/srv/academy-bluegreen-demo/proxy/versions/blue.route' '/srv/academy-bluegreen-demo/proxy/active.conf.restore' || exit 1
sudo mv -T -- '/srv/academy-bluegreen-demo/proxy/active.conf.restore' '/srv/academy-bluegreen-demo/proxy/active.conf' || exit 1
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' exec -T gateway nginx -t
exit 1
fi
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' exec -T gateway nginx -s reload || exit 1انتخاب green معتبره و reload درخواست شده، یا بعد از شکست اعتبارسنجی، blue روی دیسک برگشته. موفقیت مسیر جدا بررسی میشه.
قدم بعدی
درخواست تازه رو ببین و نسخهٔ قبلی رو نگه دار
پنج درخواست جدا با Connection: close میفرستیم و فقط متن دقیق GREEN رو قبول میکنیم. پاسخ خطا یا رنگ قبلی، جابهجایی موفق حساب نمیشه. لاگ پراکسی و فایل انتخابشده رو ببین؛ اگر reload هنوز در حال انجامه، بعد از مشاهدهٔ محدود همین بررسیها رو تکرار کن، نه اینکه blue رو حذف کنی.
این پاسخها فقط همین پنج درخواست HTTP رو ثابت میکنن. اتصال keep-alive یا WebSocket قبلی و کار پسزمینه رو تخلیه نمیکنن. نسخهٔ قدیمی و قالب مسیر قبلی رو تا پایان مهلت برگشت و تخلیهٔ متناسب با برنامه نگه دار. این نمونه کار طولانی نداره و فرمان عمومیِ حذف نسخهٔ قبلی از محیط واقعی هم نمیده.
ماشین آزمایشی لینوکس؛ همان نشست Bash مجاز
for sample in 1 2 3 4 5; do
marker=$(curl --noproxy '*' --fail --silent --show-error --max-time 3 --header 'Connection: close' 'http://127.0.0.1:18080/release') || exit 1
printf 'sample=%s release=%s\n' "$sample" "$marker"
test "$marker" = GREEN || exit 1
sleep 1
done
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' logs --tail 30 gatewayپنج درخواست تازه از ورودی GREEN میگیرن؛ هر دو نسخه روشن و قالب برگشت موجوده.
قدم بعدی
با بررسی سلامت و مسیر، به blue برگردیم
این برگشتِ مسیر برای نمونهٔ بدون state است، نه برگشت داده. اول مطمئن شو خود blue هنوز مستقیم BLUE میده. قالب قبلی رو انتخاب کن، پراکسی رو اعتبارسنجی و reload کن و بعد از ورودی دوباره BLUE بخواه. اگر خود blue سالم نیست، توقف کن و علتش رو ببین؛ رفتن به نسخهٔ قبلیِ خراب، بازیابی نیست.
انتخاب با hard link اگر فایل .next از تلاش قبلی مونده باشه، روی اون نمینویسه. همون فایل مشخص رو بررسی و وضعیتش رو روشن کن، بعد دوباره تلاش کن. برای reload فقط پراکسی، پروژهٔ blue رو از نو نساز؛ up ممکنه کانتینرها رو هم جایگزین کنه یا هویت شبکه رو عوض کنه.
ماشین آزمایشی لینوکس؛ همان نشست Bash مجاز
marker=$(curl --noproxy '*' --fail --silent --show-error --max-time 3 'http://127.0.0.1:18081/release') || exit 1
test "$marker" = BLUE || exit 1
sudo ln -- '/srv/academy-bluegreen-demo/proxy/versions/blue.route' '/srv/academy-bluegreen-demo/proxy/active.conf.next' || exit 1
sudo mv -T -- '/srv/academy-bluegreen-demo/proxy/active.conf.next' '/srv/academy-bluegreen-demo/proxy/active.conf' || exit 1
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' exec -T gateway nginx -t || exit 1
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' exec -T gateway nginx -s reload || exit 1
for sample in 1 2 3; do
marker=$(curl --noproxy '*' --fail --silent --show-error --max-time 3 --header 'Connection: close' 'http://127.0.0.1:18080/release') || exit 1
test "$marker" = BLUE || exit 1
sleep 1
doneنسخهٔ قبلی مستقل پاسخ میده و بعد از reload بررسیشده، سه درخواست تازهٔ ورودی BLUE میگیرن.
بهجای اجبار جابهجایی، همون شرط شکستخورده رو بررسی کن
از بررسی فقطخواندنیِ متناسب استفاده کن. هنگام پیدا کردن علت، هر دو پروژه و فایلهاشون رو نگه دار. SELinux یا AppArmor رو خاموش نکن، backend فایروال Docker رو عوض نکن، شنوندهٔ موجود رو حذف نکن و پاکسازی سراسری اجرا نکن.
Compose پیدا نمیشه یا لانچر قدیمی انتخاب شده
بسته و افزونه رو از همون تابع مدیریتیِ محلی ببین. به فرمان قدیمی docker-compose برنگرد، daemon فعال رو عوض نکن و برای موفقشدن نمونه از context دوردست استفاده نکن.
docker_lab version
docker_lab compose version
docker_lab compose up --helpپراکسی به شبکهٔ green وصل نمیشه
قبل از شروع blue باید create پروژهٔ green موفق شده باشه. وضعیت همین پروژه و مالکیت شبکهٔ نامبرده رو ببین. شبکهٔ خارجیِ حدسی با نام شخص دیگری نساز و پراکسی رو به شبکهٔ میزبان وصل نکن.
docker_lab compose -p 'academybg-green' -f '/srv/academy-bluegreen-demo/green.yml' ps -a
docker_lab network inspect 'academybg-green_default'green ناسالم میمونه یا درخواست مستقیم شکست میخوره
کانتینر تازه، لاگ و پورت bindشده رو ببین. سلامت اینجا به متن فایل و دسترسی mountشده وابسته است. روی میزبان SELinux، برچسب همین پوشهٔ تازه و منع مرتبط رو با مسئولش بررسی کن؛ پوشهٔ برنامهٔ موجود رو دوباره برچسب نزن.
docker_lab compose -p 'academybg-green' -f '/srv/academy-bluegreen-demo/green.yml' ps -a
docker_lab compose -p 'academybg-green' -f '/srv/academy-bluegreen-demo/green.yml' logs --tail 40 green
sudo ls -ldZ '/srv/academy-bluegreen-demo/green'
ss -H -ltn '( sport = :18082 )'green سالمه ولی ورودی هنوز blue یا 502 میده
هم فایل روی دیسک و هم بررسی پراکسی رو ببین. endpoint محلیِ سالم نه رسیدن از شبکهٔ خارجی رو ثابت میکنه، نه DNS و نه بارگذاری مسیر تازه بعد از reload رو. blue رو حفظ کن و اگر جابهجایی قابلتأیید نیست، از برگشت صریح استفاده کن.
sudo sha256sum '/srv/academy-bluegreen-demo/proxy/active.conf' '/srv/academy-bluegreen-demo/proxy/versions/blue.route' '/srv/academy-bluegreen-demo/proxy/versions/green.route'
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' exec -T gateway nginx -t
docker_lab compose -p 'academybg-blue' -f '/srv/academy-bluegreen-demo/blue.yml' logs --tail 40 gateway