Back-End

2 out, 2018

Criando gateway para suas APIs com Asp.Net Core, Ocelot e Docker em Linux

Publicidade

Olá, pessoal!

Com o aumento do desenvolvimento de microserviços, às vezes precisamos juntar todos esses serviços em lugar só, pois cada microserviço está em portas distintas, sendo difícil o controle de um front-end, por exemplo, ter que configurar várias portas para cada microsserviço. Com isso, existe o conceito de gateway.

O que é um gateway?

Gateway é um termo em inglês que significa ponto de ligação. Para o nosso cenário de APIs será um ponto de ligação, uma interface, para chamadas de vários serviços.

Exemplo de gateway

Veja no desenho acima, que o gateway é responsável por criar uma arquitetura unificada de suas APIs. Ele representa um roteador, onde recebendo uma chamada ele redireciona para o serviço respectivo.

Agora vamos para o exemplo prático: para a criação do gateway, baixaremos uma referência do NUGET para a criação do gateway, que se chama Ocelot.

“Ocelot is aimed at people using .NET running a micro-services/service orientated architecture that need a unified…”. threemammals.com.

Primeiro vamos criar um projeto novo!

Criando uma API, para a criação do Gateway

Vejam que habilitei o suporte ao Docker para a subida desses serviços em um ambiente Linux.

Depois, vamos baixar a referência do Ocelot via NUGET, em seu projeto de API que será o gateway:

PM> Install-Package Ocelot -Version 2.0.4

Depois, vamos atualizar o arquivo Program.cs:

using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace Gateway
{
    public class Program
    {
        public static void Main(string[] args)
        {

            IWebHostBuilder builder = new WebHostBuilder();

            builder.ConfigureServices(s => {
                s.AddSingleton(builder);
            });

            builder.UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseStartup<Startup>();

            var host = builder.Build();

            host.Run();
        }
    }
}

E o arquivo Startup.cs, com as configurações do Ocelot:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Ocelot.DependencyInjection;
using CacheManager.Core;
using Ocelot.Middleware;
using Microsoft.Extensions.Logging;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;

namespace Gateway
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                        .SetBasePath(env.ContentRootPath)
                        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                        .AddJsonFile("configuration.json")
                        .AddEnvironmentVariables();

            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddOcelot(Configuration)
                    .AddCacheManager(x => {
                        x.WithMicrosoftLogging(log =>
                        {
                            log.AddConsole(LogLevel.Debug);
                        })
                        .WithDictionaryHandle();
                    }); ;
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {

            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            app.UseOcelot().Wait();
        }
    }
}

Veja acima que adicionei na linha 20, para que nas configurações ler de um arquivo configuration.json, onde neste arquivo existirá um “de – para” do gateway, de qual o endereço ele recebe e para qual serviço ele redirecionará.

Mas antes de configurar esse arquivo vamos criar dois microsserviços: um chamado Pedido e outro Estoque. Exemplificando um cenário real.

Criação de dois microserviços Pedido e Estoque

Vamos configurar as portas de cada um desses serviços no docker-compose.override.yml.

Veja, que para serviço existe um nome, e qual a porta que será exposta pela imagem no Docker.

Para o gateway, a porta está configurada como 5555.

Agora vamos configurar o arquivo configuration.json. Adicione ele ao projeto Gateway.

Adicionando um arquivo configuration.json

Edite o arquivo e adicione essas configurações:

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/",
      "DownstreamScheme": "http",
      "DownstreamPort": 80,
      "DownstreamHost": "pedido:",
      "UpstreamPathTemplate": "/pedido/",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    },
    {
      "DownstreamPathTemplate": "/{everything}",
      "DownstreamScheme": "http",
      "DownstreamPort": 80,
      "DownstreamHost": "pedido",
      "UpstreamPathTemplate": "/pedido/{everything}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    },
    {
      "DownstreamPathTemplate": "/",
      "DownstreamScheme": "http",
      "DownstreamPort": 80,
      "DownstreamHost": "estoque",
      "UpstreamPathTemplate": "/estoque/",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    },
    {
      "DownstreamPathTemplate": "/{everything}",
      "DownstreamScheme": "http",
      "DownstreamPort": 80,
      "DownstreamHost": "estoque",
      "UpstreamPathTemplate": "/estoque/{everything}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete", "Options" ]
    }
  ],
  "GlobalConfiguration": {}
}

Veja nas configurações, que caso a URL do serviço seja, por exemplo, /estoque, ele redirecionará ao serviço estoque, que está configurado no arquivo docker-compose.override.yml com a porta 5557.

Depois de configurado o arquivo de configurações do gateway, vamos subir esse projeto numa máquina Linux para a criação das imagens e containers do Docker.

Projeto no servidor Linux

Logo após a cópia do projeto no servidor Linux, execute o comando:

sudo docker-compose up -d

Com esse comando, o Docker criará as imagens e containers com suas respectivas portas configuradas no arquivo docker-compose.override.yml.

Esse comando irá baixar uma imagem do compilador do aspnetcore2.1, e depois copiará todos os arquivos para uma outra pasta do servidor. Em seguida fará o download de todas as referências do NUGET e depois compilará todo o projeto.

Depois disso, criará o serviço/container na porta configurada.

Logo após a execução, seus containers foram criados:

Agora vamos executar o serviço estoque http://ipdoservidor:5555/estoque/api/values.

Lembrando que a porta 5555 é a porta do gateway.

Rota pelo gateway

Posso bater diretamente na rota do microsserviço de estoque, na porta 5557.

Rota sem o gateway

Mesma coisa no serviço de pedido http://ipdoservidor:5555/pedido/api/values.

Rota pelo gateway

E diretamente pela porta do microserviço 5556:

Rota sem gateway

Bom, essa abordagem vem sendo muito utilizada neste tipo de cenário, e centraliza todos seus microsserviços em um lugar somente utilizando essa estratégia de gateway.

Espero que tenham gostado!

Segue o exemplo desse artigo no meu GitHub.

Até a próxima!