راه اندازی یک پروژه نمونه از میکروسرویسها در Asp.net Core و Docker - قسمت دوم

در قسمت قبلی سیستم آموزشگاه را با دو میکروسرویس بصورت مستقل روی داکر راه اندازی کردیم. اکنون میخواهیم سرویسها را پشت gateway قرار دهیم.دروازه یا Gateway چیست؟وقتی پروژه شما دارای بیش از یک سرویس بود و نیاز بود برای تمام سرویسها پورت یا SubDomain مجزا تعریف کنید مدیریت این آدرس ها مشکل خواهد شد. برای رفع این مشکل از یک سرویس واسطه بنام Gateway استفاده میشود که همه درخواستها به این سرویس ارسال شده و از طریق آن به دست سرویس های مقصد میرسند.مزایای استفاده از gateway:عدم نیاز به expose کردن همه سرویسها در محیط بیرونی.مجهز به load balancer برای تقسیم کردن بار بین instance های مختلف از یک سرویس.معایب استفاده از gateway:درصورت وجود load بالا و عدم وجود استراتژی مناسب برای load balancing تبدیل به bottleneck سیستم خواهد شد.درصورت fail شدن آن، همه سرویسها از دسترس خارج خواهند شد و این موضوع با اصل استقلال میکروسرویسها (هر سرویس مستقل از وضعیت سرویسهای حتی وابسته دیگر بتواند به کار خود ادامه دهد) تناقض دارد.تعریف پروژه gatewayپروژه جدیدی با نام MicroservicesOnDocker.ApiGateway از نوع Asp.net Core – Empty ایجاد میکنیم. در این نوع پروژه نیازی به اضافه کردن MVC و هیچ کنترلری به پروژه نمیباشد. پورت اجرایی این پروژه را روی 57800 تنظیم میکنیم.پکیج Ocelot را از Nuget به این پروژه اضافه میکنیم و در کلاس Startup پروژه خطوط زیر را اضافه میکنیم:public void ConfigureServices(IServiceCollection services) { ... services.AddOcelot(); ... } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ... app.UseOcelot().Wait(); }حال تنظیمات ocelot را به پروژه اضافه میکنیم. فایلی با نام ocelot.json را به پروژه اضافه میکنیم و محتویات زیر را در آن وارد میکنیم:{ &quotReRoutes&quot: [{ &quotDownstreamPathTemplate&quot: &quot/{everything}&quot, &quotDownstreamScheme&quot: &quothttp&quot, &quotDownstreamHostAndPorts&quot: [{ &quotHost&quot: &quotschool_service&quot, &quotPort&quot: 80 }], &quotUpstreamPathTemplate&quot: &quot/school/{everything}&quot, &quotUpstreamHttpMethod&quot: [ &quotGet&quot, &quotPost&quot ] }, { &quotDownstreamPathTemplate&quot: &quot/{everything}&quot, &quotDownstreamScheme&quot: &quothttp&quot, &quotDownstreamHostAndPorts&quot: [{ &quotHost&quot: &quotincome_service&quot, &quotPort&quot: 80 }], &quotUpstreamPathTemplate&quot: &quot/income/{everything}&quot, &quotUpstreamHttpMethod&quot: [ &quotGet&quot, &quotPost&quot ] }], &quotGlobalConfiguration&quot: { &quotBaseUrl&quot: &quothttp://localhost:57800&quot } }همونطور که مشاهده میکنید در قسمت ReRoutes آدرسهای هر دو سرویس ما در محیط داکر تعریف شده اند. از آنجایی که این re-routing ها فقط در مد production کار میکنند برای مد development فایل دیگری با نام ocelot.Development.json با همان محتویات بالا ولی با تفاوت های زیر اضافه میکنیم:برای سرویس اول:&quotHost&quot: &quotschool_service&quot => &quotHost&quot: &quotlocalhost&quot, &quotPort&quot: 80 => &quotPort&quot: 57801برای سرویس دوم:&quotHost&quot: &quotincome _service&quot => &quotHost&quot: &quotlocalhost&quot, &quotPort&quot: 80 => &quotPort&quot: 57802حال بررسی کنیم که در تنظیمات بالا چه چیزی گفته شده:{ &quotDownstreamPathTemplate&quot: &quot/{everything}&quot, &quotDownstreamScheme&quot: &quothttp&quot, &quotDownstreamHostAndPorts&quot: [{ &quotHost&quot: &quotschool_service&quot, &quotPort&quot: 80 }], &quotUpstreamPathTemplate&quot: &quot/school/{everything}&quot, &quotUpstreamHttpMethod&quot: [ &quotGet&quot, &quotPost&quot ] },معنی آبجکت بالا این است که به سرویس gateway هر درخواستی با فرمت UpstreamPathTemplate آمد تبدیل به درخواستی با فرمت DownstreamPathTemplate به هاست و پورتی که در DownstreamHostAndPorts تعریف شده ارسال شود. متدهایی که در UpstreamHttpMethod تعریف شده متدهای مجاز هستند و متدهای دیگر re-route نخواهند شد. و نکته دیگر اینکه به این دلیل ویژگی DownstreamHostAndPorts بصورت آرایه تعریف شده که instance های دیگری از سرویس مورد نظر قابل تعریف باشند و روی این لیست از instance ها load balancing انجام میشود.آخرین کار معرفی فایلهای تنظیمات ocelot به برنامه dotnet core میباشد که باید در کلاس Program انجام شود:public staticIWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { config .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) .AddJsonFile(&quotappsettings.json&quot, true, true) .AddJsonFile($&quotappsettings{hostingContext.HostingEnvironment.EnvironmentName}.json&quot, true, true) .AddJsonFile(&quotocelot.json&quot) .AddJsonFile($&quotocelot.{hostingContext.HostingEnvironment.EnvironmentName}.json&quot, true, true) .AddEnvironmentVariables(); }) .UseStartup<Startup>();تنظیمات gateway انجام شده و میتوانید در محیط توسعه خود آن را اجرا کنید. نحوه اجراش هم به این صورت است که باید بصورت Multiple startup projects سیستم رو اجرا کنید. مطابق تصویر زیر:پروژه را با تنظیمات پیشفرض در پوشه publish\api_gateway_\.. پابلیش کنید.برای داکر نیاز به تغییراتی در فایل docker-compose.yml داریم:version: '3' services: api_gateway: image: mcr.microsoft.com/dotnet/core/aspnet:2.2 volumes: - ./api_gateway:/app working_dir: /app command: dotnet &quotMicroservicesOnDocker.ApiGateway.dll&quot ports: - 5000:80 depends_on: - school_service - income_service school_service: image: mcr.microsoft.com/dotnet/core/aspnet:2.2 volumes: - ./school_service:/app working_dir: /app command: dotnet &quotMicroservicesOnDocker.School.Api.dll&quot income_service: image: mcr.microsoft.com/dotnet/core/aspnet:2.2 volumes: - ./income_service:/app working_dir: /app command: dotnet &quotMicroservicesOnDocker.Income.Api.dll&quotتغییراتی که در فایل docker-compose.yml ایجاد شده:سرویسی برای gateway اضافه شده که از طریق پورت 5000 قابل دسترسی است.برای سرویسهای school_service و income_service مقدار ports حذف شده. به این دلیل که دیگر نیازی نداریم به این سرویسها بصورت مستقیم دسترسی داشته باشیم.مقدار depends_on مشخص میکند که هر سرویس به چه سرویسهای دیگری وابستگی دارد و تضمین میکند این سرویس حتما درصورت وجود سرویسهای ذکر شده اجرا شود.با استفاده از دستور docker-compose up --build سیستم را اجرا کنید. حال میتوانیم سرویسهارو از طریق gateway فراخوانی کنیم:Request => [GET] http://localhost:5000/school/api/students Request => [GET] http://localhost:5000/income/api/paymentsو سیستم ما روی داکر جواب مناسب را به این درخواست ها ارسال خواهد کرد. همونطور که ملاحظه میکنید اتفاقی که افتاد این بود که دو میکروسرویس روی یک base address و فقط با یک پیشوند قابل دسترس شدند. برای ساده تر کردن آدرس ها میتونید پیشوند /api را از route کنترلرها حذف کنید.خسته نباشید!در این قسمت توانستیم یک gateway راه اندازی کنیم و میکروسرویسهای خود را پشت آن قرار دهیم تا نهایتا بتوانیم تمام سرویسها را بطور مثال روی یک subdomain به فرمت http://api.mydomain.com قرار دهیم. در قسمت بعدی از اجرای سرویسها روی داکر نه تنها برای مد production بلکه در زمان توسعه استفاده میکنیم و با مزیت های این روش آشنا میشیم.