رفتن به محتوا
→ همه‌ی بخش‌ها

به‌روزرسانی امن و برگشت خودکار

هر تغییری که به یک سرور می‌رسد — ارسال کانفیگ، باینری تانل، ایمیج ایجنت نود — قبل از جایگزین شدن با نسخه‌ی در حال اجرا بررسی می‌شود، و آخرین نسخه‌ای که کار کرده نگه داشته می‌شود تا خودکار برگردد. یک تغییر خراب حداکثر چند ثانیه‌ی یک ری‌استارت هزینه دارد، نه نودی که از کار افتاده بماند. وقتی آپدیتی تمام شود، یک گزارش کوتاه به تلگرام می‌رود.

چه چیزی بررسی قبل از اعمال نسخه‌ی نگه‌داشته برای برگشت چه وقت برمی‌گردد
کانفیگ Xray (و Xray مخصوص WireGuard) xray run -test روی فایل جدید <config>.good Xray ردش کند، یا چند لحظه بعد از شروع از کار بیفتد
کانفیگ Hysteria2 — (حالت تست ندارد) <config>.good سرور چند لحظه بعد از شروع از کار بیفتد
کانفیگ strongSwan swanctl --load-all swanctl.conf قبلی swanctl ردش کند
کانفیگ xl2tpd / pptpd — فایل‌های قبلی سرویس بلافاصله بعد از ری‌استارت از کار بیفتد
باینری تانل -version و -check با کانفیگ فعلی، SHA-256 tifusi-tunnel.prev سرویس بالا نماند یا لینک‌های فعال برنگردند
ایمیج ایجنت نود تست در یک کانتینر موقت tifusi-node-agent:rollback ایجنت جواب ندهد، سرویسی که سالم بود بعدش سالم نباشد، یا نود در دوره‌ی زیر نظر گرفتن قطع شود

پنل هر بار که کاربرها یا هسته‌ها تغییر کنند کانفیگ نود را می‌فرستد. ایجنت نود (backend/node_agent/safe_apply.py) هر کدام را در سه قدم اعمال می‌کند:

  1. اول اعتبارسنجی. کانفیگ جدید Xray در یک فایل کناری نوشته و با xray run -test بررسی می‌شود؛ این دستور کانفیگ را می‌خواند و می‌سازد ولی هیچ پورتی نمی‌گیرد، پس کنار Xray در حال اجرا بی‌خطر است. کانفیگی که Xray نتواند بخواند رد می‌شود و پروسه‌ی در حال اجرا اصلاً دست نمی‌خورد.
  2. نوشتن اتمیک. کانفیگ در یک فایل موقت نوشته و با rename جایگزین می‌شود، پس نوشتن نیمه‌کاره هیچ‌وقت فایل نصفه برای شروع بعدی جا نمی‌گذارد.
  3. نگه‌داشتن آخرین نسخه‌ی سالم. وقتی سرویسی روی یک کانفیگ بالا ماند، آن کانفیگ در <file>.good کپی می‌شود. اگر سرویس ظرف حدود ۱.۵ ثانیه بعد از شروع روی کانفیگ جدید از کار بیفتد، نسخه‌ی سالم برمی‌گردد و سرویس دوباره با آن بالا می‌آید.

کانفیگی که یک بار کرش کرده در ارسال بعدی دوباره امتحان نمی‌شود (پنل با هر تغییر کاربر کانفیگ می‌فرستد و تلاش دوباره کاربرها را پشت سر هم قطع می‌کرد)؛ تا وقتی عوض نشود رد می‌شود. ایجنت موقع بالا آمدن هم اگر کانفیگ فعلی بالا نیاید، با آخرین کانفیگ سالم اجرا می‌شود.

رد شدن یک کانفیگ با HTTP 422 به پنل برمی‌گردد: کدام سرویس، دلیل، و اینکه کانفیگ قبلی هنوز در حال سرویس‌دهی است یا نه. پنل آن را روی صفحه‌ی نود نشان می‌دهد — مثلاً xray rejected the new config (previous config still running): … unknown config id: … — و نودی را که هنوز به کاربرها سرویس می‌دهد قطع نشان نمی‌دهد.

هسته‌ای که inbound، پورت Hysteria2 یا پورت WireGuard آن روی پورتی باشد که چیزی روی نود از قبل گرفته، ذخیره نمی‌شود:

پورت استفاده
پورت ایجنت هر نود (پیش‌فرض 62050) ایجنت نود
22 SSH
10085 API آمار Xray (loopback)
10087 API آمار WireGuard (loopback)
9998 API آمار Hysteria2 (loopback)

همه‌ی شکل‌های پورت در Xray بررسی می‌شوند: 443، "443"، بازه مثل 62000-62100 و لیست مثل 80,443. پورت ایجنت هر نود هم با هسته‌هایی که آن نود اجرا می‌کند چک می‌شود. بدون این بررسی، inboundی روی پورت ایجنت موقع شروع کانتینر زودتر پورت را می‌گرفت و ایجنت اصلاً بالا نمی‌آمد.

شیت SSH تانل برای هر سمت یک دکمه‌ی 🔄 آپدیت تانل دارد (تانل‌ها). جدیدترین باینری با بررسی SHA-256 به سرور می‌رسد — یا خود سرور از release دانلودش می‌کند، یا اگر به گیت‌هاب دسترسی نداشته باشد پنل با SFTP می‌فرستد. جابه‌جایی بعد روی خود سرور انجام می‌شود، پس قطع شدن SSH هیچ‌وقت کار را نصفه نمی‌گذارد:

  1. باینری جدید باید روی همان ماشین اجرا شود (-version) و کانفیگ فعلی تانل را قبول کند (-check)؛ وگرنه هیچ چیز تغییر نمی‌کند؛
  2. باینری فعلی با نام tifusi-tunnel.prev نگه داشته می‌شود، باینری جدید اتمیک جایگزین و سرویس ری‌استارت می‌شود؛
  3. سرویس باید فعال بماند، و اگر تانل قبلاً لینک فعال داشت، ظرف ۴۵ ثانیه لینک‌ها برگردند (از endpoint وضعیت loopback خوانده می‌شود)؛
  4. وگرنه tifusi-tunnel.prev برمی‌گردد و سرویس با آن ری‌استارت می‌شود.

سمتی که از قبل جدیدترین باینری را دارد ری‌استارت نمی‌شود. کانفیگ تانل در آپدیت هیچ‌وقت تغییر نمی‌کند. هر آپدیت با تست سلامت تانل تمام می‌شود.

آپدیت ایجنت نودها: آپدیت تدریجی Canary

Section titled “آپدیت ایجنت نودها: آپدیت تدریجی Canary”

شیت SSH هر نود تب آپدیت را برای یک نود دارد و صفحه‌ی نودها 🔄 آپدیت تدریجی نودها را برای چند نود. هر دو دو لایه دارند:

روی خود نود (اسکریپتی که با SSH اجرا می‌شود):

  1. گرفتن ایمیج جدید: docker pull از ghcr.io/javadtifusi-eng/tifusi-node-agent:<tag>، یا ایمیج داخل بسته‌ی آفلاین پنل که با SFTP فرستاده می‌شود. پنل اول شناسه‌ی ایمیج را از داخل فایل می‌خواند و اگر نود همان ایمیج را اجرا کند، اصلاً آپلود نمی‌کند.
  2. تست آن در یک کانتینر موقت: Xray اجرا شود و کد ایجنت بدون خطا import شود.
  3. تگ زدن ایمیج فعلی به‌عنوان tifusi-node-agent:rollback.
  4. ساخت دوباره‌ی کانتینر tifusi-node دقیقاً مثل install-node.sh و tifusi node update، با همان کلید API و پورت.
  5. حداکثر ۶۰ ثانیه صبر تا ایجنت به /health جواب بدهد. اگر جواب ندهد، ایمیج قبلی برمی‌گردد — روی خود نود، بدون منتظر ماندن برای پنل.

از سمت پنل: کانفیگ نود به ایجنت جدید فرستاده می‌شود، هر سرویسی که قبلاً سالم بود باید بعدش هم سالم باشد، و نود برای یک دوره زیر نظر گرفته می‌شود. هر خطایی نود را برمی‌گرداند و کانفیگش را فوراً دوباره می‌فرستد، تا Xray و IPsec و بقیه ظرف چند ثانیه سرویس بدهند.

آپدیت تدریجی: نودهای انتخاب‌شده یکی‌یکی و به ترتیب انتخاب آپدیت می‌شوند. اولی Canary است و بیشتر زیر نظر می‌ماند (پیش‌فرض ۱۸۰ ثانیه؛ بقیه ۶۰ ثانیه). با اولین نودی که شکست بخورد، کار متوقف می‌شود: همان نود روی ایمیج قبلی‌اش برگشته و بقیه‌ی نودها دست نمی‌خورند. آپدیت تدریجی با کلید SSH خود پنل وصل می‌شود، پس هر نود یک بار باید از شیت SSH خودش با رمز وصل شده باشد.

کاربرهای یک نود موقع عوض شدن کانتینرش چند ثانیه قطع و خودکار وصل می‌شوند؛ یک نود در لحظه‌ی ری‌استارت خودش نمی‌تواند سرویس بدهد. برای حذف همین چند ثانیه هم باید دو نود پشت یک آدرس باشند.

tifusi panel update قبل از هر تغییری یک snapshot ایمنی می‌گیرد و اگر نسخه‌ی جدید سالم بالا نیاید، پنل را برمی‌گرداند — پس یک آپدیت خراب فقط چند ثانیه ری‌استارت هزینه دارد، نه پنلی که از کار بیفتد.

  1. اول snapshot. ایمیج‌هایی که پنل الان اجرا می‌کند با تگ tifusi-panel-{backend,frontend}:rollback نگه داشته می‌شوند (قبل از اینکه pull تگ :latest را عوض کند)، و دیتا (دیتابیس، .env و certs/) در <install>/.rollback/ ذخیره می‌شود.
  2. آپدیت. آخرین فایل‌های نصب و ایمیج‌های آماده گرفته می‌شوند و پنل ری‌استارت می‌شود؛ مایگریشن موقع شروع اجرا می‌شود.
  3. چک سلامت. تا ۹۰ ثانیه صبر می‌شود تا کانتینر backend در حال اجرا باشد و API جواب بدهد. اگر داد، آپدیت می‌ماند و snapshot تا آپدیت بعدی نگه داشته می‌شود.
  4. برگشت در صورت خطا. وگرنه ایمیج قبلی برمی‌گردد. چون مایگریشن‌ها فقط جدول و ستون اضافه می‌کنند، کد قدیمی با اسکیمای مایگریت‌شده کار می‌کند، پس هر چیزی که از زمان snapshot نوشته شده حفظ می‌شود. فقط اگر کد قدیمی هم بالا نیاید — یک مایگریشن مخرب نادر — دیتا هم از snapshot برمی‌گردد و پنل با آن بالا می‌آید.

دیتابیس و certs/ در یک آپدیت خراب عادی هیچ‌وقت عوض نمی‌شوند، پس چیزی از دست نمی‌رود.

وقتی یک آپدیت تمام می‌شود، پنل یک پیام کوتاه به چت تلگرامی می‌فرستد که در تنظیمات ← اعلان‌های تلگرام تعیین شده (همان توکن بات و chat id بقیه‌ی اعلان‌ها):

آپدیت چه وقت گزارش می‌آید نتیجه‌ای که نشان می‌دهد
tifusi panel update بعد از چک سلامت، یا بعد از برگشت موفق موفق، یا برگشت به نسخه‌ی قبل
ایجنت یک نود (تب آپدیت در شیت SSH) وقتی کار تمام شود موفق یا ناموفق، با مدت زمانش
🔄 آپدیت تدریجی نودها یک بار برای کل rollout موفق یا ناموفق، با مدت زمانش
یک سمت تانل (🔄 آپدیت تانل) وقتی کار تمام شود موفق یا ناموفق، با مدت زمانش

گزارش ناموفق آخرین خطای لاگ همان کار را هم دارد. هر گزارش در آخر می‌گوید چند نود وصل‌اند (و اگر تانلی دارید، چند تانل سالم‌اند) و نسخه‌ی پنل چیست. متن پیام فارسی است.

آپدیتی که خودتان لغوش کنید پیامی نمی‌فرستد. فرستادن گزارش هیچ‌وقت جلوی آپدیت را نمی‌گیرد: اگر تلگرام تنظیم نشده باشد یا در دسترس نباشد، گزارش بی‌سروصدا کنار گذاشته می‌شود و خود آپدیت هیچ اثری نمی‌گیرد. آپدیت پنلی هم که برگشتش هم شکست بخورد گزارشی ندارد، چون پنلی بالا نیست که آن را بفرستد.

همین تضمین‌ها با تست‌های خودکار پوشش داده شده‌اند (توسعه): اعتبارسنجی و برگشت ایجنت با باینری‌های ساختگی xray، hysteria، swanctl و xl2tpd اجرا می‌شود؛ اسکریپت‌های آپدیت تانل و نود واقعاً با systemctl و docker ساختگی اجرا می‌شوند؛ و زنجیره‌ی مایگریشن باید یک head داشته باشد، مراحل اخیرش برگشت‌پذیر باشد و مدل‌ها دقیقاً با اسکیمای مایگریت‌شده یکی باشند. ایمیج‌ها فقط بعد از پاس شدن تست‌ها منتشر می‌شوند.