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.
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!
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.
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.
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.
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.
Posso bater diretamente na rota do microsserviço de estoque, na porta 5557.
Mesma coisa no serviço de pedido http://ipdoservidor:5555/pedido/api/values.
E diretamente pela porta do microserviço 5556:
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!