Implantação eficiente de imagem do Docker para conectividade de baixa largura de banda

Registro de Contêiner do Azure
Funções do Azure
Azure IoT Edge
Hub IoT do Azure
Azure Pipelines

Este artigo descreve uma solução para implantar módulos de borda de Internet das Coisas (IoT) em contêineres em conexões de Internet com largura de banda intermitente ou baixa.

O processamento de borda é um padrão-chave da Internet das Coisas (IoT) para fornecer conectividade de baixa latência e conservar largura de banda, como em cenários móveis. Os sistemas de IoT normalmente provisionam dispositivos de borda implantando imagens de contêiner de software. Implantações de contêiner interrompidas em conexões de Internet com largura de banda intermitente e baixa podem causar falhas em cenários móveis. Os cenários de IoT em que a largura de banda é limitada, intermitente ou baixa precisam de funcionalidades de implantação confiáveis e resilientes.

Neste exemplo, uma grande empresa de logística queria melhorar o rastreamento das remessas de produtos em todo o mundo. A empresa enviava mercadorias usando vários métodos de transporte terrestre, aéreo e marítimo para muitas localidades, inclusive áreas em que a conectividade de internet tinha largura de banda intermitente e baixa. Dependendo do tipo de mercadoria, as remessas de produtos tinham vários dispositivos de seguro, segurança ou rastreamento de IoT instalados, com diferentes recursos. Os dispositivos incluíam rastreadores GPS, sensores de temperatura e ferramentas de captura de dados.

A empresa estava tendo problemas para atualizar os dispositivos pela plataforma Azure IoT Edge recém-desenvolvida. As principais dificuldades eram as seguintes:

  • Alto consumo de largura de banda ao implantar software atualizado em dispositivos.
  • Não havia uma implantação automatizada padronizada entre os dispositivos.
  • Flexibilidade limitada da seleção de tecnologia.

Para resolver esses problemas, a equipe de desenvolvimento criou uma solução que:

  • Minimiza o tamanho da implantação em cada dispositivo, reduzindo a largura de banda.
  • Implementa uma implantação padronizada de contêiner do Docker da plataforma IoT Edge para dispositivos IoT remotos heterogêneos.
  • Permite o monitoramento confiável da implantação.
  • Aproveita vários serviços de nuvem e do Azure DevOps, e usa as ferramentas herdadas preferidas do cliente.

A solução aumentou drasticamente a confiabilidade e a resiliência do processo de provisionamento de dispositivos em ambientes com conectividade limitada. Este artigo descreve os detalhes da solução e o processo de avaliação das opções de solução.

Requisitos do cliente

O cliente tinha os seguintes requisitos:

  • A solução deve permitir conectividade de nuvem de baixa largura de banda.
  • Os aplicativos implantados devem continuar sendo executados localmente.
  • A equipe local precisa usar a funcionalidade offline ou não pode haver atraso na viagem de ida e volta à nuvem.
  • Quando conectada, a solução deve usar a conexão com a nuvem de maneira eficiente.
  • A solução deve priorizar o envio de dados de acordo com regras de negócios definidas de modo consistente entre os produtos.

Havia também os seguintes requisitos detalhados:

  • Os arquivos de imagem são transferidos por meio de uma conexão por satélite com conectividade intermitente e baixa largura de banda.
  • A quantidade de dados sendo transferidos deve ser minimizada.
  • A transferência de arquivos para dispositivos usa o aplicativo de terceiros de preferência do cliente.
  • As cargas de trabalho de dispositivo usam imagens do Docker no IoT Edge.
  • Os tamanhos das imagens variam de dezenas de MB a vários GB.
  • Os módulos do IoT Edge são criados no .NET Core 2.2.

Possíveis casos de uso

Essa solução é adequada para cenários de IoT em que contêineres de software fornecem soluções por conexões intermitentes e de baixa largura de banda. Os exemplos incluem:

  • Monitoramento remoto de petróleo, gás e mineração
  • Atualizações automotivas over-the-air
  • Em qualquer lugar onde não há garantia de uma conexão forte

Arquitetura

Em cenários de alta largura de banda, o Azure IoT Edge recebe imagens diretamente de um registro do Docker acessível pela Internet, seja um hub do Docker ou um hub privado, como o Registro de Contêiner do Azure. Essa funcionalidade equivale a executar o comando docker pull <image_name>.

Com acesso à rede potencialmente intermitente, como uma conexão de Internet por satélite, o método pull do Docker não é confiável. O andamento não será armazenado em cache se a conexão com a Internet cair enquanto o Docker estiver recebendo a imagem. Quando a conexão com a Internet for retomada, o Docker deverá começar a receber a imagem novamente desde o início.

A solução usa um mecanismo de implantação alternativo, o patch binário de arquivos de imagem do Docker, para reduzir a largura de banda e compensar a conectividade intermitente.

Diagrama mostrando o Azure DevOps e a arquitetura de solução de alto nível do Azure.

Fluxo de dados

  1. Os desenvolvedores interagem com o código-fonte dos módulos de borda em um repositório de código-fonte.
  2. O Registro de Contêiner armazena as imagens do Docker de cada módulo.
  3. O repositório de manifesto contém os manifestos de implantação para todos os fluxos de trabalho.
  4. Cada módulo tem um pipeline de build do Azure Pipelines que usa uma compilação genérica do Docker para criar e registrar módulos automaticamente.
  5. O pipeline de imagem para dispositivo implanta as imagens do Docker nos dispositivos direcionados, conforme definido pelo arquivo de manifesto.
  6. O pipeline de manifesto para dispositivo envia o manifesto de implantação para o Hub IoT do Azure adequado para o dispositivo que está sendo atualizado.
  7. Uma solução de transferência rápida de arquivos de terceiros transfere os arquivos de uma conta do Armazenamento do Azure para o dispositivo.
  8. O módulo de Reconstrução de Imagem do IoT Edge aplica os patches recebidos nos dispositivos.
  9. O Hub IoT recebe mensagens de status do módulo de Reconstrução de Imagem e define o manifesto de implantação para o dispositivo. O restante do fluxo do pipeline usa esse manifesto de implantação.
  10. O Azure Functions monitora o fluxo de mensagens do Hub IoT, atualiza o banco de dados SQL e notifica o usuário sobre o êxito ou a falha.
  11. O Banco de Dados SQL do Azure rastreia ocorrências nos dispositivos de destino e nos serviços baseados no Azure, durante e após a implantação.

Componentes

  • O Azure IoT Edge executa cargas de trabalho em contêineres nos dispositivos, fornecendo conectividade de baixa latência e conservando a largura de banda.
  • O Hub IoT do Azure é um serviço gerenciado e hospedado na nuvem que atua como um hub central de mensagens entre os aplicativos de IoT e dispositivos de IoT por eles controlados.
  • O Registro de Contêiner do Azure é um serviço de registro privado baseado em nuvem para armazenar e gerenciar imagens privadas de contêiner do Docker e os artefatos relacionados.
  • O Azure Pipelines combina integração contínua (CI) e entrega contínua (CD) para automaticamente testar e compilar código e enviá-lo para qualquer destino.
  • O Azure Functions é uma plataforma de computação sem servidor que permite executar código disparado por eventos sem precisar provisionar ou gerenciar a infraestrutura.
  • O Armazenamento do Azure fornece armazenamento altamente escalonável, seguro, eficiente e econômico para todos os tipos de dados de negócios, objetos e arquivos.
  • O Banco de Dados SQL do Azure é um serviço de banco de dados relacional multimodelo totalmente gerenciado desenvolvido para a nuvem.
  • O Docker é uma plataforma aberta para desenvolver, enviar e executar aplicativos conteinerizados

Alternativas

A equipe de desenvolvimento avaliou diversas opções antes de decidir sobre a solução completa de transferência delta de imagem do Docker. As próximas seções descrevem as alternativas e os resultados da avaliação.

A equipe considerou os seguintes critérios de avaliação para cada opção:

  • Se a solução atendeu ou não aos requisitos.
  • Se era necessário implementar uma quantidade baixa, média ou alta de lógica nos dispositivos.
  • Se era necessário implementar uma quantidade baixa, média ou alta de lógica no Azure.
  • Eficiência da largura de banda, ou a proporção de dados transferidos em relação ao tamanho total de uma imagem, para transferir uma imagem quando:

A eficiência da largura de banda incluiu cenários em que:

  • Não existiam imagens no dispositivo.
  • Existia uma imagem com a mesma base no dispositivo.
  • Existia uma imagem no dispositivo de uma versão anterior de um aplicativo.
  • Existia no dispositivo uma imagem para o aplicativo criado com base em uma imagem base anterior.

A equipe usou os seguintes cenários para avaliar a eficiência da largura de banda:

Cenário Descrição
Transferir imagem com a camada base que já está no dispositivo Transferir uma nova imagem quando outra imagem já existente no dispositivo compartilha a imagem base. Esse cenário representa a implantação de um novo aplicativo pela primeira vez, quando já existe outro aplicativo no mesmo sistema operacional e estrutura.
Atualizar a camada de aplicativo Altere somente o código da imagem de um aplicativo existente. Esse cenário representa uma alteração típica quando um usuário confirma um novo recurso.
Atualizar a imagem base Altere a versão da imagem base em que o aplicativo foi criado.

Opção Transferir camadas do Docker

Uma imagem de contêiner do Docker é uma montagem UnionFS de diferenças de sistema de arquivos somente leitura, com outra camada gravável para as alterações feitas durante a execução do contêiner. Os sistemas de arquivos são chamados de camadas, que são basicamente pastas e arquivos. As camadas são empilhadas para formar a base do sistema de arquivos raiz do contêiner. Como as camadas são somente leitura, várias imagens podem compartilhar a mesma camada se tiverem a camada em comum.

A opção de transferir camadas do Docker reutiliza as camadas entre imagens e transfere apenas as novas camadas para o dispositivo. Essa opção seria mais útil para imagens que compartilham a mesma camada base, geralmente o sistema operacional, ou para atualizar versões de imagens existentes.

As desvantagens desse método incluem as seguintes:

  • O orquestrador deve manter informações sobre que camadas existem em quais dispositivos.
  • As alterações de camada base causam a alteração dos hashes de todas as camadas subsequentes.
  • A comparação requer hashes de camada consistentes.
  • Pode haver dependências de Docker save e Docker load.

Opção Modificar cliente do Docker

O foco dessa opção é modificar ou encapsular o cliente do Docker para que ele retome o download da camada após uma interrupção. Por padrão, um Docker pull retoma um download se a conexão com a Internet é restaurada em aproximadamente 30 minutos após a interrupção. Caso contrário, o cliente sai e perde todo o andamento do download.

Esse método é viável, mas teve complicações, como as seguintes:

  • Todas as imagens no dispositivo precisam ser registradas no daemon do Docker que recebe as imagens para maximizar a eficiência de largura de banda.
  • O projeto Docker de código aberto teria que ser modificado para suportar essa funcionalidade, o que traz um risco de rejeição por parte dos mantenedores de código aberto.
  • Transferir dados por HTTP em vez de usando a solução de transferência de arquivos rápida preferida do cliente exigiria o desenvolvimento de uma lógica de repetição personalizada.
  • Todas as camadas devem ser retransmitidas quando uma imagem base é alterada.

Opção Criar no dispositivo de borda

Esta abordagem muda o ambiente de compilação de imagem para os dispositivos. Os seguintes dados são enviados para o dispositivo:

  • O código-fonte do aplicativo que está sendo criado
  • Uma cópia de todos os pacotes NuGet dos quais o código depende
  • As imagens base do Docker para o ambiente de compilação e o runtime do .NET Core
  • Metadados sobre a imagem final

Um agente de compilação no dispositivo, por sua vez, compila a imagem e a registra no Gerenciador do Docker do dispositivo.

Essa solução foi rejeitada porque:

  • Ainda precisaria haver uma maneira de mover as imagens grandes do Docker para os dispositivos. As imagens para compilar os aplicativos .NET são maiores do que as imagens do aplicativo propriamente ditas.
  • Esse método funciona apenas para aplicativos dos quais a equipe tem o código-fonte, por isso não é possível usar imagens de terceiros.
  • A opção requer empacotar os pacotes NuGet e rastrear sua movimentação até os dispositivos.
  • Se uma imagem não fosse compilada no dispositivo, a equipe teria que depurar remotamente o ambiente de compilação e a imagem criada. A depuração remota exigiria um alto uso da conexão com a internet potencialmente limitada.

Opção de transferência delta de imagem completa

A abordagem escolhida trata uma imagem do Docker como um único arquivo binário. O comando save do Docker exporta a imagem como um arquivo .tar. A solução exporta as imagens novas e existentes do Docker e calcula o delta binário, que, quando aplicado, transforma a imagem existente na nova.

A solução rastreia as imagens existentes do Docker nos dispositivos e cria patches de delta binário para transformar as imagens existentes nas novas imagens. O sistema transfere somente os patches delta pela conexão com a internet de baixa largura de banda. Esta solução exigia uma certa lógica personalizada para criar os patches binários, mas enviava a menor quantidade de dados para os dispositivos.

Resultados de avaliação

A tabela a seguir mostra o desempenho de cada uma das soluções acima em relação aos critérios de avaliação.

Atende aos requisitos Lógica do dispositivo Lógica do Azure Transporte Primeira imagem Base no dispositivo Atualizar camada de aplicativo Atualizar camada base
Transferir camadas do Docker Yes Baixo Médio FileCatalyst 100% 10.5% 22.4% 100%
Modificar cliente do Docker Yes Médio Baixo HTTP 100% 10.5% 22.4% 100%
Criar no dispositivo de borda Não Alto Médio FileCatalyst N/D N/D N/D N/D
Transferência delta de imagem completa Yes Baixa Alta FileCatalyst 100% 3.2% 0.01% 16.1%

Considerações

Essas considerações implementam os pilares da Well-Architected Framework do Azure, um conjunto de princípios orientadores que melhoram a qualidade da carga de trabalho. Para obter mais informações, confira Microsoft Azure Well-Architected Framework.

Eficiência de desempenho

Esta solução reduziu drasticamente a largura de banda consumida pelas atualizações para dispositivos IoT. As tabelas a seguir mostram um detalhamento das diferenças na eficiência de transferência.

Reconstrutor de Imagem como fonte:

Nome da imagem Tamanho da imagem Tamanho do patch Redução de dados
Visualização de dados 228 MB 79.6 MB 65.1%
WCD simulado 188 MB 1.5 MB 99,2%
Proxy 258 MB 29.9 MB 88,4%

Versão anterior como fonte:

Nome da imagem Tamanho da imagem Tamanho do patch Redução de dados
Visualização de dados 228 MB 0.01 MB 99,9%
WCD simulado 188 MB 0.5 MB 99,7%
Proxy 258 MB 0.04 MB 99,9%

Excelência operacional

As próximas seções descrevem os detalhes do passo a passo da solução.

Repositório de código-fonte

Os desenvolvedores interagem com o código-fonte dos módulos de borda em um repositório de código-fonte. O repositório consiste em pastas que contêm o código de cada módulo, como segue:


\- repository root
    - modulea
    - modulea.csproj
    - module.json
    - Program.cs
    - Dockerfile

\- moduleb
    - moduleb.csproj
    - module.json
    - Program.cs
    - Dockerfile

O número recomendado de repositórios de código-fonte é:

  • Um repositório para todos os módulos em todos os fluxos de trabalho.
  • Um repositório de código-fonte para cada fluxo de trabalho.

Instâncias do Registro de Contêiner

O Registro de Contêiner armazena as imagens do Docker de cada módulo. Há duas configurações possíveis para o Registro de Contêiner:

  • Uma única instância do Registro de Contêiner que armazena todas as imagens.
  • Duas instâncias do Registro de Contêiner, sendo uma para armazenar as imagens de desenvolvimento, teste e depuração e outra que contém apenas as imagens marcadas como prontas para produção.

Repositório de manifesto

O repositório de manifesto contém os manifestos de implantação para todos os fluxos de trabalho. Os modelos ficam em pastas, com base no fluxo de trabalho. Neste exemplo, os dois fluxos de trabalho são infraestrutura compartilhada e o aplicativo conteinerizado.


\- repository root
     - Workstream1
         - deployment.template.json
     - Workstream2
         - deployment.template.json

Pipeline de build de imagem do Docker

Cada módulo tem um pipeline de build do Azure Pipelines. O pipeline usa uma compilação genérica do Docker para criar e registrar módulos. O pipeline é responsável por:

  • Verificação de segurança do código-fonte.
  • Verificação de segurança da imagem base para criar a imagem do Docker.
  • Executando testes de unidade para o módulo.
  • Compilação da fonte em uma imagem do Docker. A marcação da imagem contém BUILD_BUILDID, por isso a imagem pode ser sempre vinculada novamente ao código-fonte que a criou.
  • Enviando a imagem para uma instância do Registro de Contêiner.
  • Criando o arquivo delta.
  • Criando um arquivo de assinatura para a imagem e salvando o arquivo em uma conta de armazenamento do Azure.

Todas as instâncias de pipeline são baseadas em uma única definição de pipeline YAML. O pipeline pode atuar nos módulos usando variáveis de ambiente. Os filtros disparam cada pipeline somente quando as alterações são confirmadas em uma determinada pasta. Esse filtro evita a compilação de todos os módulos quando apenas um deles é atualizado.

Pipeline de imagem para dispositivo

O pipeline de imagem para dispositivo implanta as imagens do Docker nos dispositivos direcionados, conforme definido por um arquivo de manifesto. Disparar o pipeline inicia a implantação manualmente.

A definição de pipeline especifica a execução dessas implantações em um contêiner. Os pipelines permitem a entrada de variáveis nas quais as imagens devem basear os contêineres. Uma única variável pode controlar as implantações de todos os pipelines.

A imagem contém o código que determina quais patches compilar, compila os patches e os distribui para o lado do Azure da ferramenta de transferência de arquivos.

A ferramenta de distribuição de imagem precisa das seguintes informações:

  • Quais imagens devem ser implantadas, o que é informado pelo manifesto no repositório.
  • Em quais dispositivos implantar, o que é informado pelo usuário que dispara o pipeline.
  • Quais imagens já estão nos dispositivos direcionados, o que é informado por um banco de dados SQL do Azure.

As saídas do pipeline são as seguintes:

  • Os pacotes de patch enviados para o lado do Azure da ferramenta de transferência de arquivos, a serem distribuídos para os dispositivos.
  • As entradas do banco de dados SQL que marcam quais imagens começaram a ser transferidas para cada dispositivo.
  • As entradas do banco de dados SQL relativas aos novos conjuntos de implantação. Essas entradas incluem o nome e o endereço de email do usuário que solicitou a implantação.

Este pipeline realiza as seguintes etapas:

  1. Determina as imagens necessárias com base no manifesto de implantação.
  2. Consulta o SQL para saber quais imagens já estão nos dispositivos. Se todas as imagens já estão presentes, o pipeline é encerrado com êxito.
  3. Determina quais pacotes de patches devem ser criados. O algoritmo determina qual imagem inicial gera o menor pacote de patches.
    • Entradas: um arquivo .tar que contém a nova imagem a ser implantada e arquivos de assinatura das imagens existentes nos dispositivos.
    • Saída: uma classificação das imagens existentes para determinar o menor patch a ser criado.
  4. Cria os pacotes de patches necessários para cada dispositivo. Compila os patches semelhantes uma vez e os copia para todos os dispositivos que precisam deles.
  5. Distribui os patches para a conta de armazenamento da ferramenta de transferência de arquivos para implantação.
  6. Atualiza o SQL para marcar as novas imagens como in transit para cada um dos dispositivos direcionados.
  7. Adiciona as informações do conjunto de implantação ao SQL, com o nome e email de contato da pessoa que implantará a imagem.

Diagrama mostrando o arquivo original para o arquivo alterado do workflow de dados resultante.

Pipeline de manifesto para dispositivo

O pipeline de manifesto para dispositivo envia o manifesto de implantação à conexão do Hub IoT adequada para o dispositivo que está sendo atualizado. Um usuário dispara o pipeline manualmente e especifica uma variável de ambiente para a instância do Hub IoT a ser direcionada.

O pipeline:

  • Determina de quais imagens a implantação precisa.
  • Consulta o SQL para garantir que as imagens necessárias estão nos dispositivos direcionados. Caso contrário, o pipeline é encerrado com um status failed.
  • Envia o novo manifesto de implantação para o Hub IoT adequado.

Solução de transferência rápida de arquivos

O cliente queria continuar usando a solução de transferência rápida de arquivos de terceiros, chamada FileCatalyst, para fornecer a conexão entre o Azure e seus dispositivos IoT. Essa solução é uma ferramenta de transferência de arquivos eventualmente consistente, o que significa que uma transferência pode levar muito tempo, mas acabará sendo concluída sem perder nenhuma informação dos arquivos.

A solução usava uma conta do Armazenamento do Azure no lado do Azure da conexão e a VM host de transferência de arquivos existente do cliente para cada um dos dispositivos que recebiam as imagens. Os pacotes de patches são transferidos para uma VM Linux que executa o Hub IoT.

Módulo de Reconstrução de Imagem

O módulo de Reconstrução de Imagem do IoT Edge aplica os patches recebidos nos dispositivos. Cada dispositivo hospeda o próprio registro de contêiner local, usando o registro de código aberto do Docker. O processo de Reconstrução de Imagem é executado na VM host, que é a mesma VM de transferência de arquivos.

O módulo:

  1. Recebe o pacote de patches em uma pasta montada no contêiner.
  2. Descompacta o conteúdo do patch para ler o arquivo de configuração.
  3. Recebe a imagem base do registro de contêiner local por hash.
  4. Salva a imagem base como um arquivo .tar.
  5. Aplica o patch à imagem base.
  6. Carrega o arquivo .tar que contém a nova imagem para o Docker.
  7. Envia a nova imagem para o registro de contêiner local, com um arquivo de configuração que inclui um nome amigável e uma marcação.
  8. Envia uma mensagem de êxito para o Hub IoT.

Se o processo falha em algum momento, o módulo envia uma mensagem de falha ao Hub IoT para notificar o usuário que disparou a implantação.

Hub IoT

Vários processos de implantação usam o Hub IoT. Além de receber mensagens de status do módulo de Reconstrução de Imagem, o Hub IoT define o manifesto de implantação para o dispositivo. O restante do fluxo do pipeline usa esse manifesto.

Diagrama mostrando o patch do Centro de Operações e do dispositivo IoT para workflow do Reconstrutor de Imagem.

Azure Functions

O Azure Functions monitora o fluxo de mensagens provenientes do Hub IoT e executa ações na nuvem.

No caso de uma mensagem de êxito:

  • A função atualiza o status da entrada do SQL da imagem no dispositivo de in transit para succeeded.
  • Se essa for a última a chegar em um conjunto de implantação:
    • A função notifica o usuário sobre o êxito da implantação.
    • A função atualiza o pipeline de manifesto para dispositivo para começar a usar as novas imagens.

No caso de uma mensagem de falha:

  • A função atualiza o status da entrada do SQL da imagem no dispositivo de in transit para failed.
  • A função notifica o usuário sobre a falha na transferência da imagem.

Workflow de mensagem do reconstrutor de imagens do Centro de Operações e do dispositivo IoT

Banco de Dados SQL

Um banco de dados SQL rastreia ocorrências nos dispositivos de destino e nos serviços de implantação baseados no Azure durante e depois da implantação. O Azure Functions e o Azure Pipelines usam um pacote NuGet privado criado para interagir com o banco de dados.

O banco de dados SQL armazena os seguintes dados:

  • As imagens que estão em cada dispositivo.
  • As imagens que estão no caminho para cada dispositivo.
  • As imagens que estão sendo implantadas que pertencem a um conjunto.
  • O usuário que solicitou as implantações.

O objetivo deste exemplo era garantir que o sistema gerasse os dados necessários para futuros painéis de dados. A consulta ao Hub IoT pode fornecer os seguintes dados sobre o pipeline de manifesto para dispositivo:

  • O estado de uma implantação.
  • As imagens em um determinado dispositivo.
  • Os dispositivos que têm uma imagem.
  • Dados de série de tempo em transferências bem-sucedidas e com falha.
  • Consultas de implantações com base no usuário.

Colaboradores

Esse artigo é mantido pela Microsoft. Ele foi originalmente escrito pelos colaboradores a seguir.

Autor principal:

Próximas etapas