الزامات برای توسعه یک برنامه کاربردی در Kubernetes

امروز قصد دارم در مورد نحوه نوشتن برنامه ها و اینکه چه الزاماتی برای عملکرد خوب برنامه شما در Kubernetes وجود دارد صحبت کنم. به طوری که هیچ سردردی در برنامه وجود نداشته باشد، به طوری که نیازی به اختراع و ایجاد "خراش" در اطراف آن نباشید - و همه چیز همانطور که خود Kubernetes در نظر داشت کار می کند.

این سخنرانی بخشی از "مدرسه شبانه Slurm در Kubernetes" می توانید سخنرانی های نظری باز مدرسه عصرانه را مشاهده کنید در یوتیوب، در یک لیست پخش گروه بندی شده است. برای کسانی که متن را به ویدیو ترجیح می دهند، این مقاله را آماده کرده ایم.

نام من پاول سلیوانوف است، در حال حاضر مهندس پیشرو DevOps در Mail.ru Cloud Solutions هستم، ما ابرها را می سازیم، کوبرنت های مدیریتی می سازیم و غیره. وظایف من اکنون شامل کمک در توسعه، راه اندازی این ابرها، عرضه برنامه هایی است که می نویسیم و توسعه مستقیم ابزارهایی که برای کاربران خود ارائه می دهیم.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

من فکر می کنم DevOps را در سه سال گذشته انجام می دهم. اما، در اصل، تقریباً پنج سال است که من همان کاری را انجام می دهم که DevOps انجام می دهد. قبل از آن بیشتر درگیر امور ادمین بودم. من مدتها پیش کار با Kubernetes را شروع کردم - احتمالاً حدود چهار سال از شروع کار با آن می گذرد.

به طور کلی، من از زمانی شروع کردم که Kubernetes نسخه 1.3 بود، احتمالا، و شاید 1.2 - زمانی که هنوز در مراحل اولیه بود. اکنون دیگر در مراحل ابتدایی خود نیست - و واضح است که تقاضای زیادی در بازار برای مهندسانی وجود دارد که مایلند قادر به انجام Kubernetes باشند. و شرکت ها تقاضای بسیار بالایی برای چنین افرادی دارند. بنابراین، در واقع، این سخنرانی ظاهر شد.

اگر طبق طرح چیزی که در مورد آن صحبت خواهم کرد صحبت کنیم، به نظر می رسد که در پرانتز نوشته شده است (TL;DR) - «خیلی طولانی است. نخوان». ارائه امروز من شامل لیست های بی پایان خواهد بود.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

در واقع، من خودم وقتی چنین ارائه‌هایی را انجام می‌دهم، دوست ندارم، اما این موضوعی است که وقتی داشتم این ارائه را آماده می‌کردم، واقعاً متوجه نشدم که چگونه این اطلاعات را متفاوت سازماندهی کنم.

زیرا، به طور کلی، این اطلاعات "ctrl+c, ctrl+v" است، از جمله موارد دیگر، ویکی ما در بخش DevOps، جایی که ما الزامات نوشته شده ای برای توسعه دهندگان داریم: "بچه ها، به طوری که ما برنامه شما را در Kubernetes، باید اینگونه باشد."

به همین دلیل است که ارائه به یک لیست بزرگ تبدیل شد. متاسف. سعی می کنم تا حد امکان بگویم تا در صورت امکان خسته کننده نباشد.

آنچه که اکنون می خواهیم به آن نگاه کنیم:

  • اینها اولاً لاگ هستند (لاگ های برنامه؟)، در Kubernetes با آنها چه باید کرد، با آنها چه باید کرد، چه باید باشند.
  • با پیکربندی‌ها در Kubernetes چه باید کرد، بهترین و بدترین راه‌ها برای پیکربندی برنامه برای Kubernetes چیست.
  • بیایید در مورد بررسی های دسترسی به طور کلی صحبت کنیم، آنها باید چگونه باشند.
  • بیایید در مورد این که خاموشی دلپذیر چیست صحبت کنیم.
  • بیایید دوباره در مورد منابع صحبت کنیم.
  • اجازه دهید یک بار دیگر به موضوع ذخیره سازی داده ها بپردازیم.
  • و در پایان به شما خواهم گفت که این برنامه اسرارآمیز بومی ابری چیست. ابری بودن، به عنوان صفت این اصطلاح.

سیاهههای مربوط

پیشنهاد می‌کنم با سیاهه‌ها شروع کنید - از جایی که این سیاهه‌ها باید در Kubernetes رانده شوند. اکنون یک برنامه کاربردی در Kubernetes راه اندازی کرده اید. با توجه به کلاسیک ها، قبلاً برنامه ها همیشه گزارش هایی را در جایی از یک فایل می نوشتند. برنامه‌های بد گزارش‌ها را در یک فایل در فهرست اصلی توسعه‌دهنده‌ای که برنامه را راه‌اندازی کرده بود، نوشتند. برنامه های خوب در جایی در یک فایل لاگ می نوشتند /var/log.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

بر این اساس، علاوه بر این، مدیران خوب مواردی را در زیرساخت‌های خود پیکربندی کرده‌اند که این لاگ‌ها می‌توانند بچرخند - همان rsyslog که به این گزارش‌ها نگاه می‌کند و وقتی اتفاقی برای آنها می‌افتد، تعداد زیادی از آنها وجود دارد، کپی‌های پشتیبان ایجاد می‌کند، گزارش‌ها را در آنجا قرار می‌دهد. ، فایل های قدیمی را بیش از یک هفته، شش ماه و مدتی دیگر حذف می کند. در تئوری، ما باید مقرراتی داشته باشیم تا صرفاً به دلیل اینکه برنامه لاگ می نویسد، فضای سرورهای تولید (سرورهای رزمی؟) تمام نشود. و بر این اساس، کل تولید به دلیل سیاهههای مربوط متوقف نشد.

وقتی به دنیای Kubernetes نقل مکان می کنیم و همان چیزی را در آنجا اجرا می کنیم، اولین چیزی که می توانید به آن توجه کنید این واقعیت است که افراد همانطور که لاگ ها را در یک فایل می نویسند، به نوشتن آنها ادامه می دهند.

به نظر می رسد که اگر در مورد Kubernetes صحبت کنیم، مکان مناسب برای نوشتن گزارش ها در جایی از یک ظرف داکر، نوشتن آنها از برنامه به اصطلاح Stdout/Stderr است، یعنی جریان های خروجی استاندارد سیستم عامل، خروجی خطای استاندارد این صحیح ترین، ساده ترین و منطقی ترین راه برای قرار دادن لاگ در اصل در Docker و به طور خاص در Kubernetis است. زیرا اگر برنامه شما گزارش‌ها را در Stdout/Stderr می‌نویسد، پس این بر عهده Docker و افزونه Kubernetes است که تصمیم بگیرند با این گزارش‌ها چه کار کنند. Docker به طور پیش فرض فایل های ویژه خود را با فرمت JSON می سازد.

در اینجا این سوال مطرح می شود که بعداً با این لاگ ها چه خواهید کرد؟ ساده ترین راه روشن است، ما توانایی انجام آن را داریم kubectl logs و به این سیاهههای مربوط به این "غلاف" نگاه کنید. اما، احتمالا، این گزینه خیلی خوبی نیست - کار دیگری باید با سیاهههای مربوط انجام شود.

در حال حاضر، بیایید همزمان با هم صحبت کنیم، از آنجایی که ما به موضوع سیاههها پرداختیم، در مورد چیزی به عنوان سیاههها باید به نظر برسد. یعنی این به طور مستقیم در مورد Kubernetes صدق نمی کند، اما وقتی شروع به فکر کردن در مورد اینکه با لاگ ها چه کار کنیم، خوب است به این موضوع نیز فکر کنیم.

ما به نوعی ابزار، به روشی دوستانه، نیاز داریم که این گزارش‌هایی را که داکر ما در فایل‌های خود قرار می‌دهد، بگیرد و به جایی بفرستد. به طور کلی، ما معمولاً نوعی عامل را در داخل Kubernetes به شکل DaemonSet راه‌اندازی می‌کنیم - جمع‌آوری گزارش که به سادگی به آن گفته می‌شود که گزارش‌هایی که داکر جمع‌آوری می‌کند در کجا قرار دارند. و این عامل جمع‌آوری به سادگی آنها را می‌گیرد، شاید حتی به نحوی آنها را در طول مسیر تجزیه می‌کند، شاید آنها را با برخی متا اطلاعات اضافی غنی می‌کند و در نهایت، آنها را برای ذخیره‌سازی به جایی می‌فرستد. در حال حاضر تغییرات در آنجا امکان پذیر است. رایج ترین احتمالاً Elasticsearch است، جایی که می توانید سیاهه ها را ذخیره کنید و می توانید به راحتی آنها را از آنجا بازیابی کنید. سپس با استفاده از یک درخواست، مثلاً با استفاده از کیبانا، نمودارهایی را بر اساس آنها بسازید، بر اساس آنها هشدار بسازید و غیره.

مهم‌ترین ایده، می‌خواهم دوباره آن را تکرار کنم، این است که در داخل Docker، به‌ویژه در داخل Kubernetes، ذخیره کردن گزارش‌های شما در یک فایل ایده بسیار بدی است.

زیرا اولاً، دریافت سیاهههای مربوط به داخل ظرف در یک فایل دشوار است. ابتدا باید به کانتینر بروید، آنجا را اجرا کنید و سپس به گزارش‌ها نگاه کنید. نکته بعدی این است که اگر در یک فایل لاگ دارید، معمولاً کانتینرها محیطی مینیمال دارند و هیچ ابزاری که معمولاً برای کار معمولی با لاگ مورد نیاز است وجود ندارد. آنها را دفن کنید، به آنها نگاه کنید، آنها را در یک ویرایشگر متن باز کنید. لحظه بعد زمانی است که در یک فایل داخل یک کانتینر لاگ هایی داریم، اگر این کانتینر حذف شود، متوجه می شوید که لاگ ها نیز همراه با آن می میرند. بر این اساس، هر گونه راه اندازی مجدد کانتینر به این معنی است که دیگر لاگ وجود ندارد. باز هم گزینه بد

و آخرین نکته این است که در داخل کانتینرها معمولاً برنامه خود را دارید و تمام - معمولاً تنها فرآیندی است که در حال اجرا است. هیچ صحبتی در مورد فرآیندی که فایل ها را با لاگ های شما بچرخاند وجود ندارد. به محض اینکه لاگ ها در یک فایل نوشته می شوند، به این معنی است که، ببخشید، سرور تولید را از دست خواهیم داد. زیرا، اولا، یافتن آنها دشوار است، هیچ کس آنها را ردیابی نمی کند، به علاوه هیچ کس آنها را کنترل نمی کند - بر این اساس، فایل به طور بی پایان رشد می کند تا زمانی که فضای سرور به سادگی تمام شود. بنابراین، دوباره می گویم که ورود به Docker، به ویژه در Kubernetes، به یک فایل ایده بدی است.

نکته بعدی، در اینجا من می خواهم دوباره در مورد این صحبت کنم - از آنجایی که ما به موضوع لاگ ها می پردازیم، خوب است که در مورد نحوه ظاهری لاگ ها صحبت کنیم تا کار با آنها راحت باشد. همانطور که گفتم، موضوع به طور مستقیم به Kubernetes مربوط نمی شود، اما ارتباط بسیار خوبی با موضوع DevOps دارد. در مورد فرهنگ توسعه و دوستی بین این دو بخش مختلف - Dev و Ops، تا همه راحت باشند.

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

اگر JSON شما بر اساس برخی معیارها کار نمی کند، هیچ کس نمی داند چه چیزی چیست، پس حداقل گزارش ها را در قالبی بنویسید که قابل تجزیه باشد. در اینجا، بهتر است به این واقعیت فکر کنید که، به عنوان مثال، اگر شما در حال اجرای دسته ای از کانتینرها هستید یا فقط با nginx پردازش می کنید، و هر کدام تنظیمات لاگ مخصوص به خود را دارند، احتمالاً به نظر می رسد که برای شما بسیار ناخوشایند باشد. آنها را تجزیه کنید زیرا برای هر نمونه جدید nginx باید تجزیه کننده خود را بنویسید، زیرا آنها لاگ ها را متفاوت می نویسند. دوباره، احتمالاً ارزش این را داشت که مطمئن شوید همه این نمونه‌های nginx پیکربندی گزارش یکسانی دارند و همه گزارش‌های خود را کاملاً یکسان می‌نویسند. همین امر برای همه برنامه ها صدق می کند.

در پایان، من همچنین می خواهم به آتش سوخت اضافه کنم که، در حالت ایده آل، باید از لاگ های قالب چند خطی اجتناب شود. نکته اینجاست، اگر تا به حال با کلکسیونرهای سیاهه کار کرده اید، به احتمال زیاد آنچه را که به شما قول می دهند، دیده اید، که می توانند با لاگ های چند خطی کار کنند، می دانند چگونه آنها را جمع آوری کنند و غیره. در واقع، به نظر من، امروز حتی یک کلکتور نمی تواند لاگ های چند خطی را به طور معمول، کامل و بدون خطا جمع آوری کند. به صورت انسانی، تا راحت و بدون خطا باشد.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

اما stack trace همیشه لاگ های چند خطی و نحوه اجتناب از آنها است. سوال اینجاست که یک log رکورد یک رویداد است و stactrace در واقع یک گزارش نیست. اگر گزارش‌ها را جمع‌آوری کنیم و آنها را در جایی در Elasticsearch قرار دهیم و سپس نمودارهایی را از آنها ترسیم کنیم، گزارش‌هایی از فعالیت کاربر در سایت شما بسازیم، سپس وقتی یک stack trace دریافت کردید، به این معنی است که اتفاقی غیرمنتظره در حال رخ دادن است. یک وضعیت کنترل نشده در برنامه شما. و منطقی است که به طور خودکار یک stack trace را در جایی در سیستمی آپلود کنید که بتواند آنها را ردیابی کند.

این نرم افزار (همان Sentry) است که به طور خاص برای کار با stack trace ساخته شده است. می‌تواند فوراً وظایف خودکار ایجاد کند، آنها را به شخصی اختصاص دهد، هنگام رخ دادن stacttraces هشدار دهد، این stacttraces را بر اساس یک نوع گروه‌بندی کند و غیره. در اصل، وقتی در مورد لاگ ها صحبت می کنیم، صحبت در مورد stactraces چندان منطقی نیست، زیرا در نهایت، اینها چیزهای مختلفی با اهداف متفاوت هستند.

پیکربندی

در ادامه در مورد پیکربندی در Kubernetes صحبت می کنیم: با آن چه باید کرد و چگونه برنامه های کاربردی داخل Kubernetes باید پیکربندی شوند. به طور کلی، من معمولا می گویم که Docker در مورد کانتینر نیست. همه می دانند که داکر در مورد کانتینرها است، حتی آنهایی که زیاد با داکر کار نکرده اند. تکرار می کنم، داکر در مورد کانتینرها نیست.

Docker، به نظر من، در مورد استانداردها است. و تقریباً برای همه چیز استانداردهایی وجود دارد: استانداردهایی برای ساخت برنامه شما، استانداردهایی برای نصب برنامه شما.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

و این چیز - ما قبلاً از آن استفاده می کردیم، به تازگی با ظهور کانتینرها محبوبیت خاصی پیدا کرد - این چیز را متغیرهای ENV (محیط) می نامند، یعنی متغیرهای محیطی که در سیستم عامل شما هستند. این به طور کلی یک راه ایده آل برای پیکربندی برنامه شما است، زیرا اگر برنامه هایی در JAVA، Python، Go، Perl، خدای ناکرده دارید، و همه آنها می توانند میزبان پایگاه داده، کاربر پایگاه داده، متغیرهای رمز عبور پایگاه داده را بخوانند، پس ایده آل است. شما برنامه هایی را به چهار زبان مختلف دارید که در پلان پایگاه داده به همان روش پیکربندی شده اند. دیگر تنظیمات متفاوتی وجود ندارد.

همه چیز را می توان با استفاده از متغیرهای ENV پیکربندی کرد. وقتی در مورد Kubernetes صحبت می کنیم، یک راه عالی برای اعلام متغیرهای ENV در داخل Deployment وجود دارد. بر این اساس، اگر در مورد داده‌های مخفی صحبت می‌کنیم، می‌توانیم بلافاصله داده‌های مخفی را از متغیرهای ENV (گذرواژه به پایگاه‌های داده و غیره) به یک راز فشار دهیم، یک خوشه مخفی ایجاد کنیم و در توضیحات ENV در Deployment نشان دهیم که مستقیماً اعلام نمی‌کنیم. مقدار این متغیر، و مقدار متغیر رمز عبور پایگاه داده از مخفی خوانده می شود. این رفتار استاندارد Kubernetes است. و این ایده آل ترین گزینه برای پیکربندی برنامه های شما است. فقط در سطح کد، دوباره این برای توسعه دهندگان صدق می کند. اگر DevOps هستید، می‌توانید بپرسید: «بچه‌ها، لطفاً خواندن متغیرهای محیطی را به برنامه خود آموزش دهید. و همه ما خوشحال خواهیم شد."

اگر همه افراد شرکت متغیرهای محیطی با نام مشابه را بخوانند، عالی است. به طوری که این اتفاق نیفتد که برخی منتظر پایگاه داده postgres هستند ، برخی دیگر منتظر نام پایگاه داده هستند ، برخی دیگر منتظر چیز دیگری هستند ، برخی دیگر منتظر یک dbn نوعی هستند تا بر این اساس یکنواختی وجود داشته باشد.

مشکل زمانی پیش می‌آید که متغیرهای محیطی زیادی دارید که فقط Deployment را باز می‌کنید - و پانصد خط متغیر محیطی وجود دارد. در این مورد، شما به سادگی از متغیرهای محیطی پیشی گرفته اید - و دیگر نیازی به شکنجه خود ندارید. در این مورد، شروع به استفاده از تنظیمات منطقی است. یعنی برنامه خود را برای استفاده از تنظیمات آموزش دهید.

تنها سوال این است که تنظیمات آن چیزی نیست که شما فکر می کنید. Config.pi پیکربندی مناسبی برای استفاده نیست. یا برخی از پیکربندی ها در قالب خود شما، به طور متناوب با استعداد - این نیز پیکربندی منظور من نیست.

چیزی که من در مورد آن صحبت می کنم پیکربندی در قالب های قابل قبول است، یعنی تا حد زیادی محبوب ترین استاندارد استاندارد .yaml است. نحوه خواندن آن مشخص است، خواندن آن توسط انسان قابل خواندن است، نحوه خواندن آن از برنامه مشخص است.

بر این اساس، علاوه بر YAML، به عنوان مثال، می توانید از JSON نیز استفاده کنید، تجزیه تقریباً به اندازه YAML از نظر خواندن پیکربندی برنامه از آنجا راحت است. خواندن آن به طور قابل توجهی برای مردم ناخوشایندتر است. می توانید فرمت را امتحان کنید، a la ini. خواندن آن از دیدگاه انسانی بسیار راحت است، اما ممکن است پردازش خودکار آن ناخوشایند باشد، به این معنا که اگر زمانی بخواهید پیکربندی های خود را ایجاد کنید، ممکن است فرمت ini از قبل برای تولید ناخوشایند باشد.

اما در هر صورت، هر فرمتی که انتخاب کنید، نکته این است که از دیدگاه Kubernetes بسیار راحت است. می توانید کل پیکربندی خود را در Kubernetes در ConfigMap قرار دهید. و سپس این configmap را بگیرید و از آن بخواهید که در پوشه شما در یک دایرکتوری خاص نصب شود، جایی که برنامه شما پیکربندی را از این configmap می خواند، گویی فقط یک فایل است. این در واقع کاری است که وقتی گزینه های پیکربندی زیادی در برنامه خود دارید انجام دهید. یا فقط نوعی ساختار پیچیده است، تودرتو وجود دارد.

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

دوباره، من قبلاً در این مورد صحبت کردم - اطلاعات مخفی در کانفیگ مپ نیست، اطلاعات مخفی در متغیرها نیست، اطلاعات مخفی در اسرار نیست. از آنجا، این اطلاعات محرمانه را به دیپلماسی متصل کنید. معمولاً ما تمام توضیحات مربوط به اشیاء Kubernetes، استقرارها، کانفیگ مپ ها، سرویس ها را در git ذخیره می کنیم. بر این اساس، قرار دادن رمز عبور پایگاه داده در git، حتی اگر git شما باشد که به صورت داخلی در شرکت دارید، ایده بدی است. زیرا، حداقل، git همه چیز را به خاطر می آورد و به سادگی حذف رمزهای عبور از آنجا چندان آسان نیست.

بررسی سلامت

نکته بعدی این چیزی است که به آن بررسی سلامت می گویند. به طور کلی، بررسی سلامت به سادگی بررسی می کند که برنامه شما کار می کند. در عین حال، ما اغلب در مورد برنامه های وب خاصی صحبت می کنیم که بر این اساس، از نظر بررسی سلامت (بهتر است اینجا و بیشتر ترجمه نشود) این یک URL خاص است که آنها به عنوان پردازش می کنند. یک استاندارد، آنها معمولا انجام می دهند /health.

بر این اساس، هنگام دسترسی به این URL، برنامه ما می گوید "بله، خوب، همه چیز با من خوب است، 200" یا "نه، همه چیز با من خوب نیست، حدود 500". بر این اساس، اگر برنامه ما http نباشد، نه یک برنامه وب، اکنون در مورد نوعی دیمون صحبت می کنیم، می توانیم نحوه انجام بررسی های سلامت را بفهمیم. یعنی لازم نیست، اگر برنامه http نباشد، همه چیز بدون بررسی سلامت کار می کند و به هیچ وجه نمی توان این کار را انجام داد. می‌توانید به‌صورت دوره‌ای برخی از اطلاعات فایل را به‌روزرسانی کنید، می‌توانید دستور خاصی برای دیمون خود ایجاد کنید، مانند: daemon status، که می گوید "بله، همه چیز خوب است، دیمون کار می کند، زنده است."

این برای چیست؟ اولین و واضح ترین چیز احتمالاً این است که چرا به بررسی سلامت نیاز است - برای درک اینکه برنامه کار می کند. منظورم این است که فقط احمقانه است، وقتی که الان بالا است، به نظر می رسد که کار می کند، بنابراین می توانید مطمئن باشید که کار می کند. و معلوم می شود که برنامه در حال اجرا است، کانتینر در حال اجرا است، نمونه کار می کند، همه چیز خوب است - و سپس کاربران قبلاً تمام شماره های تلفن را از پشتیبانی فنی قطع کرده اند و می گویند "تو چی هستی... خوابم برد، هیچ چیز کار نمی کند.»

بررسی سلامت دقیقاً راهی است برای اینکه از دیدگاه کاربر ببینید که کار می کند. یکی از روش ها. بیایید آن را اینگونه بیان کنیم. از دیدگاه Kubernetes، این نیز راهی برای فهمیدن زمان شروع برنامه است، زیرا می‌دانیم که بین زمان راه‌اندازی، ایجاد و راه‌اندازی کانتینر و زمانی که برنامه مستقیماً در این کانتینر راه‌اندازی شده است، تفاوت وجود دارد. زیرا اگر یک برنامه جاوای متوسط ​​را برداریم و سعی کنیم آن را در داک راه اندازی کنیم، برای چهل ثانیه، یا حتی یک دقیقه، یا حتی ده، می تواند به خوبی شروع شود. در این صورت حداقل می توانید به پورت های آن بکوبید، آنجا جواب نمی دهد، یعنی هنوز آماده دریافت ترافیک نیست.

باز هم، با کمک یک بررسی سلامت و با کمک این واقعیت که ما در حال چرخش به اینجا هستیم، می‌توانیم در Kubernetes بفهمیم که نه تنها یک ظرف در برنامه بالا آمده است، بلکه خود برنامه شروع به کار کرده است، قبلاً به موارد زیر پاسخ می‌دهد. بررسی سلامت، به این معنی که می توانیم ترافیک را به آنجا ارسال کنیم.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

آنچه اکنون در مورد آن صحبت می کنم، تست های آمادگی/زندگی در Kubernetes نام دارد؛ بر این اساس، تست های آمادگی ما مسئول در دسترس بودن برنامه در تعادل هستند. یعنی اگر تست های آمادگی در برنامه انجام شود، همه چیز اوکی است، ترافیک مشتری به سمت برنامه می رود. اگر تست های آمادگی انجام نشود، برنامه به سادگی شرکت نمی کند، این نمونه خاص در تعادل شرکت نمی کند، از تعادل حذف می شود، ترافیک مشتری جریان نمی یابد. بر این اساس، تست Liveness در Kubernetes مورد نیاز است تا در صورت گیرکردن برنامه، بتوان آن را مجددا راه اندازی کرد. اگر تست زنده بودن برای برنامه‌ای که در Kubernetes اعلام شده است کار نکند، برنامه نه تنها از حالت تعادل حذف می‌شود، بلکه دوباره راه‌اندازی می‌شود.

و در اینجا یک نکته مهم وجود دارد که می خواهم به آن اشاره کنم: از نظر عملی معمولاً از آزمون آمادگی بیشتر استفاده می شود و بیشتر از آزمون زنده بودن مورد نیاز است. یعنی به سادگی اعلام آمادگی و سرزندگی بدون فکر، زیرا Kubernetes می تواند این کار را انجام دهد، و بیایید از هر کاری که می تواند انجام دهد استفاده کنیم، ایده خیلی خوبی نیست. من توضیح می دهم که چرا. زیرا نکته شماره دو در آزمایش این است که ایده خوبی است که خدمات اساسی را در بررسی های سلامت خود بررسی کنید. این بدان معنی است که اگر یک برنامه وب دارید که اطلاعاتی را ارائه می دهد، که به نوبه خود، طبیعتاً باید از جایی دریافت کند. به عنوان مثال در یک پایگاه داده. خوب، اطلاعاتی را که به این API REST وارد می شود در همان پایگاه داده ذخیره می کند. سپس، بر این اساس، اگر Healthcheck شما به سادگی مانند slashhealth تماس داده شده پاسخ دهد، برنامه می گوید "200، اوکی، همه چیز خوب است" و در همان زمان پایگاه داده برنامه شما غیرقابل دسترسی است، و برنامه Healthcheck می گوید "200، اوکی، همه چیز خوب است." ” - این یک بررسی بهداشتی بد است. این طوری نیست که باید کار کند.

یعنی درخواست شما، وقتی درخواستی به آن می رسد /health، فقط جواب نمی دهد، "200، ok"، ابتدا می رود، برای مثال، به پایگاه داده، سعی می کند به آن متصل شود، یک کار بسیار ابتدایی را در آنجا انجام می دهد، مانند انتخاب یکی، فقط بررسی می کند که آیا یک اتصال در پایگاه داده وجود دارد. پایگاه داده و می توانید از پایگاه داده استعلام بگیرید. اگر همه اینها موفقیت آمیز بود، پاسخ این است "200، خوب." اگر موفقیت آمیز نباشد، می گوید که یک خطا وجود دارد، پایگاه داده در دسترس نیست.

بنابراین، در این زمینه، من دوباره به تست های آمادگی / سرزندگی باز می گردم - چرا شما به احتمال زیاد نیاز به تست آمادگی دارید، اما تست زنده بودن زیر سوال است. زیرا اگر دقیقاً همانطور که گفتم چک های سلامت را توصیف کنید، معلوم می شود که در قسمت نمونه موجود نیست.в или со всех instanceبه عنوان مثال در یک پایگاه داده هنگامی که شما یک تست آمادگی را اعلام کردید، بررسی های سلامت ما شروع به شکست کردند، و بر این اساس، تمام برنامه هایی که پایگاه داده از آنها در دسترس نیست، به سادگی از تعادل خارج می شوند و در واقع در حالت نادیده گرفته شده "هنگ می زنند" و منتظر می مانند تا پایگاه داده های آنها به حالت عادی برسند. کار کردن

اگر تست زنده بودن را اعلام کرده‌ایم، تصور کنید، پایگاه داده ما خراب شده است، و در Kubernetes شما نیمی از همه چیز شروع به راه‌اندازی مجدد می‌کند زیرا تست زنده‌گی ناموفق است. این بدان معنی است که شما باید راه اندازی مجدد کنید. این اصلاً آن چیزی نیست که شما می خواهید، من حتی در عمل تجربه شخصی داشتم. ما یک برنامه چت داشتیم که با JS نوشته شده بود و در پایگاه داده Mongo تغذیه می شد. و مشکل این بود که در ابتدای کار من با Kubernetes بود، ما آمادگی، زنده بودن تست ها را بر اساس این اصل که Kubernetes می تواند آن را انجام دهد، توضیح دادیم، بنابراین از آن استفاده خواهیم کرد. بر این اساس، در مقطعی مونگو کمی "خنگ" شد و نمونه شروع به شکست کرد. بر این اساس، طبق آزمایش بارندگی، غلاف ها شروع به "کشتن" کردند.

همانطور که می دانید، هنگامی که آنها "کشته می شوند"، این یک چت است، یعنی ارتباطات زیادی از مشتریان در آن آویزان است. آنها همچنین "کشته می شوند" - نه، نه مشتری، فقط ارتباطات - نه همه در یک زمان، و به دلیل این واقعیت که آنها در یک زمان کشته نمی شوند، برخی زودتر، برخی دیرتر، همزمان شروع نمی شوند. زمان. به علاوه تصادفی استاندارد، ما نمی‌توانیم هر بار زمان شروع برنامه را با دقت میلی‌ثانیه پیش‌بینی کنیم، بنابراین آن‌ها این کار را هر بار یک بار انجام می‌دهند. یک نقطه اطلاعاتی بالا می‌آید، به تعادل اضافه می‌شود، همه مشتری‌ها به آنجا می‌آیند، نمی‌تواند چنین باری را تحمل کند، زیرا تنها است و به طور کلی، ده‌ها نفر آنجا کار می‌کنند و سقوط می‌کند. بعدی بلند می شود، تمام بار بر دوش اوست، او هم می افتد. خوب، این آبشارها به آبشار ادامه می‌دهند. در پایان، چگونه این حل شد - ما فقط باید ترافیک کاربر را به این برنامه به شدت متوقف می کردیم، اجازه می دادیم همه نمونه ها افزایش یابند و سپس همه ترافیک کاربر را به یکباره شروع کنیم تا از قبل بین هر ده نمونه توزیع شده باشد.

اگر این تست زنده بودن اعلام نمی شد، که همه آن را مجبور به راه اندازی مجدد می کرد، برنامه به خوبی آن را مدیریت می کرد. اما همه چیز از متعادل کردن برای ما غیرفعال است، زیرا پایگاه‌های اطلاعاتی غیرقابل دسترسی هستند و همه کاربران «افتاده‌اند». سپس، زمانی که این پایگاه داده در دسترس قرار گرفت، همه چیز در بالانس گنجانده می شود، اما برنامه ها نیازی به شروع مجدد ندارند و نیازی به هدر دادن زمان و منابع در این مورد نیست. همه آنها در حال حاضر اینجا هستند، آنها برای ترافیک آماده هستند، بنابراین ترافیک فقط باز می شود، همه چیز خوب است - برنامه در جای خود است، همه چیز به کار خود ادامه می دهد.

بنابراین، تست های آمادگی و زنده بودن متفاوت است، حتی علاوه بر این، شما می توانید از نظر تئوری بررسی های سلامتی مختلفی انجام دهید، مثلا یک نوع شعاع، یک نوع liv و موارد مختلف را بررسی کنید. در طول تست های آمادگی، پشتیبان های خود را بررسی کنید. و به عنوان مثال، در یک تست زنده بودن، از این نقطه نظر بررسی نمی کنید که تست زنده بودن معمولاً فقط یک برنامه کاربردی است که پاسخ می دهد، اگر اصلاً بتواند پاسخ دهد.

زیرا آزمایش سرزندگی، به طور کلی، زمانی است که ما "گیر" کرده ایم. یک حلقه بی پایان شروع شده است یا چیز دیگری - و هیچ درخواست دیگری پردازش نمی شود. بنابراین، منطقی است که آنها را حتی از هم جدا کنیم - و منطق متفاوتی را در آنها پیاده کنیم.

در مورد آنچه که باید هنگام آزمایش، هنگام انجام بررسی های سلامت پاسخ دهید. فقط واقعا درد داره کسانی که با این آشنا هستند احتمالاً خواهند خندید - اما به طور جدی، من خدماتی را در زندگی خود دیده ام که در 200٪ موارد به "XNUMX" پاسخ می دهند. یعنی چه کسی موفق است. اما در همان زمان در متن پاسخ می نویسند "خطا فلان".

یعنی وضعیت پاسخ به شما می رسد - همه چیز موفقیت آمیز است. اما در همان زمان، باید بدن را تجزیه کنید، زیرا بدن می گوید "متاسفم، درخواست با خطا به پایان رسید" و این فقط واقعیت است. من این را در زندگی واقعی دیدم.

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

اگر همه چیز خوب پیش رفت، با جواب دو صدم پاسخ دهید. در اصل، هر پاسخ دو صدم برای شما مناسب است. اگر راگسی را خیلی خوب می خوانید و می دانید که برخی از وضعیت های پاسخ با بقیه متفاوت است، با موارد مناسب پاسخ دهید: 204، 5، 10، 15، هر چه باشد. اگر خیلی خوب نیست، فقط «دو صفر صفر» است. اگر همه چیز بد شد و چک سلامت جواب نداد، با هر پانصدم جواب دهید. باز هم، اگر می دانید که چگونه باید پاسخ دهید، وضعیت های مختلف پاسخ چقدر با یکدیگر متفاوت هستند. اگر متوجه نمی‌شوید، 502 گزینه شما برای پاسخ به بررسی‌های سلامت در صورت بروز مشکل است.

این یک نکته دیگر است، من می خواهم کمی در مورد بررسی خدمات زیربنایی برگردم. برای مثال، اگر شروع به بررسی همه سرویس‌های زیربنایی کنید که پشت برنامه شما قرار دارند - همه چیز به طور کلی. آنچه ما از نقطه نظر معماری میکروسرویس دریافت می کنیم، مفهومی به عنوان "اتصال کم" داریم - یعنی زمانی که خدمات شما حداقل به یکدیگر وابسته هستند. اگر یکی از آنها شکست بخورد، بقیه بدون این قابلیت به سادگی به کار خود ادامه می دهند. برخی از عملکردها کار نمی کنند. بر این اساس، اگر همه چک‌های سلامت را به یکدیگر گره بزنید، در نهایت با یک چیز در زیرساخت شکست خواهید خورد، و چون سقوط کرد، همه بررسی‌های سلامت همه خدمات نیز شروع به شکست می‌کنند - و به طور کلی زیرساخت‌های بیشتری برای کل معماری میکروسرویس شماره همه چیز آنجا تاریک شد.

بنابراین، من می خواهم دوباره این را تکرار کنم که باید خدمات زیربنایی را بررسی کنید، خدماتی که بدون آنها برنامه شما در صد در صد موارد نمی تواند کار خود را انجام دهد. یعنی منطقی است که اگر یک REST API دارید که کاربر از طریق آن در پایگاه داده ذخیره می کند یا از پایگاه داده بازیابی می کند، در صورت عدم وجود پایگاه داده، نمی توانید کار با کاربران خود را تضمین کنید.

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

بعد، ما همچنین یکی از مشکلات دردناک را هنگام راه اندازی برنامه ها داریم.

در واقع، این فقط به طور کلی در مورد Kubernetes صدق نمی کند؛ اتفاقاً این اتفاق افتاد که فرهنگ نوعی توسعه انبوه و به طور خاص DevOps تقریباً همزمان با Kubernetes شروع به گسترش کرد. بنابراین، به طور کلی، به نظر می رسد که شما باید برنامه خود را بدون کوبرنتس به آرامی خاموش کنید. حتی قبل از Kubernetes، مردم این کار را می کردند، اما با ظهور Kubernetes، ما شروع به صحبت در مورد آن کردیم.

خاموش شدن برازنده

به طور کلی، Graceful Shutdown چیست و چرا به آن نیاز است؟ این در مورد زمانی است که برنامه شما به دلایلی از کار می افتد، باید این کار را انجام دهید app stop - یا مثلاً سیگنالی از سیستم عامل دریافت می کنید، برنامه شما باید آن را بفهمد و کاری در مورد آن انجام دهد. بدترین حالت، البته، زمانی است که برنامه شما یک SIGTERM دریافت کند و مانند "SIGTERM، بیایید ادامه دهیم، کار کنیم، هیچ کاری نکنیم." این یک گزینه کاملاً بد است.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

یک گزینه تقریباً به همان اندازه بد زمانی است که برنامه شما یک SIGTERM دریافت می کند و مانند "آنها گفتند segterm، یعنی ما در حال پایان هستیم، من ندیده ام، من هیچ درخواست کاربر را نمی دانم، نمی دانم چه نوع درخواست‌هایی که در حال حاضر روی آنها کار می‌کنم، گفتند SIGTERM، این بدان معناست که ما در حال پایان هستیم. این هم گزینه بدی است.

کدام گزینه خوب است؟ اولین نکته در نظر گرفتن اتمام عملیات است. یک گزینه خوب این است که سرور شما همچنان در صورت دریافت SIGTERM کارهایی که انجام می دهد را در نظر بگیرد.

SIGTERM یک خاموشی نرم است، به طور خاص طراحی شده است، می توان آن را در سطح کد رهگیری کرد، می توان آن را پردازش کرد، بگویید که حالا صبر کنید، ابتدا کاری را که داریم تمام می کنیم، سپس خارج می شویم.

از دیدگاه Kubernetes، این چیزی است که به نظر می رسد. وقتی به یک پاد که در یک خوشه Kubernetes در حال اجرا است، می گوییم «لطفا متوقف شو، برو کنار»، یا راه اندازی مجدد رخ می دهد، یا زمانی که Kubernetes پادها را دوباره ایجاد می کند، به روز رسانی رخ می دهد، Kubernetes فقط همان پیام SIGTERM را به pod ارسال می کند، منتظر می ماند مدتی است، و این زمانی است که او منتظر می شود، همچنین پیکربندی شده است، چنین پارامتر خاصی در مدارک تحصیلی وجود دارد و به آن Graceful ShutdownTimeout می گویند. همانطور که می‌دانید، بیهوده به آن گفته نمی‌شود، و بیهوده نیست که اکنون در مورد آن صحبت می‌کنیم.

در آنجا می‌توانیم به طور مشخص بگوییم که چه مدت باید بین زمانی که SIGTERM را به برنامه ارسال می‌کنیم و زمانی که متوجه شدیم که برنامه برای چیزی دیوانه شده است یا "گیر" کرده است و قرار نیست به پایان برسد چقدر صبر کنیم - و ما باید SIGKILL را بفرستید، یعنی به سختی کارش را کامل کنید. یعنی، بر این اساس، ما نوعی دیمون در حال اجرا داریم، عملیات را پردازش می کند. ما می دانیم که به طور متوسط ​​عملیات ما که دیمون روی آن کار می کند بیش از 30 ثانیه در یک زمان طول نمی کشد. بر این اساس، وقتی SIGTERM می‌رسد، می‌فهمیم که دیمون ما حداکثر می‌تواند 30 ثانیه بعد از SIGTERM به پایان برسد. ما آن را مثلاً 45 ثانیه می نویسیم و می گوییم SIGTERM. پس از آن 45 ثانیه صبر می کنیم. در تئوری، در این مدت شیطان باید کار خود را به پایان می رساند و به خود پایان می داد. اما اگر ناگهان نتوانست، به این معنی است که به احتمال زیاد گیر کرده است - دیگر به طور معمول درخواست های ما را پردازش نمی کند. و در 45 ثانیه می توانید با خیال راحت، او را از پای در آورید.

و در اینجا، در واقع، حتی 2 جنبه را می توان در نظر گرفت. اولاً درک کنید که اگر درخواستی دریافت کردید، به نوعی شروع به کار با آن کرده اید و پاسخی به کاربر نداده اید، اما برای مثال SIGTERM را دریافت کرده اید. اصلاح آن و دادن پاسخ به کاربر منطقی است. این نکته شماره یک در این زمینه است. نکته شماره دو در اینجا این است که اگر برنامه خود را بنویسید، به طور کلی معماری را طوری بسازید که درخواستی برای برنامه خود دریافت کنید، سپس شروع به کار کنید، شروع به دانلود فایل ها از جایی، دانلود پایگاه داده و غیره کنید. که به طور کلی، کاربر شما، درخواست شما به مدت نیم ساعت معلق است و منتظر است تا به او پاسخ دهید - سپس، به احتمال زیاد، باید روی معماری کار کنید. یعنی حتی عقل سلیم را در نظر بگیرید که اگر عملیات شما کوتاه است، منطقی است که SIGTERM را نادیده بگیرید و آن را اصلاح کنید. اگر عملیات شما طولانی است، نادیده گرفتن SIGTERM در این مورد منطقی نیست. طراحی مجدد معماری برای جلوگیری از چنین عملیات طولانی منطقی است. به طوری که کاربران فقط دور و بر و منتظر نباشند. من نمی دانم، یک نوع وب سوکت درست کنید، قلاب های معکوس ایجاد کنید که سرور شما قبلاً برای مشتری ارسال می کند، هر چیز دیگری، اما کاربر را مجبور نکنید که نیم ساعت هنگ کند و فقط یک جلسه صبر کنید تا شما به او پاسخ دهید زیرا قابل پیش بینی نیست که کجا ممکن است شکسته شود.

هنگامی که برنامه شما خاتمه می یابد، باید کد خروج مناسب را ارائه دهید. یعنی اگر از برنامه شما خواسته شد بسته شود، متوقف شود و به طور معمول توانست خود را متوقف کند، دیگر نیازی به بازگرداندن کد خروجی 1,5,255 و غیره ندارید. هر چیزی که کد صفر نباشد، حداقل در سیستم های لینوکس، من از این مطمئن هستم، ناموفق تلقی می شود. یعنی در نظر گرفته می شود که درخواست شما در این مورد با خطا تمام شده است. بر این اساس، به صورت دوستانه، اگر درخواست شما بدون خطا تکمیل شود، روی خروجی 0 می گویید. اگر برنامه شما به دلایلی با شکست مواجه شود، در خروجی می گویید non-0. و شما می توانید با این اطلاعات کار کنید.

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

هنگامی که توسعه دهندگان برخی از چت های معمولی نمی دانند که، به نظر می رسد، سوکت وب می تواند خراب شود. برای آنها، وقتی چیزی در پروکسی اتفاق می افتد، ما فقط پیکربندی را تغییر می دهیم و دوباره بارگذاری می شود. طبیعتاً تمام جلسات طولانی مدت در این مورد پاره می شود. توسعه دهندگان به سمت ما می آیند و می گویند: "بچه ها، چه کار می کنید، چت برای همه مشتریان ما خراب شده است!" به آنها می گوییم: «شما چه کار می کنید؟ آیا مشتریان شما قادر به اتصال مجدد نیستند؟ می گویند: نه، ما نیاز داریم که جلسات پاره نشود. به طور خلاصه، این در واقع مزخرف است. طرف مشتری باید در نظر گرفته شود. به خصوص، همانطور که گفتم، با جلسات طولانی مدت مانند وب سوکت ها، می تواند خراب شود و بدون توجه کاربر، باید بتوانید چنین جلساتی را دوباره نصب کنید. و سپس همه چیز عالی است.

منابع

در واقع، در اینجا من فقط یک داستان مستقیم را برای شما تعریف می کنم. باز هم از زندگی واقعی بدترین چیزی که تا به حال در مورد منابع شنیده ام.

منابع در این مورد، منظورم نوعی درخواست، محدودیت‌هایی است که می‌توانید روی پادها در خوشه‌های Kubernetes خود قرار دهید. خنده دارترین چیزی که از یک توسعه دهنده شنیدم... یکی از توسعه دهندگان همکار من در محل کار قبلی یک بار گفت: "برنامه من در کلاستر شروع نمی شود." نگاه کردم ببینم شروع نمی‌شود، اما یا در منابع نمی گنجد، یا محدودیت‌های بسیار کوچکی تعیین کرده‌اند. به طور خلاصه، برنامه به دلیل منابع نمی تواند شروع شود. من می گویم: "به دلیل منابع شروع نمی شود، شما تصمیم می گیرید که چقدر نیاز دارید و مقدار کافی را تعیین کنید." می گوید: چه نوع منابعی؟ شروع کردم به توضیح دادن به او که Kubernetes، محدودیت در درخواست ها و blah, blah, blah باید تعیین شود. مرد به مدت پنج دقیقه گوش داد، سر تکان داد و گفت: «من به اینجا آمدم تا به عنوان یک توسعه دهنده کار کنم، نمی خواهم چیزی در مورد هیچ منبعی بدانم. من اینجا آمدم تا کد بنویسم و ​​تمام.» آن غم انگیز است. این یک مفهوم بسیار غم انگیز از دیدگاه یک توسعه دهنده است. به خصوص در دنیای مدرن، به اصطلاح، توسعه‌های مترقی.

اصلاً چرا منابع مورد نیاز است؟ 2 نوع منبع در Kubernetes وجود دارد. برخی را درخواست و برخی دیگر را محدودیت می نامند. با استفاده از منابع خواهیم فهمید که اساساً همیشه فقط دو محدودیت اساسی وجود دارد. یعنی محدودیت های زمانی CPU و محدودیت های RAM برای کانتینری که در Kubernetes اجرا می شود.

یک محدودیت، محدودیت بالایی در مورد نحوه استفاده از یک منبع در برنامه شما ایجاد می کند. یعنی بر این اساس، اگر در محدودیت ها بگویید 1 گیگابایت رم، برنامه شما نمی تواند بیش از 1 گیگابایت رم استفاده کند. و اگر او به طور ناگهانی بخواهد و سعی کند این کار را انجام دهد، آنگاه فرآیندی به نام oom killer، از حافظه خارج می شود، یعنی می آید و برنامه شما را می کشد - یعنی به سادگی دوباره راه اندازی می شود. برنامه ها بر اساس CPU راه اندازی مجدد نمی شوند. از نظر CPU، اگر یک برنامه سعی کند بیشتر از حد مشخص شده در محدودیت ها استفاده کند، CPU به سادگی انتخاب می شود. این منجر به راه اندازی مجدد نمی شود. این حد است - این حد بالایی است.

و یک درخواست وجود دارد. یک درخواست این است که چگونه Kubernetes بفهمد که چگونه گره‌های خوشه Kubernetes شما با برنامه‌ها پر شده‌اند. یعنی درخواست نوعی تعهد اپلیکیشن شماست. آنچه را که می‌خواهم استفاده کنم می‌گوید: «می‌خواهم این مقدار CPU و این مقدار حافظه را برای من رزرو کنید.» چنین تشبیه ساده ای. اگر گره ای داشته باشیم که در مجموع 8 CPU داشته باشد، نمی دانم. و یک پاد به آنجا می رسد که درخواست هایش 1 CPU است، یعنی گره 7 CPU باقی مانده است. یعنی به محض رسیدن 8 پاد به این گره که هرکدام 1 سی پی یو در درخواست های خود دارند، گره انگار از نظر کوبرنتیس سی پی یو تمام شده است و پادهای بیشتری با درخواست نمی توانند باشند. روی این گره راه اندازی شد. اگر CPU تمام گره ها تمام شود، Kubernetes شروع به گفتن می کند که هیچ گره مناسبی در خوشه برای اجرای پادهای شما وجود ندارد زیرا CPU تمام شده است.

چرا درخواست ها مورد نیاز است و چرا بدون درخواست، فکر می کنم نیازی به راه اندازی چیزی در Kubernetes نیست؟ بیایید یک موقعیت فرضی را تصور کنیم. شما برنامه خود را بدون درخواست راه اندازی می کنید، Kubernetes نمی داند چه مقدار از آنچه دارید، به چه گره هایی می توانید آن را فشار دهید. خوب، او به گره ها فشار می دهد، هل می دهد، هل می دهد. در برخی موارد، شما شروع به جذب ترافیک به برنامه خود خواهید کرد. و یکی از برنامه ها به طور ناگهانی شروع به استفاده از منابع تا حدی که با توجه به محدودیت ها دارد می کند. به نظر می رسد که برنامه دیگری در این نزدیکی وجود دارد و همچنین به منابع نیاز دارد. گره در واقع شروع به تمام شدن منابع فیزیکی می کند، به عنوان مثال، OP. گره در واقع شروع به خالی شدن فیزیکی از منابع، به عنوان مثال، حافظه دسترسی تصادفی (RAM) می کند. هنگامی که یک گره تمام می شود، اول از همه داکر پاسخ نمی دهد، سپس cubelet و سپس سیستم عامل. آنها به سادگی بیهوش خواهند شد و قطعاً همه چیز برای شما کار نخواهد کرد. یعنی این باعث می شود که گره شما گیر کند و باید آن را دوباره راه اندازی کنید. خلاصه اوضاع خیلی خوب نیست.

و هنگامی که درخواست دارید، محدودیت ها خیلی متفاوت نیستند، حداقل چندین برابر محدودیت ها یا درخواست ها نیستند، در این صورت می توانید چنین پر کردن نرمال و منطقی برنامه ها در سراسر گره های خوشه های Kubernetes داشته باشید. در همان زمان، Kubernetes تقریباً از چه مقدار از آنچه در کجا قرار می دهد، چه مقدار از چه چیزی در کجا استفاده می شود آگاه است. یعنی دقیقاً چنین لحظه ای است. درک آن مهم است. و مهم است که کنترل کنید که این نشان داده شود.

ذخیره سازی داده ها

نکته بعدی ما در مورد ذخیره سازی اطلاعات است. با آنها و به طور کلی، با پایداری در Kubernetes چه باید کرد؟

من فکر می کنم، دوباره، در درون ما مدرسه عصرانه، موضوعی در مورد پایگاه داده در Kubernetes وجود داشت. و به نظر من حتی تقریباً می دانم که همکاران شما وقتی از شما پرسیدند: "آیا امکان اجرای یک پایگاه داده در Kubernetes وجود دارد؟" بنا به دلایلی، به نظر من، همکاران شما باید به شما می‌گفتند که اگر این سوال را می‌پرسید که آیا امکان اجرای یک پایگاه داده در Kubernetes وجود دارد، غیرممکن است.

منطق اینجا ساده است. در هر صورت، من یک بار دیگر توضیح خواهم داد، اگر شما واقعاً مرد باحالی هستید که می‌توانید یک سیستم نسبتاً مقاوم در برابر خطا از فضای ذخیره‌سازی شبکه توزیع شده بسازید، بدانید که چگونه یک پایگاه داده را در این مورد قرار دهید، چگونه ابر بومی در کانتینرها باید کار کند. به طور کلی در یک پایگاه داده به احتمال زیاد، شما هیچ سوالی در مورد نحوه اجرای آن ندارید. اگر چنین سوالی دارید، و می‌خواهید مطمئن شوید که همه چیز آشکار می‌شود و تا حد مرگ در تولید می‌ماند و هرگز سقوط نمی‌کند، این اتفاق نمی‌افتد. مطمئناً با این روش به پای خود شلیک خواهید کرد. پس بهتر است این کار را نکنید.

مثلاً با داده‌هایی که برنامه ما می‌خواهد ذخیره کند، برخی از تصاویری که کاربران آپلود می‌کنند، برخی چیزهایی که برنامه ما در حین کار خود تولید می‌کند، مثلاً در هنگام راه‌اندازی، چه کنیم؟ در Kubernetes با آنها چه کنیم؟

به طور کلی، در حالت ایده آل، بله، البته، Kubernetes بسیار خوب طراحی شده است و به طور کلی در ابتدا برای برنامه های کاربردی بدون کشور طراحی شده است. یعنی برای آن دسته از برنامه هایی که اصلا اطلاعات را ذخیره نمی کنند. این ایده آل است.

اما، البته، گزینه ایده آل همیشه وجود ندارد. پس چی؟ اولین و ساده ترین نکته این است که یک نوع S3 را تهیه کنید، فقط یک نوع خانگی نیست، که نحوه کار آن نیز مشخص نیست، بلکه از یک ارائه دهنده است. یک ارائه دهنده خوب و معمولی - و استفاده از S3 را به برنامه خود آموزش دهید. یعنی وقتی کاربر شما می‌خواهد فایلی را آپلود کند، بگویید «اینجا، لطفاً آن را در S3 آپلود کنید». وقتی می‌خواهد آن را دریافت کند، بگویید: "اینم یک پیوند به S3 و از اینجا بگیرید." این ایده آل است.

اگر ناگهان به دلایلی این گزینه ایده آل مناسب نیست، برنامه ای دارید که ننوشته اید، توسعه نداده اید، یا نوعی میراث وحشتناک است، نمی تواند از پروتکل S3 استفاده کند، اما باید با دایرکتوری های محلی کار کند. پوشه های محلی چیزی کم و بیش ساده را در نظر بگیرید، Kubernetes را مستقر کنید. به نظر من، شمشیربازی فوری Ceph برای چند کار حداقلی، ایده بدی است. چون Ceph البته خوب و شیک است. اما اگر واقعاً نمی‌دانید چه کار می‌کنید، پس از اینکه چیزی را روی Ceph قرار دادید، می‌توانید خیلی راحت و به سادگی دیگر آن را از آنجا خارج نکنید. زیرا همانطور که می دانید Ceph داده ها را در کلاستر خود به صورت باینری ذخیره می کند و نه به صورت فایل های ساده. بنابراین، اگر به طور ناگهانی خوشه Ceph خراب شود، این احتمال وجود دارد که دیگر هرگز اطلاعات خود را از آنجا دریافت نکنید.

ما یک دوره آموزشی در مورد Ceph خواهیم داشت، شما می توانید با برنامه آشنا شوید و درخواست ارسال کنید.

بنابراین، بهتر است کاری ساده مانند سرور NFS انجام دهید. Kubernetes می‌تواند با آنها کار کند، می‌توانید دایرکتوری را تحت یک سرور NFS نصب کنید - برنامه شما دقیقاً مانند یک فهرست محلی است. در عین حال، به طور طبیعی، شما باید درک کنید که، دوباره، باید کاری با NFS خود انجام دهید، باید بدانید که گاهی اوقات ممکن است غیر قابل دسترس شود و این سوال را در نظر بگیرید که در این مورد چه خواهید کرد. شاید باید در جایی روی یک دستگاه جداگانه بک آپ گرفته شود.

نکته بعدی که من در مورد آن صحبت کردم این است که اگر برنامه شما در حین کار چند فایل تولید کند چه باید کرد. به عنوان مثال، هنگامی که شروع می شود، یک فایل ثابت تولید می کند که بر اساس اطلاعاتی است که برنامه فقط در زمان راه اندازی دریافت می کند. چه لحظه ای اگر چنین داده‌ای زیادی وجود ندارد، پس اصلاً نیازی به زحمت نیست، فقط این برنامه را برای خود نصب کنید و کار کنید. تنها سوال اینجاست که چه، نگاه کنید. اغلب، انواع سیستم های قدیمی، مانند وردپرس و غیره، به ویژه با برخی از پلاگین های هوشمند اصلاح شده، توسعه دهندگان باهوش PHP، اغلب می دانند چگونه آن را طوری بسازند که نوعی فایل برای خود تولید کنند. بر این اساس، یکی یک فایل تولید می کند، دومی یک فایل دوم تولید می کند. آنها متفاوتند. تعادل در خوشه Kubernetes مشتریان به سادگی به طور تصادفی اتفاق می افتد. بر این اساس، معلوم می شود که آنها به عنوان مثال نمی دانند چگونه با هم کار کنند. یکی اطلاعاتی را می دهد و دیگری اطلاعات دیگری را به کاربر می دهد. این چیزی است که باید از آن اجتناب کنید. یعنی در Kubernetes، هر چیزی که راه‌اندازی می‌کنید تضمین می‌شود که بتواند در چندین نمونه کار کند. زیرا Kubernetes یک چیز متحرک است. بر این اساس، او می تواند هر زمان که بخواهد، بدون اینکه از کسی بخواهد، هر چیزی را جابجا کند. بنابراین، شما باید روی این موضوع حساب کنید. هر چیزی که در یک نمونه راه اندازی می شود دیر یا زود شکست می خورد. هرچه رزرو بیشتری داشته باشید، بهتر است. ولی بازم میگم اگه چندتا فایل از این دست داری پس میتونی زیر خودت بذاری، وزنشون کمه. اگر تعداد آنها کمی بیشتر است، احتمالاً نباید آنها را داخل ظرف فشار دهید.

من توصیه می کنم که چنین چیز شگفت انگیزی در Kubernetes وجود دارد، می توانید از حجم استفاده کنید. به طور خاص، یک حجم از نوع خالی dir وجود دارد. به این معنی که Kubernetes به طور خودکار یک دایرکتوری را در دایرکتوری های سرویس خود در سروری که شروع کرده اید ایجاد می کند. و به شما می دهد تا از آن استفاده کنید. فقط یک نکته مهم وجود دارد. یعنی اطلاعات شما در داخل کانتینر ذخیره نمی شود، بلکه در میزبانی که روی آن اجرا می کنید ذخیره می شود. علاوه بر این، Kubernetes می تواند چنین تیرهای خالی را تحت پیکربندی معمولی کنترل کند و می تواند حداکثر اندازه آنها را کنترل کند و اجازه نمی دهد از آن فراتر رود. تنها نکته این است که آنچه در dir خالی نوشته اید در هنگام راه اندازی مجدد پاد از بین نمی رود. یعنی اگر غلاف شما به اشتباه بیفتد و دوباره بالا بیاید، اطلاعات داخل dir خالی به جایی نمی رسد. او می‌تواند در شروع جدید دوباره از آن استفاده کند - و این خوب است. اگر غلاف شما جایی را ترک کند، طبیعتاً او بدون داده خواهد رفت. یعنی به محض ناپدید شدن پاد از گره ای که با dir خالی راه اندازی شده بود، dir خالی حذف می شود.

چه چیز دیگری در مورد فیلم خالی است؟ برای مثال می توان از آن به عنوان کش استفاده کرد. بیایید تصور کنیم که برنامه ما چیزی را در پرواز تولید می کند، آن را به کاربران می دهد و آن را برای مدت طولانی انجام می دهد. بنابراین، برنامه، به عنوان مثال، آن را تولید می کند و در اختیار کاربران قرار می دهد و در عین حال آن را در جایی ذخیره می کند، تا دفعه بعد که کاربر برای همان مورد مراجعه می کند، سریعتر آن را بلافاصله تولید می کند. Empty dir را می توان از Kubernetes درخواست کرد تا در حافظه ایجاد کند. و بنابراین، حافظه پنهان شما به طور کلی می تواند با سرعت رعد و برق کار کند - از نظر سرعت دسترسی به دیسک. یعنی شما یک dir خالی در حافظه دارید، در سیستم عامل در حافظه ذخیره می شود، اما برای شما، برای کاربر داخل پاد، فقط یک فهرست محلی به نظر می رسد. شما نیازی به برنامه ندارید تا به طور خاص هر جادویی را آموزش دهید. شما فقط فایل خود را مستقیماً می گیرید و در یک دایرکتوری قرار می دهید، اما در واقع، در حافظه روی سیستم عامل. این نیز از نظر Kubernetes یک ویژگی بسیار راحت است.

Minio چه مشکلاتی دارد؟ مشکل اصلی Minio این است که برای اینکه این چیز کار کند باید در جایی اجرا شود و یک نوع فایل سیستم یعنی ذخیره سازی وجود داشته باشد. و در اینجا با همان مشکلاتی که Ceph دارد مواجه می شویم. یعنی Minio باید فایل هایش را در جایی ذخیره کند. این به سادگی یک رابط HTTP برای فایل های شما است. علاوه بر این، عملکرد به وضوح ضعیف تر از S3 آمازون است. قبلاً نمی توانست به درستی به کاربر مجوز دهد. در حال حاضر، تا آنجا که من می دانم، در حال حاضر می تواند سطل هایی با مجوزهای مختلف ایجاد کند، اما باز هم، به نظر من، مشکل اصلی، حداقل سیستم ذخیره سازی زیربنایی است.

Empty dir در حافظه چگونه بر محدودیت ها تأثیر می گذارد؟ به هیچ وجه محدودیت ها را تحت تاثیر قرار نمی دهد. در حافظه میزبان نهفته است، نه در حافظه ظرف شما. یعنی ظرف شما dir خالی در حافظه را به عنوان بخشی از حافظه اشغال شده خود نمی بیند. میزبان این را می بیند. بر این اساس، بله، از دیدگاه kubernetes، هنگامی که شما شروع به استفاده از این می کنید، بهتر است درک کنید که بخشی از حافظه خود را به تیر خالی اختصاص می دهید. و بر این اساس، درک کنید که حافظه ممکن است نه تنها به دلیل برنامه‌ها، بلکه به این دلیل که شخصی در این آدرس‌های خالی می‌نویسد تمام شود.

ابری بودن

و آخرین موضوع فرعی این است که Cloudnative چیست. چرا نیاز است؟ ابری بودن و غیره.

یعنی آن دسته از اپلیکیشن هایی که قادر و نوشته شده اند تا در زیرساخت ابری مدرن کار کنند. اما در واقع، Cloudnative جنبه دیگری نیز دارد. اینکه این نه تنها یک برنامه کاربردی است که تمام الزامات یک زیرساخت ابری مدرن را در نظر می گیرد، بلکه می داند چگونه با این زیرساخت ابری مدرن کار کند، از مزایا و معایب این واقعیت که در این ابرها کار می کند استفاده کند. فقط در فضای ابری کار نکنید، بلکه از مزایای کار در فضای ابری استفاده کنید.

الزامات برای توسعه یک برنامه کاربردی در Kubernetes

بیایید فقط Kubernetes را به عنوان مثال در نظر بگیریم. برنامه شما در Kubernetes در حال اجرا است. برنامه شما همیشه یا بهتر است بگوییم ادمین های برنامه شما می توانند همیشه یک حساب سرویس ایجاد کنند. یعنی یک حساب برای مجوز در خود Kubernetes در سرور آن. برخی از حقوقی را که به آن نیاز داریم اضافه کنید. و می توانید از داخل برنامه خود به Kubernetes دسترسی داشته باشید. چه کاری می توانید به این روش انجام دهید؟ به عنوان مثال، از برنامه، داده‌هایی را در مورد محل قرارگیری سایر برنامه‌های کاربردی خود، سایر نمونه‌های مشابه دریافت کنید، و در صورت وجود چنین نیازی، به نوعی در بالای Kubernetes قرار بگیرید.

باز هم اخیراً به معنای واقعی کلمه موردی داشتیم. ما یک کنترلر داریم که صف را نظارت می کند. و هنگامی که برخی از وظایف جدید در این صف ظاهر می شود، به Kubernetes می رود - و در Kubernetes یک pod جدید ایجاد می کند. به این پاد یک کار جدید می دهد و در چارچوب این پاد، پاد وظیفه را انجام می دهد، پاسخی را برای خود کنترلر ارسال می کند و سپس کنترلر با این اطلاعات کاری انجام می دهد. به عنوان مثال، یک پایگاه داده را اضافه می کند. یعنی، دوباره، این یک نکته مثبت از این واقعیت است که برنامه ما در Kubernetes اجرا می شود. ما می‌توانیم از خود عملکرد داخلی Kubernetes استفاده کنیم تا به نحوی کارکرد برنامه خود را گسترش دهیم و راحت‌تر کنیم. یعنی نوعی جادو را در مورد نحوه راه اندازی یک برنامه، نحوه راه اندازی یک کارگر پنهان نکنید. در Kubernetes، اگر برنامه به زبان پایتون نوشته شده باشد، به سادگی درخواستی را در برنامه ارسال می کنید.

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

در مورد مقیاس بندی هم همینطور. Kubernetes معمولی می تواند با ارائه دهندگان ابر ادغام شود. می داند که چگونه بفهمد که اگر گره های خوشه تمام شود، یعنی فضای گره تمام شده است، باید اضافه کنید - خود Kubernetes گره های جدیدی را به خوشه شما اضافه می کند و شروع به راه اندازی غلاف روی آنها می کند. یعنی وقتی بار شما می آید تعداد اجاق ها شروع به زیاد شدن می کند. وقتی گره‌های خوشه برای این غلاف‌ها تمام می‌شوند، Kubernetes گره‌های جدیدی راه‌اندازی می‌کند و بر این اساس، تعداد غلاف‌ها همچنان می‌تواند افزایش یابد. و بسیار راحت است. این یک فرصت مستقیم برای مقیاس بندی خوشه در پرواز است. خیلی سریع نیست، به این معنا که یک ثانیه نیست، بیشتر شبیه یک دقیقه است تا گره های جدید اضافه شود.

اما با توجه به تجربه من، دوباره، این جالب ترین چیزی است که تا به حال دیده ام. وقتی خوشه Cloudnative بر اساس زمان روز مقیاس شد. این یک سرویس پشتیبان بود که توسط افراد در دفتر پشتی استفاده می شد. یعنی ساعت 9 صبح سر کار می آیند، شروع به ورود به سیستم می کنند، و بر این اساس، کلاستر Cloudnative، جایی که همه چیز در حال اجراست، شروع به متورم شدن می کند و پادهای جدیدی راه اندازی می کند تا همه کسانی که سر کار می آیند بتوانند با برنامه کار کنند. هنگامی که آنها کار را در ساعت 8 بعد از ظهر یا 6 بعد از ظهر ترک می کنند، خوشه های Kubernetes متوجه می شوند که هیچ کس دیگر از برنامه استفاده نمی کند و شروع به کوچک شدن می کنند. پس انداز تا 30 درصد تضمین شده است. در آن زمان در آمازون کار می کرد؛ در آن زمان هیچ کس در روسیه نبود که بتواند آن را به این خوبی انجام دهد.

من صراحتاً به شما می گویم، صرفه جویی 30 درصدی صرفاً به این دلیل است که ما از Kubernetes استفاده می کنیم و از قابلیت های ابر استفاده می کنیم. اکنون می توان این کار را در روسیه انجام داد. البته برای کسی تبلیغ نمی‌کنم، اما اجازه دهید بگوییم که ارائه‌دهندگانی هستند که می‌توانند این کار را انجام دهند، آن را مستقیماً با یک دکمه ارائه دهند.

نکته آخری وجود دارد که توجه شما را نیز به آن جلب می کنم. برای اینکه برنامه شما، زیرساخت شما Cloudnative باشد، منطقی است که در نهایت رویکردی به نام زیرساخت به عنوان کد را تطبیق دهید. یعنی این به این معنی است که برنامه شما یا بهتر است بگوییم زیرساخت شما دقیقاً به همان کدی نیاز دارد که Describe your نرم افزار، منطق کسب و کار شما در قالب کد. و با آن به عنوان کد کار کنید، یعنی آن را تست کنید، آن را رول کنید، آن را در git ذخیره کنید، CICD را روی آن اعمال کنید.

و این دقیقاً همان چیزی است که به شما اجازه می دهد، اولاً، همیشه کنترل زیرساخت خود را داشته باشید، همیشه درک کنید که در چه وضعیتی است. ثانیا، از عملیات دستی که باعث خطا می شود خودداری کنید. سوم، زمانی که دائماً نیاز به انجام همان کارهای دستی دارید، صرفاً از آنچه که گردش مالی نامیده می شود اجتناب کنید. چهارم، این امکان را به شما می دهد که در صورت شکست، خیلی سریعتر بازیابی کنید. در روسیه، هر بار که در مورد این موضوع صحبت می کنم، همیشه تعداد زیادی از مردم هستند که می گویند: "بله، واضح است، اما شما رویکردهایی دارید، به طور خلاصه، نیازی به اصلاح چیزی نیست." اما این حقیقت دارد. اگر چیزی در زیرساخت شما خراب است، از دیدگاه رویکرد Cloudnative و از دیدگاه زیرساخت به عنوان یک کد، به جای اینکه آن را تعمیر کنید، به سرور بروید، بفهمید چه چیزی خراب است و آن را تعمیر کنید، آسان تر است. برای حذف سرور و ایجاد مجدد آن. و من همه اینها را بازسازی خواهم کرد.

همه این مسائل با جزئیات بیشتر در دوره های ویدیویی Kubernetes: Junior، Basic، Mega. با مراجعه به لینک می توانید با برنامه و شرایط آن آشنا شوید. نکته راحت این است که شما می توانید با مطالعه در خانه یا محل کار به مدت 1-2 ساعت در روز به Kubernetes مسلط شوید.

منبع: www.habr.com

اضافه کردن نظر