کانتینرها، میکروسرویس ها و مش های سرویس

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

من در مورد پلتفرم dotCloud صحبت خواهم کرد که بر روی بیش از صد میکروسرویس ساخته شده و از هزاران برنامه کانتینری پشتیبانی می کند. من چالش‌هایی را که در توسعه و راه‌اندازی آن با آن مواجه بودیم و اینکه چگونه مش‌های سرویس می‌توانند (یا نمی‌توانند) کمک کنند را توضیح خواهم داد.

تاریخچه dotCloud

من در مورد تاریخچه dotCloud و انتخاب های معماری برای این پلتفرم نوشته ام، اما در مورد لایه شبکه زیاد صحبت نکرده ام. اگر نمی خواهید در مطالعه غوطه ور شوید آخرین مقاله در مورد dotCloud، به طور خلاصه در اینجا خلاصه می شود: این یک پلتفرم PaaS به عنوان یک سرویس است که به مشتریان اجازه می دهد طیف گسترده ای از برنامه ها (جاوا، پی اچ پی، پایتون...) را با پشتیبانی از طیف گسترده ای از داده ها اجرا کنند. خدمات (MongoDB، MySQL، Redis...) و یک گردش کاری مانند Heroku: شما کد خود را در پلتفرم آپلود می کنید، آن تصاویر کانتینر را می سازد و آنها را مستقر می کند.

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

مسیریابی ترافیک برای برنامه های میزبانی شده

برنامه های کاربردی در dotCloud می توانند نقاط پایانی HTTP و TCP را در معرض نمایش قرار دهند.

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

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

نقاط پایانی TCP با یک شماره پورت مرتبط است، که سپس از طریق متغیرهای محیطی به همه کانتینرهای آن پشته ارسال می شود.

کلاینت ها می توانند با استفاده از نام میزبان مناسب (چیزی مانند gateway-X.dotcloud.com) و شماره پورت به نقاط پایانی TCP متصل شوند.

این نام میزبان به خوشه سرور «nats» (مربوط به NATS) که اتصالات TCP ورودی را به کانتینر صحیح (یا در مورد سرویس های متعادل بار، به کانتینرهای صحیح هدایت می کند).

اگر با Kubernetes آشنا هستید، این احتمالاً شما را به یاد سرویس ها می اندازد NodePort.

هیچ سرویس معادلی در پلتفرم dotCloud وجود نداشت ClusterIP: برای سادگی، دسترسی به خدمات هم از داخل و هم از خارج از پلتفرم یکسان بود.

همه چیز کاملاً ساده سازماندهی شده بود: پیاده سازی های اولیه شبکه های مسیریابی HTTP و TCP احتمالاً تنها چند صد خط از پایتون بودند. الگوریتم‌های ساده (من می‌توانم بگویم ساده‌لوحانه) که با رشد پلتفرم و ظهور الزامات اضافی اصلاح شدند.

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

این چه تفاوتی با مش سرویس مدرن دارد؟

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

دید نه تنها از منظر عملیاتی (برای کمک به عیب یابی مشکلات)، بلکه هنگام انتشار ویژگی های جدید مهم است. این در مورد امن است استقرار آبی-سبز и استقرار قناری.

کارایی مسیریابی نیز محدود است. در شبکه مسیریابی dotCloud، تمام ترافیک باید از طریق یک دسته از گره‌های مسیریابی اختصاصی عبور کند. این به معنای عبور بالقوه از مرزهای چندگانه AZ (منطقه در دسترس) و افزایش قابل توجه تأخیر است. کد عیب‌یابی را به خاطر می‌آورم که بیش از صد پرسش SQL در هر صفحه ایجاد می‌کرد و برای هر درخواست یک اتصال جدید به سرور SQL باز می‌کرد. هنگامی که به صورت محلی اجرا می شود، صفحه بلافاصله بارگیری می شود، اما در dotCloud چند ثانیه طول می کشد تا بارگیری شود زیرا هر اتصال TCP (و پرس و جوی SQL بعدی) ده ها میلی ثانیه طول می کشد. در این مورد خاص، اتصالات مداوم مشکل را حل کرد.

مش های سرویس مدرن در مقابله با چنین مشکلاتی بهتر هستند. اول از همه، آنها بررسی می کنند که اتصالات روت شده باشند در منبع. جریان منطقی یکسان است: клиент → меш → сервис، اما اکنون مش به صورت محلی کار می کند و روی گره های راه دور کار نمی کند، بنابراین اتصال клиент → меш محلی و بسیار سریع است (میکروثانیه به جای میلی ثانیه).

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

امنیت هم بهتر مش مسیریابی dotCloud به طور کامل روی EC2 Classic اجرا می‌شد و ترافیک را رمزگذاری نمی‌کرد (بر اساس این فرض که اگر کسی موفق شد یک sniffer را روی ترافیک شبکه EC2 قرار دهد، شما قبلاً در مشکل بزرگی قرار داشتید). مش های سرویس مدرن به طور شفاف از تمام ترافیک ما محافظت می کنند، به عنوان مثال، با احراز هویت متقابل TLS و رمزگذاری بعدی.

مسیریابی ترافیک برای خدمات پلت فرم

خوب، ما در مورد ترافیک بین برنامه ها بحث کرده ایم، اما در مورد خود پلتفرم dotCloud چطور؟

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

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

این سرویس های سطح پایین و حیاتی با اجرای کانتینرها به طور مستقیم بر روی چند گره کلیدی مستقر شدند. در این مورد، از خدمات پلتفرم استاندارد استفاده نشد: پیوند دهنده، زمانبند و رانر. اگر می‌خواهید با سکوهای کانتینری مدرن مقایسه کنید، مانند اجرای یک هواپیمای کنترلی است docker run به‌جای واگذاری کار به Kubernetes، مستقیماً روی گره‌ها. از نظر مفهومی بسیار شبیه است ماژول های استاتیک (غلاف)، که از آن استفاده می کند kubeadm یا bootkube هنگام بوت کردن یک کلاستر مستقل

این خدمات به روشی ساده و خام در معرض دید قرار گرفتند: یک فایل YAML نام و آدرس آنها را فهرست کرده بود. و هر کلاینت باید یک کپی از این فایل YAML را برای استقرار می گرفت.

از یک طرف، بسیار قابل اعتماد است زیرا نیازی به پشتیبانی از یک فروشگاه کلید/مقدار خارجی مانند Zookeeper ندارد (به یاد داشته باشید، etcd یا کنسول در آن زمان وجود نداشت). از طرفی جابه جایی سرویس ها را با مشکل مواجه می کرد. هر بار که حرکتی انجام می شد، همه مشتریان یک فایل YAML به روز شده (و احتمالاً راه اندازی مجدد) دریافت می کردند. خیلی راحت نیست!

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

(همچنین برنامه ریزی شده بود که ترافیک در اتصالات TLS کپسوله شود و سرور پروکسی دیگری در سمت دریافت کننده قرار گیرد و همچنین گواهینامه های TLS بدون مشارکت سرویس گیرنده تأیید شود که برای پذیرش اتصالات فقط در پیکربندی شده است. localhost. بیشتر در این مورد بعدا).

این بسیار شبیه است SmartStack از Airbnb، اما تفاوت قابل توجه این است که SmartStack پیاده سازی شده و به تولید می رسد، در حالی که سیستم مسیریابی داخلی dotCloud زمانی که dotCloud به Docker تبدیل شد، کنار گذاشته شد.

من شخصا SmartStack را یکی از پیشینیان سیستم‌هایی مانند Istio، Linkerd و Consul Connect می‌دانم زیرا همه آنها از یک الگو پیروی می‌کنند:

  • روی هر گره یک پروکسی اجرا کنید.
  • کلاینت ها به پروکسی متصل می شوند.
  • صفحه کنترل پیکربندی پروکسی را هنگامی که باطن تغییر می کند به روز می کند.
  • ... سود!

اجرای مدرن مش سرویس

اگر امروز نیاز به پیاده سازی یک شبکه مشابه داشتیم، می توانستیم از اصول مشابه استفاده کنیم. به عنوان مثال، با نگاشت نام سرویس ها به آدرس های موجود در فضا، یک منطقه DNS داخلی را پیکربندی کنید 127.0.0.0/8. سپس HAProxy را بر روی هر گره در خوشه اجرا کنید و اتصالات را در هر آدرس سرویس (در آن زیر شبکه 127.0.0.0/8) و تغییر مسیر/تعادل بار به باطن های مناسب. پیکربندی HAProxy را می توان کنترل کرد confd، به شما امکان می دهد اطلاعات باطن را در etcd یا Consul ذخیره کنید و به طور خودکار پیکربندی به روز شده را در صورت نیاز به HAProxy فشار دهید.

ایستیو تقریباً اینگونه عمل می کند! اما با کمی تفاوت:

  • استفاده می کند پروکسی فرستاده به جای HAProxy
  • پیکربندی backend را از طریق Kubernetes API به جای etcd یا Consul ذخیره می کند.
  • سرویس‌ها به جای 127.0.0.0/8، آدرس‌هایی را در زیرشبکه داخلی (آدرس‌های Kubernetes ClusterIP) اختصاص می‌دهند.
  • دارای یک جزء اضافی (Citadel) برای افزودن احراز هویت متقابل TLS بین مشتری و سرور.
  • پشتیبانی از ویژگی های جدید مانند قطع مدار، ردیابی توزیع شده، استقرار قناری و غیره.

بیایید نگاهی گذرا به برخی از تفاوت ها بیندازیم.

پروکسی فرستاده

Envoy Proxy توسط Lyft [رقیب اوبر در بازار تاکسی - تقریباً نوشته شده است. مسیر]. از بسیاری جهات مشابه سایر پروکسی ها است (مانند HAProxy، Nginx، Traefik...)، اما Lyft پروکسی آنها را نوشت زیرا آنها به ویژگی هایی نیاز داشتند که سایر پروکسی ها فاقد آن بودند، و به نظر می رسید که یک پروکسی جدید به جای گسترش موجود، هوشمندتر باشد.

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

اما فرستاده همچنین قادر به کار به عنوان صفحه داده (صفحه داده) برای مش سرویس. این بدان معنی است که Envoy اکنون برای این سرویس مش پیکربندی شده است کنترل هواپیما (کنترل هواپیما).

کنترل هواپیما

برای صفحه کنترل، ایستیو به API Kubernetes متکی است. این تفاوت چندانی با استفاده از confd ندارد، که برای مشاهده مجموعه کلیدها در فروشگاه داده به etcd یا Consul متکی است. Istio از Kubernetes API برای مشاهده مجموعه ای از منابع Kubernetes استفاده می کند.

بین این و بعد: من شخصا این را مفید یافتم توضیحات Kubernetes APIکه میخواند:

سرور Kubernetes API یک «سرور گنگ» است که ذخیره‌سازی، نسخه‌سازی، اعتبارسنجی، به‌روزرسانی و معناشناسی منابع API را ارائه می‌دهد.

ایستیو برای کار با Kubernetes طراحی شده است. و اگر می‌خواهید خارج از Kubernetes از آن استفاده کنید، باید نمونه‌ای از سرور API Kubernetes (و سرویس helper etcd) را اجرا کنید.

آدرس های خدمات

Istio متکی بر آدرس های ClusterIP است که Kubernetes تخصیص می دهد، بنابراین سرویس های Istio یک آدرس داخلی دریافت می کنند (نه در محدوده 127.0.0.0/8).

ترافیک به آدرس ClusterIP برای یک سرویس خاص در یک خوشه Kubernetes بدون Istio توسط kube-proxy رهگیری می‌شود و به باطن آن پراکسی ارسال می‌شود. اگر به جزئیات فنی علاقه مند هستید، kube-proxy قوانین iptables (یا متعادل کننده بار IPVS، بسته به نحوه پیکربندی آن) را تنظیم می کند تا آدرس های IP مقصد اتصالاتی را که به آدرس ClusterIP می روند، بازنویسی کند.

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

هنگامی که با Kubernetes DNS یکپارچه می شود، این بدان معنی است که کد ما می تواند با نام سرویس متصل شود و همه چیز "فقط کار می کند". به عبارت دیگر، کد ما پرس و جوهایی مانند http://api/v1/users/4242سپس api حل درخواست برای 10.97.105.48، قوانین iptables اتصالات را از 10.97.105.48 قطع می کند و آنها را به پروکسی محلی Envoy ارسال می کند و آن پراکسی محلی درخواست را به API پشتیبان واقعی ارسال می کند. اوه!

زواید اضافی

ایستیو همچنین رمزگذاری و احراز هویت از طریق mTLS (TLS متقابل) را فراهم می کند. یک جزء به نام دژ.

یک جزء نیز وجود دارد مخلوط کن، که فرستاده می تواند درخواست کند از هر کدام درخواست برای تصمیم گیری ویژه در مورد آن درخواست بسته به عوامل مختلفی مانند هدرها، بارگذاری پشتیبان و غیره... (نگران نباشید: راه های زیادی برای فعال نگه داشتن Mixer وجود دارد و حتی اگر خراب شود، Envoy به کار خود ادامه خواهد داد. خوب به عنوان یک پروکسی).

و، البته، ما به قابلیت مشاهده اشاره کردیم: Envoy در حالی که ردیابی توزیع شده را ارائه می دهد، مقدار زیادی از معیارها را جمع آوری می کند. در معماری میکروسرویس‌ها، اگر یک درخواست API منفرد باید از میکروسرویس‌های A، B، C و D عبور کند، پس از ورود، ردیابی توزیع‌شده یک شناسه منحصربه‌فرد به درخواست اضافه می‌کند و این شناسه را از طریق درخواست‌های فرعی به همه این میکروسرویس‌ها ذخیره می‌کند. همه تماس‌های مرتبط باید گرفته شود. تاخیرها و غیره

توسعه دهید یا بخرید

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

اگر نیازهای متوسطی داشته باشیم (به دید، قطع کننده مدار و سایر ظرافت ها نیاز نداریم)، ​​پس فکر می کنیم که ابزار خودمان را توسعه دهیم. اما اگر از Kubernetes استفاده کنیم، ممکن است حتی نیازی به آن نباشد، زیرا Kubernetes از قبل ابزارهای اساسی برای کشف سرویس و متعادل کردن بار ارائه می دهد.

اما اگر نیازمندی های پیشرفته ای داشته باشیم، به نظر می رسد "خرید" مش سرویس گزینه بسیار بهتری باشد. (این همیشه یک "خرید" نیست زیرا Istio منبع باز است، اما ما هنوز برای درک، استقرار و مدیریت آن نیاز به زمان مهندسی داریم.)

آیا Istio، Linkerd یا Consul Connect را انتخاب کنم؟

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

چه چیزی را انتخاب کنید؟

راستش من نمی دانم. در حال حاضر خودم را به اندازه کافی صلاحیت برای پاسخ به این سوال نمی دانم. مقدار کمی وجود دارد جالب هست مقالات با مقایسه این ابزارها و حتی معیارها.

یکی از رویکردهای امیدوارکننده استفاده از ابزاری مانند SuperGloo. این یک لایه انتزاعی را برای ساده کردن و یکپارچه کردن API های در معرض دید مش های سرویس پیاده سازی می کند. به جای یادگیری API های خاص (و به نظر من نسبتاً پیچیده) مش های مختلف سرویس، می توانیم از ساختارهای ساده تر SuperGloo استفاده کنیم - و به راحتی از یکی به دیگری تغییر مکان دهیم، گویی که یک فرمت پیکربندی میانی داریم که رابط های HTTP و باطن های قابل توصیف را توصیف می کند. ایجاد پیکربندی واقعی برای Nginx، HAProxy، Traefik، Apache...

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

منبع: www.habr.com

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