Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este artigo descreve como criar, validar, depurar e publicar conectores Akri personalizados utilizando a extensão de pré-visualização VS Code Azure IoT Operations Conectores Akri.
A extensão suporta as seguintes plataformas:
- Linux
- Subsistema Microsoft Windows para Linux (WSL)
- Windows
A extensão permite-lhe criar conectores utilizando as seguintes linguagens de programação:
- .NET
- Rust
Pré-requisitos
Ambiente de desenvolvimento:
- Docker
- Código do Visual Studio
- Extensão do VS Code Azure IoT Operations Akri Connectors (pré-visualização)
- SDK de .NET
- Para depurar conectores baseados em .NET - extensão C#
- Para depurar conectores baseados em Rust - extensão C/C++
- Azure CLI
- ORAS CLI
- Clona o repositório Explore Azure IoT Operations se ainda não o fizeste.
Configuração do Docker:
As imagens usadas pela extensão devem ser puxadas e etiquetadas localmente antes de usar a extensão:
docker pull mcr.microsoft.com/azureiotoperations/devx-runtime:0.1.8 docker tag mcr.microsoft.com/azureiotoperations/devx-runtime:0.1.8 devx-runtimeTodos os contentores que a extensão lança estão configurados para correr numa rede personalizada nomeada
aio_akri_networkpara fins de isolamento de rede:docker network create aio_akri_networkO contentor DevX utiliza um volume
akri_devx_docker_volumepersonalizado para armazenar a configuração do cluster:docker volume rm akri_devx_docker_volume # delete the volume created from any previous release docker volume create akri_devx_docker_volume
Para implementar e usar o seu conector com uma instância Azure IoT Operations, também precisa de:
- Uma instância do Azure IoT Operations.
- Acede a um registo de contentores, como o Azure Container Registry, para publicar as imagens dos seus conectores.
- Um endpoint de registo de contentores configurado na sua instância do Azure IoT Operations para obter as imagens dos seus conectores. Para mais informações, consulte Configurar endpoints do registo.
Criar e validar um conector Akri
Neste exemplo, cria um conector HTTP/REST usando a linguagem C#, constrói uma imagem docker e depois executa a aplicação conector usando a extensão VS Code:
Pressione
Ctrl+Shift+Ppara abrir a paleta de comandos e procure por Azure IoT Operations Akri Connectors: Criar um novo comando Akri Connector . Crie uma nova pasta chamadamy-connectorse selecione-a, selecione C# como linguagem, introduza um nome para o conector comorest_connector, e selecione PollingTelemetryConnector como tipo de conector.A extensão cria um novo espaço de trabalho nomeado usando o nome do conector que escolheu na etapa anterior. O espaço de trabalho inclui a estrutura para um conector de telemetria de sondagem escrito na linguagem C#.
Os passos seguintes assumem que criou um projeto .NET chamado MyConnector.
Importante
O seguinte código de exemplo destina-se apenas a fins ilustrativos e não é destinado a ser usado em produção. Num conector de produção, deve implementar uma lógica robusta de tratamento de erros e de repetição, e garantir que quaisquer credenciais usadas para ligar ao ativo são armazenadas e utilizadas de forma segura. Um conector de qualidade de produção deve implementar o contrato descrito no documento do operador Akri e de contrato do conector no repositório de kits de desenvolvimento de software (SDK).
Para representar o estado do termóstato, crie um ficheiro chamado ThermostatStatus.cs na MyConnector pasta do espaço de trabalho com o seguinte conteúdo. Este ficheiro modela a resposta JSON a partir do endpoint REST:
using System.Text.Json.Serialization;
namespace MyConnector
{
internal class ThermostatStatus
{
[JsonPropertyName("desiredTemperature")]
public double? DesiredTemperature { get; set; }
[JsonPropertyName("currentTemperature")]
public double? CurrentTemperature { get; set; }
}
}
Para adicionar uma configuração de pontos de dados, crie um ficheiro chamado DataPointConfiguration.cs na MyConnector pasta do espaço de trabalho com o seguinte conteúdo. Este ficheiro modela uma configuração para um ponto de dados que o utilizador especifica na interface de experiência operacional:
using System.Text.Json.Serialization;
namespace MyConnector
{
public class DataPointConfiguration
{
[JsonPropertyName("HttpRequestMethod")]
public string? HttpRequestMethod { get; set; }
}
}
Implementa o método SampleDatasetAsync na classe fornecida DatasetSampler. O método toma a Dataset como parâmetro. A Dataset contém os pontos de dados para o conector processar.
Abre o ficheiro
MyConnector/DatasetSampler.csno teu espaço de trabalho VS Code.Para passar os dados necessários para processar os dados do endpoint, adiciona-se um construtor à
DatasetSamplerclasse . A classe usa oHttpClienteEndpointProfileCredentialspara se conectar e autenticar no endpoint do ativo.private readonly HttpClient _httpClient; private readonly string _assetName; private readonly EndpointCredentials? _credentials; private readonly static JsonSerializerOptions _jsonSerializerOptions = new() { AllowTrailingCommas = true, }; public DatasetSampler(HttpClient httpClient, string assetName, EndpointCredentials? credentials) { _httpClient = httpClient; _assetName = assetName; _credentials = credentials; } public ValueTask DisposeAsync() { _httpClient.Dispose(); return ValueTask.CompletedTask; }Modificar o
GetSamplingIntervalAsyncmétodo para devolver um intervalo de amostragem de três segundos:public Task<TimeSpan> GetSamplingIntervalAsync(AssetDataset dataset, CancellationToken cancellationToken = default) { return Task.FromResult(TimeSpan.FromSeconds(3)); }Observação
Para simplificar, este exemplo utiliza um intervalo de amostragem fixo. Num conector de produção, pode tornar o intervalo de amostragem configurável usando os metadados do conector para definir uma propriedade de intervalo de amostragem que o utilizador pode definir na interface de experiência operacional.
Substitua o método existente
SampleDatasetAsyncpelo seguinte esboço:public async Task<byte[]> SampleDatasetAsync(AssetDataset dataset, CancellationToken cancellationToken = default) { int retryCount = 0; while (true) { try { // TODO: Implement your dataset sampling logic here. } catch (Exception ex) { if (++retryCount >= 3) { throw new InvalidOperationException($"Failed to sample dataset with name {dataset.Name} in asset with name {_assetName}. Error: {ex.Message}", ex); } await Task.Delay(1000, cancellationToken); } } }No bloco
trydo métodoSampleDatasetAsync, adicione o seguinte código para obter cadaDataPointdoDataSete extrair os caminhos da fonte de dados. Estes caminhos fazem parte dos URLs usados para obter os dados do endpoint REST. OscurrentTemperaturepontos de dados edesiredTemperatureforam modelados anteriormente naThermostatStatusclasse. O método de pedido HTTP é extraído da configuração do ponto de dados modelada naDataPointConfigurationclasse:AssetDatasetDataPointSchemaElement httpServerDesiredTemperatureDataPoint = dataset.DataPoints!.Where(x => x.Name!.Equals("desiredTemperature"))!.First(); HttpMethod httpServerDesiredTemperatureHttpMethod = HttpMethod.Parse(JsonSerializer.Deserialize<DataPointConfiguration>(httpServerDesiredTemperatureDataPoint.DataPointConfiguration!, _jsonSerializerOptions)!.HttpRequestMethod); string httpServerDesiredTemperatureRequestPath = httpServerDesiredTemperatureDataPoint.DataSource!; AssetDatasetDataPointSchemaElement httpServerCurrentTemperatureDataPoint = dataset.DataPoints!.Where(x => x.Name!.Equals("currentTemperature"))!.First(); HttpMethod httpServerCurrentTemperatureHttpMethod = HttpMethod.Parse(JsonSerializer.Deserialize<DataPointConfiguration>(httpServerCurrentTemperatureDataPoint.DataPointConfiguration!, _jsonSerializerOptions)!.HttpRequestMethod); string httpServerCurrentTemperatureRequestPath = httpServerCurrentTemperatureDataPoint.DataSource!;Observação
Para simplificar, este exemplo só mostra como recuperar o método HTTP a usar a partir da configuração do ponto de dados. A amostra não usa este valor quando faz o pedido HTTP.
No mesmo método, configure a autenticação usando as credenciais fornecidas se estiverem em uso endpoints autenticados:
if (_credentials != null && _credentials.Username != null && _credentials.Password != null) { // Note that this sample uses username + password for authenticating the connection to the asset. In general, // x509 authentication should be used instead (if available) as it is more secure. string httpServerUsername = _credentials.Username; string httpServerPassword = _credentials.Password; var byteArray = Encoding.ASCII.GetBytes($"{httpServerUsername}:{httpServerPassword}"); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); }Este código extrai as credenciais e adiciona-as ao cabeçalho de autorização.
DatasetSamplerimplementa a autenticação básica com credenciais de nome de utilizador e palavra-passe.Depois, adicione código para fazer um pedido HTTP ao endpoint, desserialize a resposta, extraia as propriedades
CurrentTemperatureeDesiredTemperaturee coloque-as num objetoThermostatStatus.var currentTemperatureHttpResponse = await _httpClient.GetAsync(httpServerCurrentTemperatureRequestPath); var desiredTemperatureHttpResponse = await _httpClient.GetAsync(httpServerDesiredTemperatureRequestPath); if (currentTemperatureHttpResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized || desiredTemperatureHttpResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized) { throw new Exception("Failed to authorize request to HTTP server. Check credentials configured in rest-server-device-definition.yaml."); } currentTemperatureHttpResponse.EnsureSuccessStatusCode(); desiredTemperatureHttpResponse.EnsureSuccessStatusCode(); ThermostatStatus thermostatStatus = new() { CurrentTemperature = (JsonSerializer.Deserialize<ThermostatStatus>(await currentTemperatureHttpResponse.Content.ReadAsStreamAsync(), _jsonSerializerOptions)!).CurrentTemperature, DesiredTemperature = (JsonSerializer.Deserialize<ThermostatStatus>(await desiredTemperatureHttpResponse.Content.ReadAsStreamAsync(), _jsonSerializerOptions)!).DesiredTemperature };De seguida, serializa o estado para JSON e devolve a resposta ao endpoint. Neste exemplo, a carga útil de resposta HTTP já corresponde ao esquema esperado da mensagem, pelo que não é necessária nenhuma tradução:
// The HTTP response payload matches the expected message schema, so return it as-is return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(thermostatStatus));Sugestão
Opcionalmente, o conector pode registar um esquema no registo de esquemas para permitir que outras Operações Azure IoT compreendam o formato das mensagens.
Finalmente, importa os tipos necessários:
using Azure.Iot.Operations.Connector.Files; using System.Net.Http.Headers; using System.Text; using System.Text.Json;
A versão final do código é semelhante ao DatasetSampler.
Implementa o método CreateDatasetSampler na classe DatasetSamplerProvider. Esta classe cria DataSetSampler objetos para injetar na aplicação conforme necessário.
Abre o
MyConnector/DatasetSamplerProvider.csficheiro no teu espaço de trabalho VS Code.No
CreateDatasetSamplermétodo, devolve aDatasetSamplerjuntamente com oendpointCredentials, se o nome do conjunto de dados forthermostat_status:if (dataset.Name.Equals("thermostat_status")) { if (device.Endpoints != null && device.Endpoints.Inbound != null && device.Endpoints.Inbound.TryGetValue(inboundEndpointName, out var inboundEndpoint)) { var httpClient = new HttpClient() { BaseAddress = new Uri(inboundEndpoint.Address), }; return new DatasetSampler(httpClient, assetName, endpointCredentials); } } throw new InvalidOperationException($"Unrecognized dataset with name {dataset.Name} on asset with name {assetName}");Observação
Para simplificar, este exemplo assume que o nome do conjunto de dados é sempre
thermostat_status. Num conector de produção, pode implementar lógica adicional para lidar com múltiplos conjuntos de dados.
A versão final do código é semelhante ao DatasetSamplerProvider.
De seguida, constrói o projeto para confirmar que não há erros. Use o comando VS Code Azure IoT Operations Akri Connectors: Criar um Akri Connector e escolha o modo Release. Este comando mostra o progresso da build na consola OUTPUT e notifica-te quando a build termina. Pode então ver uma nova imagem Docker com etiqueta <connector_name>release localmente no Docker Desktop.
Para testar o novo conector localmente, siga estes passos:
Crie um endpoint local que funcione como um servidor REST para o conector se conectar. No
explore-iot-operationrepositório que clonou anteriormente, execute os seguintes comandos para construir um servidor REST local para testes:cd samples/akri-vscode-extension/sample-rest-server docker build -t rest-server:latest .Pode ver a imagem no Docker Desktop.
Execute o seguinte comando para iniciar o servidor REST num contentor local:
docker run -d --rm --network aio_akri_network --name restserver rest-server:latestPode ver o contentor em execução no Docker Desktop. O servidor REST é acessível em
http://restserver:3000para contentores a executar emaio_akri_network.Copie o ficheiro
rest-server-device-definition.yamlda pastasamples/akri-vscode-extension/rest-server-custom-resourcesna cópia local do repositórioexplore-iot-operationspara a pasta Dispositivos no seu ambiente de trabalho de conector no VS Code. Este recurso de dispositivo define uma ligação de endpoint ao servidor REST.Copie o ficheiro
rest-server-asset1-definition.yamldo diretóriosamples/akri-vscode-extension/rest-server-custom-resourcesna sua cópia local do repositórioexplore-iot-operationspara o diretório Assets no espaço de trabalho do conector no VS Code. Este ativo publica informação de temperatura do dispositivo no tópico MQTTmqtt/machine/asset1/status.Copie o ficheiro
rest-server-asset2-definition.yamldo diretóriosamples/akri-vscode-extension/rest-server-custom-resourcesna sua cópia local do repositórioexplore-iot-operationspara o diretório Assets no espaço de trabalho do conector no VS Code. Este ativo publica informações de temperatura do dispositivo para a loja estadual.Para testar o conector com os recursos de dispositivos e ativos, vá para o painel Executar e Depurar no espaço de trabalho do VS Code e selecione a configuração Executar um Conector Akri. Esta configuração lança um terminal que executa as tarefas de pré-lançamento para iniciar o
aio-brokercontentor e o conector REST que desenvolveu noutro contentor chamado<connector_name>_release. Este processo demora vários minutos. Pode ver o fluxo de dados de telemetria do servidor REST para o broker MQ através do conector REST na janela do terminal no VS Code. Os registos dos contentores também são visíveis no Docker Desktop.Podes parar a execução a qualquer momento usando o botão Parar no painel de comandos de depuração. Este comando limpa e elimina os contentores
aio-brokerem execução e<connector_name>_release.
Depurar um conector Akri
Para depurar um conector Akri baseado em .NET, certifique-se de que tem a extensão C# VS Code instalada. Usa o mesmo conector REST que criaste anteriormente:
Para construir o conector em modo Debug , use o comando VS Code Azure IoT Operations Akri Connectors: Build an Akri Connector e selecione o modo Debug . Este comando cria uma imagem Docker local chamada
<connector_name>com a tagdebug. Pode ver a imagem no Docker Desktop.Podes adicionar um ponto de interrupção e a execução é interrompida quando esse ponto é atingido. Tente adicionar um ponto de interrupção no início do
SampleDatasetAsyncmétodo emDatasetSampler.cs.Para depurar o conector, vá ao painel Executar e Depurar no espaço de trabalho do VS Code e selecione a configuração Depurar Conector Akri. Esta configuração lança um terminal que executa as tarefas de pré-lançamento para iniciar o
aio-brokercontentor e o conector REST que desenvolveu noutro contentor chamado<connector_name>_debug. Este processo demora vários minutos. Pode ver o fluxo de dados de telemetria do servidor REST para o broker MQ através do conector REST na janela do terminal no VS Code. Os registos dos contentores também são visíveis no Docker Desktop.Use o botão Desconectar no painel de comandos de depuração para terminar a execução.
Observação
A extensão Akri VS Code lança o contentor DevX num cenário Run/Debug com um período de timeout de três minutos. Se o contentor não completar o lançamento dentro do período de timeout, a extensão termina o contentor.
Aplicar atualizações de configuração
Podes atualizar dinamicamente as configurações do dispositivo e dos ativos no ambiente de execução local enquanto estás a usar o teu conector. Esta funcionalidade permite-lhe verificar se o seu conector responde a alterações de configuração. Use os seguintes comandos de extensão VS Code para fazer estas alterações:
- Azure IoT Operações Conectores Akri: Aplicar YAML de Dispositivo no cluster
- Azure IoT Operations Akri Connectors: Aplicar YAML de Ativo no cluster
- Azure IoT Operations Akri Conectores: Eliminar YAML do Dispositivo do cluster
- Azure IoT Operations Akri Connectors: Eliminar Asset YAML do cluster
Estado do conector de captura
Para capturar o estado atual do registo de esquemas, utilize o comando de extensão Azure IoT Operations Akri Connectors: Capture Connector State do VS Code. Este comando cria uma pasta na pasta OUTPUT do workspace com um nome baseado no carimbo temporal atual. A pasta criada contém uma cópia do estado atual do registo de esquemas, incluindo quaisquer esquemas criados pelo conector personalizado.
O estado do registo de esquemas está sempre visível na Output/ConnectorState pasta. O comando permite-lhe capturar o estado do registo de esquemas num momento específico.
Publicar uma imagem do conector
Utilize o comando Azure IoT Operations Akri connectors: Publish Akri Connector Image ou Metadata para publicar imagens de conector num registo Microsoft Azure Container Registry (ACR). O comando utiliza a CLI do Microsoft Azure e os comandos oras. Para publicar num registo ACR, precisa do seu ID de subscrição Azure e do nome do registo ACR.
Configuração de metadados do conector do autor
Utilize o espaço de trabalho VS Code criado a partir do comando Create an Akri Connector para elaborar o ficheiro connector-metadata.json que cumpre com o esquema JSON do Azure IoT Operations Connector Metadata 9.0-preview. Pode colocar este ficheiro em qualquer lugar do seu espaço de trabalho de conectores. A extensão fornece uma capacidade de validação estática usando o connector-metadata.json ficheiro e mostra avisos no PROBLEMS painel caso faltem alguma propriedade necessária.
Publicar artefactos de metadados
Use o comando Azure IoT Operations Akri connectors: Publish Akri Connector Image ou Metadata para publicar pastas de metadados num registo ACR. O comando utiliza o Azure CLI e oras comandos. Para publicar num registo ACR, precisa do seu ID de subscrição Azure e do nome do registo ACR. Atualmente, a extensão espera que os ficheiros chamados connector-metadata.json e, opcionalmente additionalConfig.json , estejam presentes em qualquer pasta que pressionar.
Problemas conhecidos
As atualizações de configuração que resultam dos
Delete/Apply Asset/Device YAMLcomandos VS Code atualmente não funcionam no Windows devido às limitações da implementação do CIFS no kernel Linux. Quaisquer eventos de alteração de ficheiros em pastas montadas no host não são propagados para o contentor pelo Docker para Windows.Quando elimina um asset ou dispositivo do cluster usando os comandos VS Code, o conector .NET apresenta atualmente o seguinte erro 404:
Unhandled exception. Azure.Iot.Operations.Protocol.Retry.RetryExpiredException: Retry expired while attempting the operation. Last known exception is the inner exception. ---> Azure.Iot.Operations.Services.AssetAndDeviceRegistry.Models.AkriServiceErrorException: ApiError: assets.namespaces.deviceregistry.microsoft.com "my-rest-thermostat-asset2" not found: NotFound (ErrorResponse { status: "Failure", message: "assets.namespaces.deviceregistry.microsoft.com \"my-rest-thermostat-asset2\" not found", reason: "NotFound", code: 404 }) at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.<>c__DisplayClass19_0.<<SetNotificationPreferenceForAssetUpdatesAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.RunWithRetryAsync[TResult](Func`1 taskFunc, CancellationToken cancellationToken) --- End of inner exception stack trace --- at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.RunWithRetryAsync[TResult](Func`1 taskFunc, CancellationToken cancellationToken) at Azure.Iot.Operations.Services.AssetAndDeviceRegistry.AdrServiceClient.SetNotificationPreferenceForAssetUpdatesAsync(String deviceName, String inboundEndpointName, String assetName, NotificationPreference notificationPreference, Nullable`1 commandTimeout, CancellationToken cancellationToken) at Azure.Iot.Operations.Connector.AdrClientWrapper.AssetFileChanged(Object sender, AssetFileChangedEventArgs e) at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state) at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()Atualmente, lançar a imagem DevX como um container a partir do WSL, sem o Docker Desktop instalado, faz com que o container fique indefinidamente bloqueado.