Partilhar via


Implementar Orleans no Azure Container Apps

Neste tutorial, irá aprender a implementar uma aplicação de carrinho de compras de exemplo Orleans no Azure Container Apps. Este tutorial expande a funcionalidade da aplicação do carrinho de compras de exemploOrleans, introduzida em Implementar Orleans no Serviço de Aplicações do Azure. A aplicação de exemplo adiciona a autenticação empresa-consumidor (B2C) do Azure Active Directory (AAD) e implementa no Azure Container Apps.

Irá aprender a implementar com GitHub Actions, as CLIs do .NET e do Azure e o Azure Bicep. Além disso, irá aprender a configurar a entrada HTTP da Aplicação de Contentor.

Neste tutorial, ficará a saber como:

  • Implementar uma aplicação no Orleans Azure Container Apps
  • Automatizar a implementação com o GitHub Actions e o Azure Bicep
  • Configurar a entrada HTTP

Pré-requisitos

Executar a aplicação localmente

Para executar a aplicação localmente, fork the Azure Samples: Orleans shopping cart on Azure Container Apps repository and clone it to your local machine. Depois de clonada, abra a solução num IDE à sua escolha. Se estiver a utilizar o Visual Studio, clique com o botão direito do rato em Orleans. ShoppingCart.Silo project e selecione Definir Como Projeto de Arranque e, em seguida, execute a aplicação. Caso contrário, pode executar a aplicação com o seguinte comando da CLI de .NET:

dotnet run --project Silo\Orleans.ShoppingCart.Silo.csproj

Para obter mais informações, consulte Executar dotnet. Com a aplicação em execução, é-lhe apresentada uma página de destino que discute a funcionalidade da aplicação. No canto superior direito, verá um botão de início de sessão. Pode inscrever-se numa conta ou iniciar sessão se já tiver uma conta. Depois de iniciar sessão, pode navegar e pode testar as respetivas capacidades. Todas as funcionalidades da aplicação ao executar localmente dependem da persistência dentro da memória, do clustering local e utiliza o pacote NuGet Bogus para gerar produtos falsos. Pare a aplicação selecionando a opção Parar Depuração no Visual Studio ou premindo Ctrl+C na CLI .NET.

AAD B2C

Embora o ensino dos conceitos de autenticação esteja fora do âmbito deste tutorial, pode aprender a Criar um inquilino do Azure Active Directory B2C e, em seguida, pode Registar uma aplicação Web para a consumir. No caso desta aplicação de exemplo de carrinho de compras, o URL do Container Apps implementado resultante terá de ser registado no inquilino B2C. Para obter mais informações, veja ASP.NET Core autenticação e autorização do Blazor.

Importante

Após a implementação da Aplicação de Contentor, terá de registar o URL da aplicação no inquilino B2C. Na maioria dos cenários de produção, só terá de registar o URL da aplicação uma vez, uma vez que não deve ser alterado.

Para ajudar a visualizar como a aplicação está isolada no ambiente do Azure Container Apps, veja o seguinte diagrama:

Entrada HTTP do Azure Container Apps.

No diagrama anterior, todo o tráfego de entrada para a aplicação é canalizado através de uma entrada HTTP segura. O ambiente do Azure Container Apps contém uma instância de aplicação e a instância da aplicação contém um anfitrião ASP.NET Core, que expõe a funcionalidade do Servidor Blazor e Orleans da aplicação.

Implementar no Azure Container Apps

Para implementar a aplicação no Azure Container Apps, o repositório utiliza GitHub Actions. Antes de esta implementação poder ocorrer, precisará de alguns recursos do Azure e terá de configurar corretamente o repositório do GitHub.

Antes de implementar a aplicação, tem de criar um Grupo de Recursos do Azure (ou pode optar por utilizar um existente). Para criar um novo Grupo de Recursos do Azure, utilize um dos seguintes artigos:

Tome nota do nome do grupo de recursos que escolher, precisará dele mais tarde para implementar a aplicação.

Criar um principal de serviço

Para automatizar a implementação da aplicação, terá de criar um principal de serviço. Esta é uma conta Microsoft que tem permissão para gerir recursos do Azure em seu nome.

az ad sp create-for-rbac --sdk-auth --role Contributor \
  --name "<display-name>"  --scopes /subscriptions/<your-subscription-id>

As credenciais JSON criadas terão um aspeto semelhante ao seguinte, mas com valores reais para o seu cliente, subscrição e inquilino:

{
  "clientId": "<your client id>",
  "clientSecret": "<your client secret>",
  "subscriptionId": "<your subscription id>",
  "tenantId": "<your tenant id>",
  "activeDirectoryEndpointUrl": "https://login.microsoftonline.com/",
  "resourceManagerEndpointUrl": "https://brazilus.management.azure.com",
  "activeDirectoryGraphResourceId": "https://graph.windows.net/",
  "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
  "galleryEndpointUrl": "https://gallery.azure.com",
  "managementEndpointUrl": "https://management.core.windows.net"
}

Copie a saída do comando para a área de transferência e avance para o passo seguinte.

Criar um segredo do GitHub

O GitHub fornece um mecanismo para criar segredos encriptados. Os segredos que criar estão disponíveis para utilização em fluxos de trabalho GitHub Actions. Verá como GitHub Actions podem ser utilizadas para automatizar a implementação da aplicação, em conjunto com o AzureBicep. Bicep é uma linguagem específica do domínio (DSL) que utiliza uma sintaxe declarativa para implementar recursos do Azure. Para obter mais informações, veja O que é o Bicep. Com a saída do passo Criar um principal de serviço , terá de criar um segredo do GitHub com o nome AZURE_CREDENTIALS com as credenciais formatadas em JSON.

No repositório do GitHub, selecione Definições Segredos>>Criar um novo segredo. Introduza o nome AZURE_CREDENTIALS e cole as credenciais JSON do passo anterior no campo Valor .

Repositório do GitHub: Definições de Segredos >

Para obter mais informações, consulte GitHub: Segredos Encriptados.

Preparar a implementação do Azure

A aplicação terá de ser empacotada para implementação. Orleans.ShoppingCart.Silos No projeto, definimos um Target elemento que é executado após o Publish passo. Isto irá zipar o diretório de publicação num ficheiro desilo.zip :

<Target Name="ZipPublishOutput" AfterTargets="Publish">
    <Delete Files="$(ProjectDir)\..\silo.zip" />
    <ZipDirectory SourceDirectory="$(PublishDir)" DestinationFile="$(ProjectDir)\..\silo.zip" />
</Target>

Existem várias formas de implementar uma aplicação .NET no Azure Container Apps. Neste tutorial, vai utilizar GitHub Actions, o Azure Bicep e as CLIs do .NET e do Azure. Considere o ficheiro ./github/workflows/deploy.yml na raiz do repositório do GitHub:

name: Deploy to Azure Container Apps

on:
  push:
    branches:
    - main

env:
  UNIQUE_APP_NAME: orleanscart
  SILO_IMAGE_NAME: orleanscart-silo
  AZURE_RESOURCE_GROUP_NAME: orleans-resourcegroup
  AZURE_RESOURCE_GROUP_LOCATION: eastus

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Setup .NET 6.0
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 6.0.x

    - name: .NET publish shopping cart app
      run: dotnet publish ./Silo/Orleans.ShoppingCart.Silo.csproj --configuration Release

    - name: Login to Azure
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Flex ACR Bicep
      run: |
        az deployment group create \
          --resource-group ${{ env.AZURE_RESOURCE_GROUP_NAME }} \
          --template-file '.github/workflows/flex/acr.bicep' \
          --parameters location=${{ env.AZURE_RESOURCE_GROUP_LOCATION }}

    - name: Get ACR Login Server
      run: |
        ACR_NAME=$(az deployment group show -g ${{ env.AZURE_RESOURCE_GROUP_NAME }} -n acr \
        --query properties.outputs.acrName.value | tr -d '"')
        echo "ACR_NAME=$ACR_NAME" >> $GITHUB_ENV
        ACR_LOGIN_SERVER=$(az deployment group show -g ${{ env.AZURE_RESOURCE_GROUP_NAME }} -n acr \
        --query properties.outputs.acrLoginServer.value | tr -d '"')
        echo "ACR_LOGIN_SERVER=$ACR_LOGIN_SERVER" >> $GITHUB_ENV

    - name: Prepare Docker buildx
      uses: docker/setup-buildx-action@v1

    - name: Login to ACR
      run: |
        access_token=$(az account get-access-token --query accessToken -o tsv)
        refresh_token=$(curl https://${{ env.ACR_LOGIN_SERVER }}/oauth2/exchange -v \
        -d "grant_type=access_token&service=${{ env.ACR_LOGIN_SERVER }}&access_token=$access_token" | jq -r .refresh_token)
        # The null GUID 0000... tells the container registry that this is an ACR refresh token during the login flow
        docker login -u 00000000-0000-0000-0000-000000000000 \
        --password-stdin ${{ env.ACR_LOGIN_SERVER }} <<< "$refresh_token"

    - name: Build and push Silo image to registry
      uses: docker/build-push-action@v2
      with:
        push: true
        tags: ${{ env.ACR_LOGIN_SERVER }}/${{ env.SILO_IMAGE_NAME }}:${{ github.sha }}
        file: Silo/Dockerfile

    - name: Flex ACA Bicep
      run: |
        az deployment group create \
          --resource-group ${{ env.AZURE_RESOURCE_GROUP_NAME }} \
          --template-file '.github/workflows/flex/main.bicep' \
          --parameters location=${{ env.AZURE_RESOURCE_GROUP_LOCATION }} \
            appName=${{ env.UNIQUE_APP_NAME }} \
            acrName=${{ env.ACR_NAME }} \
            repositoryImage=${{ env.ACR_LOGIN_SERVER }}/${{ env.SILO_IMAGE_NAME }}:${{ github.sha }} \
          --debug

    - name: Get Container App URL
      run: |
        ACA_URL=$(az deployment group show -g ${{ env.AZURE_RESOURCE_GROUP_NAME }} \
        -n main --query properties.outputs.acaUrl.value | tr -d '"')
        echo $ACA_URL

    - name: Logout of Azure
      run: az logout

O fluxo de trabalho do GitHub anterior:

  • Publique a aplicação do carrinho de compras como um ficheiro zip com o comando dotnet publish .
  • Inicie sessão no Azure com as credenciais do passo Criar um principal de serviço .
  • Avalie o ficheiro acr.bicep e inicie um grupo de implementação com az deployment group create.
  • Obtenha o servidor de início de sessão do Azure Container Registry (ACR) a partir do grupo de implementação.
  • Inicie sessão no ACR com o segredo dos repositórios AZURE_CREDENTIALS .
  • Crie e publique a imagem de silo no ACR.
  • Avalie o ficheiro main.bicep e inicie um grupo de implementação com az deployment group create.
  • Implementar o silo
  • Fim de sessão do Azure.

O fluxo de trabalho é acionado por um push para o ramo principal . Para obter mais informações, veja GitHub Actions e .NET.

Dica

Se encontrar problemas ao executar o fluxo de trabalho, poderá ter de verificar se o principal de serviço tem todos os espaços de nomes de fornecedor necessários registados. São necessários os seguintes espaços de nomes de fornecedor:

  • Microsoft.App
  • Microsoft.ContainerRegistry
  • Microsoft.Insights
  • Microsoft.OperationalInsights
  • Microsoft.Storage

Para obter mais informações, veja Resolver erros de registo do fornecedor de recursos.

O Azure impõe restrições de nomenclatura e convenções para recursos. Tem de atualizar os valores de ficheiro deploy.yml para o seguinte:

  • UNIQUE_APP_NAME
  • SILO_IMAGE_NAME
  • AZURE_RESOURCE_GROUP_NAME
  • AZURE_RESOURCE_GROUP_LOCATION

Defina estes valores para o nome exclusivo da aplicação e o nome e localização do grupo de recursos do Azure.

Para obter mais informações, veja Regras de nomenclatura e restrições para recursos do Azure.

Explorar os modelos do Bicep

Quando o az deployment group create comando é executado, avaliará uma determinada referência de ficheiro .bicep . Este ficheiro contém informações declarativas que detalham os recursos do Azure que pretende implementar. Uma forma de pensar neste passo é que aprovisiona todos os recursos para implementação.

Importante

Se estiver a utilizar o Visual Studio Code, a experiência de criação do Bicep é melhorada ao utilizar a Extensão bicep.

O primeiro ficheiro Bicep que é avaliado é o ficheiro acr.bicep . Este ficheiro contém os detalhes do recurso do servidor de início de sessão do Azure Container Registry (ACR):

param location string = resourceGroup().location

resource acr 'Microsoft.ContainerRegistry/registries@2021-09-01' = {
  name: toLower('${uniqueString(resourceGroup().id)}acr')
  location: location
  sku: {
    name: 'Basic'
  }
  properties: {
    adminUserEnabled: true
  }
}

output acrLoginServer string = acr.properties.loginServer
output acrName string = acr.name

Este ficheiro bicep produz o servidor de início de sessão do ACR e o nome correspondente. O ficheiro Bicep seguinte encontrado contém mais do que apenas um único resource. Considere o ficheiro main.bicep composto principalmente por delegar module definições:

param appName string
param acrName string
param repositoryImage string
param location string = resourceGroup().location

resource acr 'Microsoft.ContainerRegistry/registries@2021-09-01' existing = {
  name: acrName
}

module env 'environment.bicep' = {
  name: 'containerAppEnvironment'
  params: {
    location: location
    operationalInsightsName: '${appName}-logs'
    appInsightsName: '${appName}-insights'
  }
}

var envVars = [
  {
    name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
    value: env.outputs.appInsightsInstrumentationKey
  }
  {
    name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
    value: env.outputs.appInsightsConnectionString
  }
  {
    name: 'ORLEANS_AZURE_STORAGE_CONNECTION_STRING'
    value: storageModule.outputs.connectionString
  }
  {
    name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED'
    value: 'true'
  }
]

module storageModule 'storage.bicep' = {
  name: 'orleansStorageModule'
  params: {
    name: '${appName}storage'
    location: location
  }
}

module siloModule 'container-app.bicep' = {
  name: 'orleansSiloModule'
  params: {
    appName: appName
    location: location
    containerAppEnvironmentId: env.outputs.id
    repositoryImage: repositoryImage
    registry: acr.properties.loginServer
    registryPassword: acr.listCredentials().passwords[0].value
    registryUsername: acr.listCredentials().username
    envVars: envVars
  }
}

output acaUrl string = siloModule.outputs.acaUrl

O ficheiro Bicep anterior:

  • Referencia um existing recurso do ACR, para obter mais informações, veja Azure Bicep: Recursos existentes.
  • Define um module env que delega para o ficheiro de definição environment.bicep .
  • Define um module storageModule que delega para o ficheiro de definição storage.bicep .
  • Declara vários partilhados envVars que são utilizados pelo módulo silo.
  • Define um module siloModule que delega para o ficheiro de definição container-app.bicep .
  • Produz o URL da ACA (isto pode potencialmente ser utilizado para atualizar o URI de redirecionamento de uma aplicação B2C existente).

O main.bicep delega vários outros ficheiros Bicep. O primeiro é o ficheiro environment.bicep :

param operationalInsightsName string
param appInsightsName string
param location string

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: appInsightsName
  location: location
  kind: 'web'
  properties: {
    Application_Type: 'web'
    WorkspaceResourceId: logs.id
  }
}

resource logs 'Microsoft.OperationalInsights/workspaces@2021-06-01' = {
  name: operationalInsightsName
  location: location
  properties: {
    retentionInDays: 30
    features: {
      searchVersion: 1
    }
    sku: {
      name: 'PerGB2018'
    }
  }
}

resource env 'Microsoft.App/managedEnvironments@2022-03-01' = {
  name: '${resourceGroup().name}env'
  location: location
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logs.properties.customerId
        sharedKey: logs.listKeys().primarySharedKey
      }
    }
  }
}

output id string = env.id
output appInsightsInstrumentationKey string = appInsights.properties.InstrumentationKey
output appInsightsConnectionString string = appInsights.properties.ConnectionString

Este ficheiro bicep define os recursos do Azure Log Analytics e do Application Insights. O appInsights recurso é um web tipo e o logs recurso é um PerGB2018 tipo. Tanto o appInsights recurso como o logs recurso são aprovisionados na localização do grupo de recursos. O appInsights recurso está ligado ao logs recurso através da WorkspaceResourceId propriedade . Existem três saídas definidas neste bíceps, utilizadas posteriormente pelas Container Apps module. Em seguida, vamos ver o ficheiro storage.bicep :

param name string
param location string

resource storage 'Microsoft.Storage/storageAccounts@2021-08-01' = {
  name: name
  location: location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
}

var key = listKeys(storage.name, storage.apiVersion).keys[0].value
var protocol = 'DefaultEndpointsProtocol=https'
var accountBits = 'AccountName=${storage.name};AccountKey=${key}'
var endpointSuffix = 'EndpointSuffix=${environment().suffixes.storage}'

output connectionString string = '${protocol};${accountBits};${endpointSuffix}'

O ficheiro Bicep anterior define o seguinte:

  • Dois parâmetros para o nome do grupo de recursos e o nome da aplicação.
  • A resource storage definição da conta de armazenamento.
  • Um único output que constrói a cadeia de ligação para a conta de armazenamento.

O último ficheiro Bicep é o ficheiro container-app.bicep :

param appName string
param location string
param containerAppEnvironmentId string
param repositoryImage string = 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
param envVars array = []
param registry string
param registryUsername string
@secure()
param registryPassword string

resource containerApp 'Microsoft.App/containerApps@2022-03-01' = {
  name: appName
  location: location
  properties: {
    managedEnvironmentId: containerAppEnvironmentId
    configuration: {
      activeRevisionsMode: 'multiple'
      secrets: [
        {
          name: 'container-registry-password'
          value: registryPassword
        }
      ]
      registries: [
        {
          server: registry
          username: registryUsername
          passwordSecretRef: 'container-registry-password'
        }
      ]
      ingress: {
        external: true
        targetPort: 80
      }
    }
    template: {
      revisionSuffix: uniqueString(repositoryImage, appName)
      containers: [
        {
          image: repositoryImage
          name: appName
          env: envVars
        }
      ]
      scale: {
        minReplicas: 1
        maxReplicas: 1
      }
    }
  }
}

output acaUrl string = containerApp.properties.configuration.ingress.fqdn

A extensão do Visual Studio Code para Bicep acima mencionada inclui um visualizador. Todos estes ficheiros Bicep são visualizados da seguinte forma:

Orleans: Composição do visualizador de aprovisionamento de bicep da aplicação de exemplo do carrinho de compras.

Resumo

À medida que atualiza o código fonte e push muda para o main ramo do repositório, o fluxo de trabalho deploy.yml será executado. Aprovisiona os recursos do Azure definidos nos ficheiros bicep e implementa a aplicação. As revisões são registadas automaticamente no seu Azure Container Registry.

Além do visualizador da extensão bicep, a página portal do Azure grupo de recursos teria um aspeto semelhante ao seguinte exemplo após o aprovisionamento e implementação da aplicação:

Portal do Azure: Orleans recursos da aplicação de exemplo do carrinho de compras para o Azure Container Apps.

Ver também