Adicionar integração contínua aos builds de contêiner

A integração contínua é um processo de desenvolvimento de software no qual um aplicativo é mantido em um estado continuamente liberável fornecendo builds automatizados com cada commit para uma base de código específica. Você pode adicionar integração contínua a praticamente qualquer sistema de build, mas dois que são particularmente convenientes são GitHub Actions e Pipelines do Azure. Neste tópico, você verá como usar GitHub Actions ou Azure Pipelines para automatizar as etapas de build do Docker descritas em Usar contêineres para criar aplicativos do Azure Sphere.

Use GitHub Actions para compilar automaticamente seu contêiner

GitHub Actions permitir que você automatize seu processo de build diretamente de seus repositórios do GitHub. Assim, a primeira etapa para usar GitHub Actions é criar ou abrir um repositório GitHub que contenha o código do aplicativo. Este tópico pressupõe que você tenha criado um repositório GitHub contendo o aplicativo Blink gerado no Tutorial: crie um aplicativo de alto nível e que seu projeto se chama "Blink". Assim como acontece com qualquer projeto de integração contínua, certifique-se de que seu projeto seja criado localmente e forneça os artefatos esperados antes de tentar automatizar o processo. Neste exemplo, assumimos que, após um build bem-sucedido, o out diretório contém um arquivo Blink.imagepackage.

No diretório de nível superior do repositório do GitHub, crie um diretório chamado .devcontainer e crie um arquivo chamado Dockerfile nesse diretório com o seguinte conteúdo:

FROM mcr.microsoft.com/azurespheresdk:latest AS dev

FROM dev AS build
COPY ./ /src/
WORKDIR /out
RUN cmake -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="/opt/azurespheresdk/CMakeFiles/AzureSphereToolchain.cmake" \
    -DAZURE_SPHERE_TARGET_API_SET="latest-lts" -DCMAKE_BUILD_TYPE="Release" "/src"
ENTRYPOINT [ "ninja" ]

A linha inicial FROM especifica a imagem padrão do Docker do Azure Sphere como o contêiner de desenvolvimento base e a segunda diz para usar esse contêiner base como o ambiente de build. A COPY linha copia o conteúdo do repositório no diretório /src/do contêiner. O WORKDIR especifica o diretório de build. O RUN comando fornece o comando CMake para gerar os arquivos de build. Por fim, o especifica que o ENTRYPOINT ninja deve ser invocado para realmente criar o aplicativo.

No diretório de nível superior do repositório, crie o diretório .github/workflows e adicione um arquivo chamado ci.yml com o seguinte conteúdo:

# This is a basic workflow to help you get started with Actions

name: ContinuousIntegration

# Controls when the action will run. Triggers the workflow on push or pull request
# events, but including workflow_dispatch also allows manual execution
on:
  push:
  pull_request:
  workflow_dispatch:


jobs:
  build:
    runs-on: ubuntu-latest
    name: Build Azure Sphere Apps
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Build image for az sphere builds and Start container from build image
      run: |
        docker build --target build -t hlbuildimage -f .devcontainer/Dockerfile .
        docker run --name hlbuildcontainer hlbuildimage
    - name: Copy container build output
      run:
        docker cp hlbuildcontainer:/out HLOutput
    - name: Publish HL imagepackage
      uses: actions/upload-artifact@v2
      with:
        name: HL imagepackage
        path: ${{ github.workspace }}/HLOutput/Blink.imagepackage

Esse fluxo de trabalho tem apenas um trabalho para criar o aplicativo; o trabalho é executado em um GitHub Actions corredor, nesse caso ubuntu-latest, e tem quatro etapas:

  1. Etapa 1, Checkout, é uma ação padrão do GitHub que simplesmente verifica seu repositório para o gerenciador mais recente do ubuntu.

  2. A etapa 2 cria a imagem (docker build) e inicia o contêiner (docker run).

  3. A etapa 3 copia a saída do contêiner para o corredor.

  4. Etapa 4, Publicar pacote de imagens HL, publica o pacote de imagens de aplicativo de alto nível como um artefato.

Confirme essas alterações no branch main e selecione Ações. Agora você deve ver uma página rotulada como "Todos os fluxos de trabalho", com pelo menos um fluxo de trabalho em execução ou concluído. Se o fluxo de trabalho for concluído com êxito, uma marca de marcar verde será exibida ao lado dele. Clique em um fluxo de trabalho bem-sucedido e você deve ver uma caixa rotulada como "Artefatos" contendo um artefato rotulado como "pacote de imagens HL". Baixe este artefato e descompacte o arquivo imagepackage; em seguida, você pode criar uma implantação ou carregar o aplicativo em seu dispositivo.

Usar o Azure Pipelines para compilar automaticamente seu contêiner

Os Pipelines do Azure permitem automatizar seu processo de build diretamente de seus repositórios do GitHub (e muitos outros repositórios de código também). Este tópico pressupõe que você já pertence a uma organização com um projeto do Azure DevOps e tenha acesso ao Azure Pipelines. A primeira etapa para usar o Azure Pipelines é criar ou abrir um repositório que contenha o código do aplicativo. Este tópico pressupõe que você tenha criado um repositório GitHub contendo o aplicativo Blink gerado no Tutorial: Criar um aplicativo de alto nível.

No diretório de nível superior deste repositório, crie o diretório .devcontainer e crie um arquivo dockerfile nesse diretório com o seguinte conteúdo:

FROM mcr.microsoft.com/azurespheresdk:latest AS dev

FROM dev AS build
COPY ./ /src/
WORKDIR /out
RUN cmake -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="/opt/azurespheresdk/CMakeFiles/AzureSphereToolchain.cmake" \
    -DAZURE_SPHERE_TARGET_API_SET="latest-lts" -DCMAKE_BUILD_TYPE="Release" "/src"
ENTRYPOINT [ "ninja" ]

A linha inicial FROM especifica a imagem padrão do Docker do Azure Sphere como o contêiner de desenvolvimento base e a segunda diz para usar esse contêiner base como o ambiente de build. A COPY linha copia o conteúdo do repositório no diretório /src/do contêiner. O WORKDIR especifica o diretório de build. O RUN comando fornece o comando CMake para gerar os arquivos de build. Por fim, o especifica que o ENTRYPOINT ninja deve ser invocado para realmente criar o aplicativo.

Para criar o pipeline:

  1. Faça logon no projeto do Azure DevOps e abra Pipelines.
  2. Selecione Novo Pipeline e, em seguida, selecione GitHub quando perguntado Onde está seu código? Você pode ser levado para uma página de autenticação do GitHub; conclua a autenticação e continue até a página para selecionar seu repositório.
  3. Selecione seu repositório Blink. Você é levado para uma página intitulada Configurar seu pipeline.
  4. Selecione Pipeline de inicialização. Isso abre um arquivo chamado azure-pipelines.yml no diretório de nível superior do seu repositório com uma tarefa Hello, World.
  5. Selecione Salvar e executar. Aceite o mensagem do commit padrão e, novamente, selecione Salvar e executar. O arquivo azure-pipelines.yml está comprometido com seu repositório GitHub e o pipeline é criado.

Substitua o conteúdo do arquivo azure-pipelines.yml pelo seguinte conteúdo:

# Docker
# Build a Docker image
# /azure/devops/pipelines/languages/docker

trigger:
- main

resources:
- repo: self

variables:
  tag: '$(Build.BuildId)'

stages:
- stage: Build
  displayName: Build image
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - bash: docker build --target build -t hlbuildimage -f .devcontainer/Dockerfile . &&  docker run --name hlbuildcontainer hlbuildimage && docker cp hlbuildcontainer:/out $(Build.ArtifactStagingDirectory)/HLOutput
      displayName: Build high-level Azure Sphere application in a container and copy the output
    - task: PublishBuildArtifacts@1
      displayName: Publish build artifacts
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)/HLOutput/Blink.imagepackage'
        ArtifactName: 'BlinkSample.imagepackage'
        publishLocation: 'Container'

Esse fluxo de trabalho tem apenas um trabalho para criar o aplicativo; o trabalho é executado em um agente do Azure DevOps, nesse caso ubuntu-latest, e tem duas etapas:

  1. A etapa 1 cria a imagem (docker build), inicia o contêiner (docker run) e copia a saída do contêiner para o agente.

  2. Etapa 2, Publicar artefatos de build, publica o pacote de imagens de aplicativo de alto nível como um artefato.

Confirme essas alterações no branch main. No Azure DevOps, abra Pipelines novamente. Você deve ver uma execução do pipeline em andamento ou apenas concluída. Se a execução mostrar uma marca de seleção verde, o build foi bem-sucedido. Selecione a execução bem-sucedida; você deve ver 1 Publicado na coluna Relacionado . Baixe este artefato e descompacte o arquivo imagepackage; em seguida, você pode criar uma implantação ou carregar o aplicativo em seu dispositivo.

Adicionar integração contínua a aplicativos de exemplo do Azure Sphere

GitHub Actions e a Azure Pipelines destinam-se a automatizar builds para um único projeto, como os baixados do navegador de exemplos da Microsoft. Os Exemplos do Azure Sphere no GitHub são uma coleção de projetos com alguns recursos compartilhados. Para usar um desses exemplos na integração contínua, você precisa incorporar todos os recursos compartilhados necessários. Normalmente, isso significa pelo menos criar um diretório HardwareDefinitions no diretório de nível superior do seu projeto e editar o arquivo CMakeLists.txt para apontar para a cópia local. Por exemplo, se você criar um projeto com base no exemplo helloworld/HelloWorld_HighLevelApp, o diretório de nível superior inicialmente se parece com este:

.vscode
.gitignore
applibs_versions.h
app_manifest.json
CMakeLists.txt
CMakeSettings.json
launch.vs.json
LICENSE.txt
main.c
README.md

O arquivo CMakeLists.txt contém a seguinte linha apontando para o diretório HardwareDefinitions compartilhado no repositório Exemplos:

azsphere_target_hardware_definition(${PROJECT_NAME} TARGET_DIRECTORY "../../../HardwareDefinitions/mt3620_rdb" TARGET_DEFINITION "sample_appliance.json")

Para permitir que seu projeto seja criado, copie a pasta HardwareDefinitions no diretório de nível superior e edite o arquivo CMakeLists.txt para usar o local:

azsphere_target_hardware_definition(${PROJECT_NAME} TARGET_DIRECTORY "HardwareDefinitions/mt3620_rdb" TARGET_DEFINITION "sample_appliance.json")

Novamente, verifique se o projeto é criado localmente antes de tentar automatizar com GitHub Actions.