利用Service Fabric承載eShop On Containers

從模塊化到微服務化

從Pet Shop 到eShop on Container都是Microsoft在技術演進的路徑上給開發者展現.Net的開發能力和架構能力的Sample工程,Petshop的時候更多的是展示應用的分層架構,設計的抽象與模塊間的通信。到了eShop on Container更多的關注在架構設計與微服務化的,下面咱們先來看看eshop on Container的架構圖git

在上圖,咱們能夠看到後端服務分紅了github

  1. Identity microservice(驗證服務)
  2. Catalog microservice(商品分類服務)
  3. Ordering microservice(訂單服務)
  4. Basket microservice(購物車服務)
  5. Marketing microservice(市場營銷服務)
  6. Locations microservice(地理位置信息服務)

在之前的分層架構中,一般這些服務都是以某一模塊來體現的,爲何如今要將他們拆分紅了各個服務呢?當咱們從業務場景上面來看這些服務時,咱們會發現每一個服務的訪問峯值時間區間、容量規劃都是不同的,甚至實現這些服務最方便最簡單的技術棧都有多是不同的(固然強大的.net core無所不能,可是公司內不一樣業務線上的技術儲備不同,就有可能選擇不一樣的技術實現)。這是由於若是咱們都將這些模塊整合到了一個程序或者服務中的時候,就會碰到在不一樣時間內服務高峯期擴展系統容量困難,要不就是資源不足,要不就是資源過剩。譬如搶購業務開始前你們提早個半小時登陸了系統,這時候系統最忙的是登陸模塊,到了開始搶購時間,系統最忙的是訂單模塊。不採用微服務架構的話,半小時前準備給登陸模塊使用的資源不必定可以及時的釋放出來給訂單模塊。若是兩個模塊都使用單一程序架構的話,極可能出現的狀況就是搶購的業務把全部資源都佔滿了了,連其餘正常訪問系統的用戶資源都被佔用掉,致使系統崩潰。在講究Dev/Ops的今天,開發人員和架構師須要更多的考慮硬件架構層面對程序應用帶來的影響。數據庫

用Service Fabric來承載eShop on Container微服務的方法一,經過Service Fabric直接管理Docker

首先咱們先到Azure上申請一個Container Registry來承載eShop各個微服務程序的鏡像(image).建立Azure Docker Registry能夠參考官方文檔:https://docs.microsoft.com/zh-cn/azure/container-registry/json

如今最新版本Service Fabric已經能夠直接管理編排Docker了。後端

1.建立一個類型爲Container的Serviceapi

image

2.在servicemanifest.xml中描述清楚image所在路徑架構

<CodePackage Name="Code" Version="1.0.0">

    <!-- Follow this link for more information about deploying Windows containers to Service Fabric: https://aka.ms/sfguestcontainers -->
    <EntryPoint>
  
      <ContainerHost>
        <ImageName>eshopsample.azurecr.io/catalog:latest</ImageName>       
      </ContainerHost>      
    </EntryPoint>
    <!-- Pass environment variables to your container: -->   
    <EnvironmentVariables>
      <EnvironmentVariable Name="HttpGatewayPort" Value=""/>
    </EnvironmentVariables>
  </CodePackage>

這裏很是簡單,指定了image所在位置就行了,若是自己Docker Image裏須要不少配置信息譬如:數據庫連接串、其餘服務的地址等等均可以在EnvironmentVariables裏面去配置。app

3.配置Registry的訪問帳號密碼,須要在ApplicationManifest.xml上面來配置框架

<ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="CatalogService_Pkg"  ServiceManifestVersion="1.0.1" />      
    <Policies>
      <ContainerHostPolicies CodePackageRef="Code" Isolation="hyperv">
        <RepositoryCredentials AccountName="youraccount" Password="xxxxxxxxxxxxx" PasswordEncrypted="false"/>
        <PortBinding ContainerPort="80" EndpointRef="CatalogServieEndpoint"/>
      
      </ContainerHostPolicies>
    </Policies>
  </ServiceManifestImport>

整個過程不會太複雜,只要配置好了Catalog microserivce的ServiceManifest.xm和ApplicationManifest.xml文件以後,咱們能夠用一樣的方法將其餘服務一一配置完成,而後咱們就能夠將Service Fabric的配置Publish到Cluster上面了。less

image

Service Fabric會自動根據配置在Cluster上面Pull Image和將Docker運行起來。很是簡單

用Service Fabric承載eShop on Container微服務的方法二:用Service Fabric的Runtime運行eShop on Container的微服務

Service Fabric自己就是個微服務的開發框架,如今已經直接支持了.net Core 2.0了因此,咱們更新了Service Fabric的SDK以後就能夠直接建立.net core的服務了

imageimage

eShop on Container的代碼都已是一份成型的.net core 2.0的代碼,因此不須要從新編寫服務。

1.經過nuget添加最新的Service Fabric最新的SDK。

image

2.修改programe.cs,啓動ServiceFabric Runtime而不是直接啓動Asp.net WebHost

public static void Main(string[] args)
        {

            try
            {
                // ServiceManifest.XML 文件定義一個或多個服務類型名稱。
                // 註冊服務會將服務類型名稱映射到 .NET 類型。
                // 在 Service Fabric 建立此服務類型的實例時,
                // 會在此主機進程中建立類的實例。

                ServiceRuntime.RegisterServiceAsync("Catalog.API",
                    context => new CatalogAPI(context)).GetAwaiter().GetResult();

                ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(CatalogAPI).Name);

                // 防止此主機進程終止,以使服務保持運行。 
                Thread.Sleep(Timeout.Infinite);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
                throw;
            }
}
3.編寫

CatalogAPI 類用於啓動WebHost

internal sealed class CatalogAPI : StatelessService
    {
        public CatalogAPI(StatelessServiceContext context)
            : base(context)
        { }

        /// <summary>
        /// Optional override to create listeners (like tcp, http) for this service instance.
        /// </summary>
        /// <returns>The collection of listeners.</returns>
        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            return new ServiceInstanceListener[]
            {
                new ServiceInstanceListener(serviceContext =>
                    new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                    {
                        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on {url}");
                                                return new WebHostBuilder()
                                         .UseKestrel()
                                    .ConfigureServices(
                                        services => services
                                            .AddSingleton<StatelessServiceContext>(serviceContext))
                                    .UseContentRoot(Directory.GetCurrentDirectory())
                                    .ConfigureAppConfiguration((builderContext, config) =>
                                    {
                                        IHostingEnvironment env = builderContext.HostingEnvironment;

                                        config.AddJsonFile("settings.json", optional: false, reloadOnChange: true)
                                            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
                                       
                                    })
                                    .UseStartup<Startup>()
                                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                    .UseUrls(url)
                                    .UseWebRoot("Pics")
                                    .Build();                  
                    }))
            };
        }
    }

4.編寫serviceManifest.xml描述服務端口等信息

<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="Catalog.APIPkg"
                 Version="1.0.3"
                 xmlns="http://schemas.microsoft.com/2011/01/fabric"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ServiceTypes>
        <StatelessServiceType ServiceTypeName="Catalog.API" />
  </ServiceTypes>

  <!-- Code package is your service executable. -->
  <CodePackage Name="Code" Version="1.0.3">
    <EntryPoint>
      <ExeHost>
        <Program>Catalog.API.exe</Program>
        <WorkingFolder>CodePackage</WorkingFolder>
      </ExeHost>
    </EntryPoint>
    <EnvironmentVariables>
      <EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="Development"/>
    </EnvironmentVariables>
  </CodePackage>


  <ConfigPackage Name="Config" Version="1.0.1" />

  <Resources>
   
    <Endpoints>   
  
      <Endpoint Protocol="http" Name="ServiceEndpoint"  Type="Input"  Port="5101" />
    </Endpoints>
  </Resources>
</ServiceManifest>


5.修改AppcationManifest.xml增長几個服務的描述信息

添加ServiceImport節

<ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="Catalog.APIPkg" ServiceManifestVersion="1.0.3" />
    <ConfigOverrides />
  </ServiceManifestImport>

在DefaultService中描述Service

<Service Name="Catalog.API" ServiceDnsName="catalog.fabric.api">
      <StatelessService ServiceTypeName="Catalog.API" InstanceCount="[Catalog.API_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>

這樣咱們就能夠將Catalog這個服務改形成能夠經過Service Fabric來管理的微服務了。經過Publish,咱們可看到幾個服務都已經在Service Fabric下面接受管理和編排了。

image

訪問localhost:5100

image

相關文章
相關標籤/搜索