معماری
چطور کار میکند
نمای کامل معماری دزکوب — از مسیر یک درخواست تا مرزهای امنیتی، و چهار تصمیمی که همهچیز از آنها آمد.
سه صفحه، سه مسئولیت
چرا دیتابیس ما منبع حقیقت نیست
رایجترین معماری در این دسته از محصولات این است: حالت را در دیتابیس نگه دار و کلاستر را همگام با آن نگه دار. این ساده است و در دموی اول عالی کار میکند. مشکل، ماه سوم شروع میشود.
کافی است یک بار کسی مستقیم در کلاستر تغییری بدهد، یا یک عملیات نیمهکاره بماند. از آن لحظه، دیتابیس یک چیز میگوید و کلاستر چیز دیگری. هر قابلیتی که به آن حالت تکیه دارد — سهمیه، مالکیت، صورتحساب، بکاپ — بیصدا اشتباه میشود. ما جهت را برعکس کردیم.
| مدل «دیتابیس = حقیقت» | مدل دزکوب | |
|---|---|---|
| نوشتن | به دیتابیس، بعد تلاش برای همگامسازی | مستقیم به Kubernetes |
| خواندن | از دیتابیس | از projection که با watch از کلاستر ساخته میشود |
| تغییر دستی در کلاستر | بیصدا واگرایی میسازد | reconciler میبیند: یا برمیگرداند یا گزارش میدهد |
| بازسازی پس از فاجعه | باید دیتابیس را با کلاستر آشتی داد | projection از خودِ کلاستر بازساخته میشود |
| سرعت خواندن | سریع | سریع — همان projection |
چطور مطمئنیم کار میکند؟
یک تست آشوب در مجموعهٔ تستها هست که عمداً منبعی را در کلاستر دستکاری میکند و انتظار دارد اصلاح خودکار رخ بدهد. اگر reconciler خاموش بماند، آن تست قرمز میشود و تغییر مرج نمیشود.
تمام تماس با کلاستر از یک در میگذرد
هیچ سرویسی در دزکوب مستقیم با Kubernetes حرف نمیزند. همه از یک واسطِ واحد عبور میکنند.
قابلیت تست
چون کلاستر پشت یک واسط است، سرویسها را میشود بدون کلاستر واقعی تست کرد. بخش بزرگی از آن ۱۵٬۰۰۰ تست به همین دلیل ممکن شد.
مرز امنیتی واحد
همهٔ manifestها از یک نقطه اعمال میشوند — یعنی یک جای واحد برای اعمال گاردریل، برچسب مالکیت و بررسی سیاست.
کنترل انفجار
حجم درخواست به API server از یک نقطه قابل اندازهگیری و محدودسازی است، نه از سی نقطهٔ پراکنده.
کجاها مرز کشیدهایم
| مرز | چه چیزی را از چه چیزی جدا میکند | مکانیزم |
|---|---|---|
| مستأجر ↔ مستأجر | بار کاری دو سازمان مختلف | namespace، سیاست شبکهٔ default-deny، سهمیه، و ServiceAccount اختصاصی |
| اپلیکیشن ↔ اپلیکیشن | دو اپلیکیشن در یک محیط | سیاست شبکهٔ L3/L4 و در صورت نیاز L7 |
| بار کاری ↔ هسته | کد مستأجر از هستهٔ نود | سطوح ایزوله: عادی، gVisor، یا Kata (ماشین مجازی سبک) |
| کاربر ↔ کلاستر | دسترسی مستقیم به API کلاستر | هیچ کاربری credential کلاستر نمیگیرد؛ همهچیز از کنترلپلن |
| کنترلپلن ↔ کلاستر | خودِ کنترلپلن | نقش حداقلی بهجای cluster-admin |
| ترافیک داخل ↔ بیرون | خروج به اینترنت | سیاست خروج سلسلهمراتبی؛ هیچ سطحی سقف بالادست را باز نمیکند |
| مستأجرِ سختگیر ↔ بقیه | مشتریای که کلاستر مجازی میخواهد | vcluster — کنترلپلن مجازی مستقل |
بلوک اثبات
ماتریسِ تستِ نفوذِ ایزولهسازی، بهازای هر جفتِ نقش و هر منبع، بررسی میکند که آیا دسترسی متقابل ممکن است یا نه. این ماتریس بخشی از مجموعهٔ تست است، نه یک بررسی دستیِ یکباره.
یک درخواست، از اول تا آخر
مثال: یک توسعهدهنده دکمهٔ استقرار را میزند.
اعتبارسنجی توکن
نسخهٔ توکن با نسخهٔ فعلی کاربر مقایسه میشود. توکن باطلشده ← ۴۰۱
بررسی مجوز
نقش در آن پروژه، شرایط ABAC، و مالکیت خودِ منبع. رد شدن ← ۴۰۳ با نامِ سطحی که رد کرد
بررسی سهمیه
پیش از هر کار سنگین. عبور از سقف ← ۴۲۹ با عددِ باقیمانده
اعتبارسنجی ورودی
با schema سختگیرانه. خطا ← ۴۰۰ با نام دقیق فیلد
ثبت ممیزی
یک ردیف نوشته میشود — پیش از انجام کار
بیلد
در صف قرار میگیرد و در یک Job ایزوله و rootless اجرا میشود
بازرسی و امضا
ایمیج اسکن، SBOM تولید، و امضا میشود. آسیبپذیریِ مسدودکننده ← توقف
اعمال
manifest از درگاه واحد به کلاستر اعمال میشود. خطای کلاستر با پیام واقعی، نه ۵۰۰ خالی
همگامسازی
watch تغییر را میبیند و projection را بهروز میکند؛ اختلاف توسط reconciler دیده میشود
گام ۵ عمداً قبل از گام ۶ است.
اگر ممیزی بعد از انجام کار نوشته شود، هر عملیاتی که وسطش خطا بدهد، ردی از خودش باقی نمیگذارد. تلاشِ ناموفق هم باید ثبت شود — برای ممیز، تلاش رد شده گاهی مهمتر از تلاش موفق است.
وقتی چیزی میافتد
| سناریو | چه اتفاقی میافتد |
|---|---|
| یک نودِ کاری میافتد | بار کاری روی نودهای دیگر جدولبندی میشود؛ ماشینهای مجازیِ تحت HA با ترتیبِ حصارکشی راهاندازی مجدد میشوند |
| یک نودِ کنترلی میافتد | etcd با quorum ادامه میدهد؛ کنترلپلن روی نودهای باقیمانده |
| نمونهٔ کنترلپلن میافتد | انتخاب رهبر، مالکیتِ کارهای دورهای را جابهجا میکند — هیچ کار زمانبندیشدهای دو بار اجرا نمیشود |
| کارِ صف شکست میخورد | تلاش مجدد با backoff؛ پس از سقف، به صف نامههای مرده میرود و قابل بازپخش است |
| دیسک replica از دست میرود | Longhorn بازسازی میکند؛ چیدمانِ آگاه به zone مانع میشود همهٔ replicaها در یک domain باشند |
| کل کلاستر از دست میرود | بازیابی از اسنپشات etcd و بکاپهای آبجکتاستوریج، با سطح تعهد RTO/RPO مشخص |
نکتهٔ طراحی
سه سازوکاری که ماشین مجازی جابهجا میکنند — HA، توزیع مجدد بار، و مانور آشوب — یک بودجهٔ حرکتِ مشترک دارند، نه سه بودجهٔ جدا. اگر سهتا جدا بودند، در بدترین لحظه هر سه همزمان شروع به جابهجایی میکردند. HA در این بودجه اولویت دارد، چون اول اجازه میگیرد.
تصمیمهایی که «نه» بودند
| چه چیزی | چرا نه |
|---|---|
| مدل کاملاً اعلامی (GitOps خالص) | مدل ما امری است و منبع حقیقتش کلاستر است. چسباندنِ یک موتور GitOps بالای آن، دو مالک برای یک شیء میسازد. اگر تیم شما GitOps دارد، بهعنوان یک حالتِ اختیاری پشتیبانی میشود، نه بهعنوان موتور اصلی. |
| فرمت اختصاصی برای تعریف بار کاری | هر چیزی که میسازیم، در نهایت یک شیء استاندارد Kubernetes است. اگر روزی دزکوب را کنار بگذارید، کلاستر شما همچنان کار میکند. |
| سرویس بیرونی برای هر قابلیت | هر وابستگیِ سرویسی یک نقطهٔ شکست، یک مسیر ارتقا و یک سطح حمله اضافه میکند. کتابخانهٔ درونپروسه ترجیح دارد مگر ارزش سرویسِ جدا عظیم باشد. |
| اعتماد به آنچه پادِ بیلد دربارهٔ خودش میگوید | پادِ بیلد کد مستأجر را اجرا میکند. اطلاعاتِ اصالت را کنترلپلن میسازد، نه خودِ پاد — وگرنه در همان مدلِ تهدیدی که provenance را ارزشمند میکند، قابل جعل است. |
اینها را هم ببینید
سؤالهای سختتری دارید؟
جلسهٔ فنی بگذارید. با تیم مهندسی صحبت میکنید، نه تیم فروش.