Jump to content

Featured Replies

Posted

O avanço das arquiteturas de microsserviços levou a uma reorganização das responsabilidades entre serviços. Isso impulsionou a adoção de contêineres e consequentemente, soluções de orquestração como o Kubernetes. No entanto, essa abordagem trouxe desafios, como o acoplamento excessivo entre aplicações e serviços externos.

 

Para mitigar isso, surgiu o Dapr, um runtime que permite comunicação desacoplada entre aplicações. Este artigo foca em apresentar o Dapr e como configurá-lo no Azure Container Apps, abordando funcionalidades essenciais e procedimentos práticos para uma integração bem-sucedida.

 

 

Azure Container Apps

 

 

O Azure Container Apps é a solução de orquestração de contêineres do Azure. Ele permite que você implante e gerencie contêineres sem se preocupar com a infraestrutura subjacente. O Azure Container Apps é baseado no Azure Kubernetes Service, mas oferece uma experiência simplificada para implantar e gerenciar contêineres.

 

Podemos definir o Azure Container Apps como sendo uma solução serverless de Kubernetes.

 

Esse serviço é um ótimo acelerador para empresas que estão iniciando sua jornada de adoção de contêineres, pois permite que você implante e gerencie contêineres sem se preocupar com a infraestrutura.

 

 

Dapr

 

 

O Dapr codifica as melhores práticas para a construção de aplicativos baseados em microsserviços em APIs abertas e independentes chamadas de building block, que permitem que você crie aplicativos portáteis com a linguagem e o framework de sua escolha. Cada building block é totalmente independente, e você pode usar um, alguns ou todos eles em seu aplicativo.

 

Usando o Dapr, você pode migrar gradualmente seus aplicativos existentes para uma arquitetura de microsserviços, adotando padrões nativos da nuvem, como dimensionamento sob demanda, resiliência e implantações independentes.

 

Além disso, o Dapr é independente de plataforma, o que significa que você pode executar seus aplicativos localmente, em qualquer cluster Kubernetes, em máquinas virtuais ou físicas e em outros ambientes de hospedagem que o Dapr integra. Isso permite que você construa aplicativos baseados em microsserviços que podem ser executados na nuvem e na borda.

 

d7cbc92a-b572-4ee6-a4c0-3f829d504658

 

 

Building Blocks

 

 

Um building block é uma API HTTP ou gRPC, que pode ser chamada a partir do seu código e utiliza um ou mais componentes do Dapr. O Dapr é composto por um conjunto de unidades de construção de API, com a capacidade de adicionar novas unidades de construção para estender suas funcionalidades.

 

Abaixo está uma lista dos principais building blocks do Dapr:

 


  1. State:
     
    • O building block State permite que os aplicativos armazenem e recuperem estado de maneira confiável. Ele oferece suporte a várias opções de estado, incluindo estado persistente e temporário.

[*]

Pub/Sub:

 

  • O Pub/Sub (Publicação/Assinatura) facilita a comunicação entre os diferentes componentes de um aplicativo distribuído. Os aplicativos podem publicar eventos e se inscrever para receber notificações quando esses eventos ocorrem.

[*]

Bindings:

 

  • Bindings permitem que os aplicativos interajam facilmente com recursos externos, como bancos de dados, sistemas de mensagens e serviços da nuvem, por meio de adaptadores pré-construídos.

[*]

Secrets:

 

  • O building block Secrets gerencia e fornece acesso seguro a segredos sensíveis, como chaves de autenticação e senhas, para os aplicativos.

[*]

Actors:

 

  • O Actors é um modelo de programação baseado em atores que facilita a criação de aplicativos de estado escaláveis e com estado isolado.

[*]

Observability:

 

  • O Observability é uma parte fundamental do Dapr que fornece recursos de rastreamento, métricas e registro para facilitar a monitoração e solução de problemas de aplicativos.

[*]

Middleware:

 

  • Middleware permite a adição de funcionalidades personalizadas a aplicativos Dapr, como autenticação, autorização e manipulação de solicitações HTTP.

[*]

HTTP API:

 

  • O HTTP API permite que os aplicativos exponham APIs HTTP de maneira simplificada, facilitando a comunicação com outros serviços.

 

Na perspectiva das aplicações em execução no Kubernetes, esses building blocks são implementados como sidecars de contêineres. Isso significa que cada building block é executado como um contêiner adjacente à aplicação principal.

 

47608468-18c0-429f-87e9-d23635f431fa

 

 

Componente

 

 

Um building block é exposto através de um contêiner sidecar associado a cada aplicação, atuando de forma isolada para fornecer uma funcionalidade específica, como gerenciamento de estado ou comunicação de eventos.

 

Por outro lado, um componente do Dapr é uma peça central que lida com a complexidade da comunicação com o serviço final. Em vez de ser um contêiner sidecar individual, ele serve como uma camada intermediária entre a aplicação e os serviços externos.

 

Portanto, enquanto os building blocks oferecem funcionalidades específicas diretamente para cada aplicação por meio de sidecars, os componentes do Dapr desempenham um papel mais central e abrangente.

 

A imagem abaixo representa claramente o papel do componente:

 

02531047-01e4-48d4-8d01-7395dbd7cd52

 

 

Componente no Container App Environment

 

 

Os componentes usam um design modular, e podem ser compartilhados entre aplicações. Eles são executados como um processo separado, fora do escopo da aplicação.

 

Os componentes são configurados em nível de ambiente do Container App, mesmo que a plataforma se responsabilize por criar e configurar o Dapr, ainda precisaremos configurar os componentes.

 

Essa configuração é feita através de arquivos de definição yaml, cada tipo de componente conterá suas próprias propriedades.

 

No artigo, estamos demonstrando a integração do componente de pub/sub do Dapr com o serviço do Service Bus.

 

Existe uma diferença entre o arquivo utilizado para criação de componentes direto em um cluster Kubernetes e o arquivo utilizado para criação de componentes no ambiente do Container App.

 

Todos os componentes de código aberto do Dapr seguem o seguinte esquema básico:

 

apiVersion: dapr.io/v1alpha1

kind: Component

metadata:

name: [COMPONENT-NAME]

namespace: [COMPONENT-NAMESPACE]

spec:

type: [COMPONENT-TYPE]

version: v1

initTimeout: [TIMEOUT-DURATION]

ignoreErrors: [bOOLEAN]

metadata:

- name: [METADATA-NAME]

value: [METADATA-VALUE]

 

 

 

 

No Azure Container Apps, o esquema acima foi ligeiramente simplificado para suportar os componentes do Dapr e remover campos desnecessários, incluindo apiVersion, kind e propriedades redundantes de metadados e especificações.

 

componentType: [COMPONENT-TYPE]

version: v1

initTimeout: [TIMEOUT-DURATION]

ignoreErrors: [bOOLEAN]

metadata:

- name: [METADATA-NAME]

value: [METADATA-VALUE]

 

 

 

 

No nosso exemplo, o arquivo ficou da seguinte forma:

 

componentType: pubsub.azure.servicebus.queues

version: v1

ignoreErrors: false

secrets:

- name: connectionstring

value: <VALOR DA CONNECTION-STRING>

metadata:

- name: connectionString

secretRef: connectionstring

scopes:

- app-publisher

- app-subscriber

 

A propriedade scopes define quais aplicações terão acesso ao componente, portanto é obrigatória.

 

 

 

Para criar o componente no ambiente do Container App, rode o comando:

 

az containerapp env dapr-component set --name ENVIRONMENT_NAME --resource-group RESOURCE_GROUP_NAME --dapr-component-name pubsub --yaml "./pubsub.yaml"

 

 

 

 

Se o comando funcionou corretamente, verá um resultado parecido com:

 

{

"id": "/subscriptions/60e0dc1e-a3f7-44cb-8561-17980fce2670/resourceGroups/tdc-huebr/providers/Microsoft.App/managedEnvironments/tdc-huebr-env/daprComponents/pubsubgeneric",

"name": "pubsub",

"properties": {

"componentType": "pubsub.azure.servicebus.queues",

"ignoreErrors": false,

"metadata": [

{

"name": "connectionString",

"secretRef": "connectionstring"

}

],

"scopes": [

"app-publisher",

"app-subscriber"

],

"secrets": [

{

"name": "connectionstring"

}

],

"version": "v1"

},

"resourceGroup": "RESOURCE_GROUP_NAME",

"systemData": {

"createdAt": "2023-09-13T13:08:13.2180324Z",

"createdBy": "<SEU-EMAIL>",

"createdByType": "User",

"lastModifiedAt": "2023-09-13T13:08:13.2180324Z",

"lastModifiedBy": "<SEU-EMAIL>",

"lastModifiedByType": "User"

},

"type": "Microsoft.App/managedEnvironments/daprComponents"

}

 

 

Projeto PUB/SUB

 

 

Para demonstrar o uso do Dapr, criamos um projeto de exemplo que utiliza o componente de pub/sub do Dapr para publicar e consumir mensagens de um tópico do Service Bus. O projeto é composto por duas aplicações, uma que publica mensagens e outra que consome as mensagens.

 

O building block de publicação e inscrição do Dapr fornece um framework de API agnóstico à plataforma para enviar e receber mensagens. Seus serviços publicam mensagens em um tópico. Seus serviços se inscrevem em um tópico para consumir mensagens. O serviço faz chamadas à API de publicação/assinatura (pub/sub) no sidecar do Dapr. O sidecar então faz chamadas para o componente do Dapr criado previamente que encapsula a lógica para comunicação com o Service Bus.

 

 

Aplicação Publicadora

 

 

Utilizamos o Dapr .NET Sdk, para lidar com a complexidade da comunicação com o container sidecar do Dapr. O código abaixo mostra como configurar o DaprClient para publicar mensagens no tópico TOPICO:

 

using Dapr.Client;

 

var daprClient = new DaprClientBuilder().Build();

await daprClient.PublishEventAsync<int>("NOME_DO_COMPONENTE", "TOPICO", new object());

 

 

 

 

Esse trecho de código será responsável por encapsular a chamada HTTP ou gRPC para o sidecar do Dapr, essa chamada vai acontecer no Endpoint:

 

http://localhost:<dapr-port>/v1.0/publish/<pub-sub-name>/<topic>

 

 

Aplicação Consumidora

 

 

Essa aplicação vai funcionar de forma passiva, onde o sidecar do Dapr vai ficar escutando o tópico TOPICO e quando uma mensagem for publicada, o sidecar vai fazer uma chamada HTTP ou gRPC para a aplicação consumidora.

 

No início, o tempo de execução do Dapr chamará o aplicativo em um ponto de extremidade conhecido para identificar e criar as assinaturas necessárias:

 

http://localhost:<appPort>/dapr/subscribe

 

 

 

 

O sidecar vai utilizar da resposta desse endpoint como insumo para mapear quais são os tópicos que a aplicação consome.

 

A biblioteca Dapr.AspNetCore deixa esse processo trivial para o desenvolvedor, onde com poucas linhas de código, podemos configurar esse endpoint que o sidecar vai usar posteriormente.

 

O primeiro passo é instalar o pacote Dapr.AspNetCore:

 

dotnet add package Dapr.AspNetCore

 

 

 

 

Podemos utilizar a classe de atributo Topic sobre o método que vai receber as mensagens do tópico TOPICO, dessa forma:

 

[Topic("NOME_DO_COMPONENTE","TOPICO")]

[HttpPost("/count")]

public IActionResult Post(int value) {

...

return Ok();

}

 

 

 

 

Após isso, precisamos configurar a aplicação fazendo modificações na classe Program.cs:

 

var builder = WebApplication.CreateBuilder(args);

 

// Add services to the container.

 

builder.Services.AddControllers().AddDapr();

 

var app = builder.Build();

 

app.UseCloudEvents();

 

app.MapControllers();

 

app.MapSubscribeHandler();

 

app.Run();

 

 

 

 

O segmento de código .AddDapr() registra os serviços necessários como o DaprClient. O segmento de código MapSubscribeHandler() registra o endpoint que o sidecar vai utilizar para identificar e criar as assinaturas necessárias, para atingir esse objetivo ele mapeia todos os endpoints decorados com o atributo Topic.

 

A fins de curiosidade, a lógica que o método MapSubscribeHandler() utiliza para identificar os endpoints decorados com o atributo Topic é a seguinte:

 

private static IEndpointConventionBuilder CreateSubscribeEndPoint(IEndpointRouteBuilder endpoints, SubscribeOptions options = null)

{

if (endpoints is null)

{

throw new System.ArgumentNullException(nameof(endpoints));

}

 

return endpoints.MapGet("dapr/subscribe", async context =>

{

var logger = context.RequestServices.GetService<ILoggerFactory>().CreateLogger("DaprTopicSubscription");

var dataSource = context.RequestServices.GetRequiredService<EndpointDataSource>();

var subscriptions = dataSource.Endpoints

.OfType<RouteEndpoint>()

.Where(e => e.Metadata.GetOrderedMetadata<ITopicMetadata>().Any(t => t.Name != null))

.SelectMany(e =>

{

...

})

.Distinct()

.GroupBy(e => new { e.PubsubName, e.Name })

.Select(e => e.OrderBy(e => e.Priority))

.Select(e =>

{

...

})

.OrderBy(e => (e.PubsubName, e.Topic));

 

await context.Response.WriteAsync(JsonSerializer.Serialize(subscriptions,

new JsonSerializerOptions

{

PropertyNamingPolicy = JsonNamingPolicy.CamelCase,

DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull

}));

});

}

 

 

 

 

Utilizando a classe EndpointDatasource a lib consegue identificar todos os endpoints decorados com o atributo Topic através do seguimento de código .Where(e => e.Metadata.GetOrderedMetadata<ITopicMetadata>().Any(t => t.Name != null)). No final ele vai retornar um json com todas as assinaturas que o sidecar vai criar, no endpoint dapr/subscribe.

 

Para saber mais veja o código fonte no repositório: Dapr.AspNetCore.

 

Teste local

 

 

Para testar seu projeto, você pode executar as aplicações localmente, para isso, você precisa instalar o Dapr CLI.

 

Após instalar o Dapr CLI, você precisa inicializar o Dapr localmente, para isso, rode o comando:

 

dapr init

 

 

 

 

Após isso, você precisa configurar o componente, para isso entre na pasta .dapr no local de instalação, depois na pasta components, crie o arquivo pubsub.yaml e cole o conteúdo abaixo:

 

apiVersion: dapr.io/v1alpha1

kind: Component

metadata:

name: pubsub

spec:

type: pubsub.azure.servicebus.queues

version: v1

metadata:

- name: connectionString

value: "<CONNECTION_STRING>"

 

 

 

 

Após a criação do componente, basta rodar as aplicações, para isso, abra os terminais no diretório das aplicações e rode os comandos:

 

dapr run --app-id publisher -- dotnet run

dapr run --app-id subscriber -- dotnet run

 

 

Conclusão

 

 

Ao realizar a leitura deste artigo, você estará pronto para iniciar sua jornada de adoção do Dapr no Azure Container Apps. O Dapr é uma ferramenta poderosa para desacoplar aplicações, ele permite que você implante e gerencie contêineres sem se preocupar com a infraestrutura. Além disso, o Dapr é independente de plataforma, o que significa que você pode executar seus aplicativos localmente, em qualquer cluster Kubernetes, em máquinas virtuais ou físicas e em outros ambientes de hospedagem que o Dapr integra.

 

Continue reading...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...