استقرار یک کانتینر ساده است. استقرار ده کانتینر قابل مدیریت است. اما زمانی که صدها کانتینر را روی ده‌ها ماشین اجرا می‌کنید، مدیریت دستی دیگر فقط دشوار نیست، بلکه غیرممکن می‌شود. شما دیگر نمی‌دانید هر کانتینر کجا قرار دارد. یک سرور از کار می‌افتد و اپلیکیشن شما از دسترس خارج می‌شود تا زمانی که کسی بیدار شود و آن را دوباره راه‌اندازی کند. قبل از اینکه بتوانید نمونه‌های (instances) جدیدی ایجاد کنید، افزایش ناگهانی ترافیک سیستم شما را از پا در می‌آورد. این دقیقاً همان جایی است که Kubernetes وارد میدان می‌شود. این فقط یک ابزار DevOps دیگر نیست؛ بلکه یک لایه ارکستراسیون (orchestration) است که مدیریت کانتینرها را به جای یک تمرین اسکریپت‌نویسی، به عنوان یک مسئله کنترلی می‌بیند.

چرا اسکریپت‌ها در نهایت از کار می‌افتند

اکثر تیم‌ها با اسکریپت‌های شل (shell scripts) یا اتوماسیون‌های پایه شروع می‌کنند. آن‌ها دستوراتی برای دریافت ایمیج‌ها (pull images)، شروع کانتینرها، نظارت بر لاگ‌ها و راه‌اندازی مجدد فرآیندهای شکست‌خورده می‌نویسند. این رویکرد برای اثبات مفهوم (proof of concept) جواب می‌دهد، اما زیر بارِ فشار دنیای واقعی فرو می‌پاشد. میکروسرویس‌ها با یکدیگر در میزبان‌های (hosts) مختلف ارتباط برقرار می‌کنند، به متغیرهای محیطی (environment variables) خاصی وابسته هستند، به ذخیره‌سازی پایدار (persistent storage) نیاز دارند که با راه‌اندازی مجدد کانتینر از بین نرود، و انتظار شبکه‌سازی یکپارچه بین نسخه‌ها را دارند. یک اسکریپت نمی‌تواند وقتی یک ماشین مجازی ناپدید می‌شود، بار کاری (workload) را به طور خودکار باززمان‌بندی (reschedule) کند. اسکریپت نمی‌تواند ترافیک شبکه را بین نمونه‌های سالم توزیع کند و همزمان از نمونه‌هایی که در چرخه کرش (crash loop) گیر کرده‌اند عبور کند. Kubernetes این مشکل را با سپردن مسئولیت این تصمیمات به خودِ کلاستر حل می‌کند. شما آنچه را که می‌خواهید توصیف می‌کنید و سیستم به طور مداوم آن وضعیت را اعمال می‌کند.

سه قابلیت اصلی که به شما می‌دهد

Kubernetes سه قابلیت اصلی را ارائه می‌دهد که جایگزین مدیریت بحران‌های دستی با قابلیت اطمینان خودکار می‌شود.

در دسترس بودن بالا (High availability) به این معناست که اپلیکیشن‌های شما حتی زمانی که بخش‌هایی از زیرساخت شما از کار می‌افتند، آنلاین می‌مانند. اگر یک کانتینر کرش کند، Kubernetes در عرض چند ثانیه آن را جایگزین می‌کند. اگر یک نودِ کارگر (worker node) کاملاً از دسترس خارج شود، زمان‌بند (scheduler) متوجه قطع شدن ضربان قلب (heartbeat) شده و بارهای کاریِ تحت تأثیر را به ماشین‌های سالم در جای دیگری از کلاستر منتقل می‌کند. سیستم به طور مداوم بر وضعیت مطلوب (desired state) که شما تعریف کرده‌اید نظارت می‌کند و انحرافات را بدون دخالت انسان اصلاح می‌کند.

مقیاس‌پذیری (Scalability) به این معناست که اپلیکیشن‌های شما همگام با کاربران شما رشد می‌کنند. به جای آماده‌سازی بیست سرور فقط برای تحمل یک اوج ترافیک دو ساعته، معیارهای مهمی مانند میزان استفاده از CPU یا تأخیر درخواست (request latency) را تعریف می‌کنید و اجازه می‌دهید کلاستر در صورت عبور از آستانه‌ها، نمونه‌های کانتینر بیشتری اضافه کند. وقتی تقاضا کاهش می‌یابد، تعداد کپی‌ها (replica count) دوباره کم می‌شود. شما فقط برای آنچه نیاز دارید و در زمانی که نیاز دارید، هزینه پرداخت می‌کنید.

بازیابی پس از فاجعه (Disaster recovery) به این معناست که داده‌ها و تنظیمات شما پس از یک کرش بازمی‌گردند. Kubernetes کل وضعیت کلاستر را در یک ذخیره‌ساز کلید-مقدار (key-value store) توزیع‌شده ذخیره می‌کند. اگر یک خرابی فاجعه‌بار، نودهای کارگر یا حتی بخشی از صفحه کنترل (control plane) را از بین ببرد، آن وضعیت ذخیره‌شده به سیستم اجازه می‌دهد تا بارهای کاری شما را دقیقاً همان‌گونه که پیکربندی شده بودند، بازسازی کند. داده‌های شما بازمی‌گردند زیرا ارکستراتور به یاد می‌آورد که وضعیت باید چگونه می‌بود.

ساختار: مغز و عضله

یک کلاستر Kubernetes دارای دو نقش اساسی است که در اینجا به عنوان «مغز» و «عضله» توصیف می‌شوند، و این تشبیه در عمل بسیار دقیق است.

Master Node همان مغز است. این نود اپلیکیشن‌های رو به مشتری شما را اجرا نمی‌کند؛ بلکه میزبان اجزای صفحه کنترل (control plane) است که وظایف را زمان‌بندی می‌کنند، وضعیت کلاستر را مدیریت می‌کنند و به تغییرات پاسخ می‌دهند. وقتی دستوری صادر می‌کنید یا یک فایل پیکربندی ارسال می‌کنید، Master Node تصمیم می‌گیرد که بار کاری کجا باید قرار بگیرد، آیا سالم است یا خیر، و در صورت عدم سلامت باید چه کرد.

Worker Nodes همان عضله هستند. هر Worker یک عامل (agent) سبک را اجرا می‌کند که با Master ارتباط برقرار کرده و از یک محیط اجرای کانتینر (container runtime) برای اجرای پادهای (pods) واقعی استفاده می‌کند. این نودها جایی هستند که کد اپلیکیشن شما از CPU و حافظه استفاده می‌کند. با افزودن نودهای کارگر بیشتر، ظرفیت خام کلاستر شما افزایش می‌یابد. با افزودن Master Nodeهای بیشتری که برای افزونگی (redundancy) پیکربندی شده‌اند، صفحه کنترل شما در برابر خرابی‌های سخت‌افزاریِ تک‌واحدی مقاوم می‌شود.

پادها، کانتینرها و سرویس‌ها

برای کار با Kubernetes، باید سه اصطلاح را درک کنید که نحوه بسته‌بندی و دسترسی به نرم‌افزار را تعریف می‌کنند.

کانتینرها (Containers) بسته‌هایی هستند که اپلیکیشن شما را همراه با وابستگی‌ها، کتابخانه‌ها و تنظیماتش بسته‌

Podها کوچک‌ترین واحد قابل استقرار در Kubernetes هستند. یک pod یک یا چند کانتینر را که نیاز به اشتراک‌گذاری منابع دارند، در بر می‌گیرد. آن‌ها فضای نام شبکه (network namespace) یکسانی دارند و می‌توانند به حجم‌های ذخیره‌سازی محلی (local storage volumes) یکسانی دسترسی داشته باشند. نکته مهم این است: شما یک کانتینر خام را مستقیماً مستقر نمی‌کنید، بلکه پادی را مستقر می‌کنید که آن را در خود جای داده است. Podها همچنین به عمد گذرا (ephemeral) هستند. آن‌ها با تغییر شرایط، ایجاد، تخریب و جایگزین می‌شوند. طول عمر آن‌ها به گونه‌ای طراحی شده که پویا باشد.

Serviceها به این دلیل وجود دارند که podها گذرا هستند. هر بار که یک pod ری‌استارت می‌شود، احتمالاً یک آدرس IP داخلی جدید دریافت می‌کند. اگر بخش‌های دیگر اپلیکیشن شما سعی کنند مستقیماً به این آدرس‌های متغیر متصل شوند، مدام با خطا مواجه خواهند شد. یک service به podهای شما یک آدرس IP ثابت و یک نام DNS اختصاص می‌دهد. این سرویس مانند یک در ورودی پایدار عمل کرده و درخواست‌های ورودی را بین تمام podهای سالمی که با انتخاب‌گر (selector) آن مطابقت دارند، متعادل‌سازی (load-balancing) می‌کند. این کار کلاینت‌های شما را از آشفتگی چرخه‌های عمر تک‌تک کانتینرها جدا می‌کند.

Kubernetes در مقیاس بزرگ: مثال Netflix

Netflix از Kubernetes برای مدیریت شبکه توزیع محتوای (CDN) خود استفاده می‌کند. این زیرساخت جریان‌های ویدئویی را به‌طور همزمان به میلیون‌ها بیننده در سراسر جهان ارسال می‌کند. وقتی یک سریال محبوب منتشر می‌شود و تقاضا به شدت بالا می‌رود، کلاستر (cluster) گره‌های حافظه پنهان (cache nodes) را که بخش‌های ویدئویی را در نزدیکی کاربران ذخیره می‌کنند، گسترش می‌دهد (scale out). اگر یک گره منطقه‌ای از کار بیفتد، ترافیک به‌طور خودکار تغییر مسیر می‌دهد. نتیجه این است که فیلم‌ها برای میلیون‌ها نفر بدون نیاز به فراخوانی اضطراری و دستی یک مهندس، بدون وقفه پخش می‌شوند. ارکستراتور (orchestrator) مقیاس‌پذیری و خطاها را مدیریت می‌کند تا سرویس بدون وقفه ادامه یابد.

شروع کار: YAML، JSON و API Server

شروع کار با Kubernetes به معنای کنار گذاشتن روش‌های دستوری (imperative click-ops) و پذیرش پیکربندی بیانی (declarative configuration) است. شما آنچه را که می‌خواهید در فایل‌های YAML یا JSON می‌نویسید. این مانیفست‌ها (manifests) همه چیز را توصیف می‌کنند؛ از ایمیج کانتینر گرفته تا تعداد نسخه‌ها (replicas)، پورت‌های باز شده، متغیرهای محیطی و محل‌های اتصال ذخیره‌سازی (storage mounts). وقتی فایل شما آماده شد، آن را به API server در گره اصلی (master node) ارسال می‌کنید. کنترل پلین (control plane) آن اعلان را دریافت کرده، در پایگاه داده وضعیت کلاستر ذخیره می‌کند و سپس برای مطابقت دادن واقعیت با توصیف شما شروع به کار می‌کند. شما به Kubernetes دقیقاً نمی‌گویید که چگونه کارش را انجام دهد؛ بلکه به آن می‌گویید نتیجه نهایی باید چه باشد و خودِ آن مراحل را پیدا می‌کند.

نتیجه‌گیری اصلی

یادگیری Kubernetes منحنی یادگیری دارد. اصطلاحات در ابتدا سنگین و پیچیده به نظر می‌رسند. اجزای متحرک زیادی وجود دارد و عیب‌یابی (debugging) یک سیستم توزیع‌شده ذاتاً دشوارتر از عیب‌یابی یک سرور واحد است. اما پاداش آن، آرامش عملیاتی است. دیگر نیازی نیست مدام مراقب ماشین‌های تکی باشید. دیگر لازم نیست دعا کنید که اسکریپت‌های استارتاپ شما در زمان قطعی ساعت ۳ صبح کار کنند. شما شروع به طراحی برای شکست (designing for failure) به صورت پیش‌فرض می‌کنید؛ با این فرض که گره‌ها از کار خواهند افتاد و با اعتماد به ارکستراتور برای سالم نگه داشتن اپلیکیشن خود. این تغییر در طرز فکر، از «امیدوار بودن به اینکه چیزی خراب نشود» به «دانستن اینکه سیستم می‌تواند خرابی‌ها را مدیریت کند»، همان چیزی است که ارزش این تلاش را دارد.

Source: What Is Kubernetes? Kubernetes Explained in 15 Mins

Optional learning community: GyaanSetu AI on Telegram