Implantar Orleans nos Aplicativos de Contêiner do Azure
Neste tutorial, você aprenderá a implantar um aplicativo de carrinho de compras do Orleans de exemplo nos Aplicativos de Contêiner do Azure. Este tutorial expande a funcionalidade do aplicativo de carrinho de compras de exemplo do Orleans, introduzido em Implantar o Orleans no Serviço de Aplicativo do Azure. O aplicativo de exemplo adiciona a autenticação B2C (entre empresas e consumidores) do Azure Active Directory (AAD) e é implantado nos Aplicativos de Contêiner do Azure.
Você aprenderá a implantar com o GitHub Actions, as CLIs do .NET e do Azure e o Azure Bicep. Além disso, você aprenderá a configurar a entrada HTTP do Aplicativo de Contêiner.
Neste tutorial, você aprenderá como:
- Implantar um aplicativo do Orleans nos Aplicativos de Contêiner do Azure
- Automatizar a implantação usando as GitHub Actions e o Azure Bicep
- Configurar a entrada HTTP
Pré-requisitos
- Uma conta do GitHub
- Leia uma introdução ao Orleans
- O SDK do .NET 6
- A CLI do Azure
- Um ambiente de desenvolvimento integrado do .NET (IDE)
- Fique à vontade para usar o Visual Studio ou o Visual Studio Code
Executar o aplicativo localmente
Para executar o aplicativo localmente, bifurque o repositório de Amostras do Azure: carrinho de compras Orleans no Aplicativos de Contêiner do Azure e clone-o em sua máquina local. Depois de clonado, abra a solução em um IDE de sua escolha. Se você estiver usando o Visual Studio, clique com o botão direito do mouse no projeto Orleans.ShoppingCart.Silo e selecione Definir como Projeto de Inicialização e execute o aplicativo. Caso contrário, você poderá executar o aplicativo usando o seguinte comando da CLI do .NET:
dotnet run --project Silo\Orleans.ShoppingCart.Silo.csproj
Para obter mais informações, confira dotnet run. Com o aplicativo em execução, você recebe uma página de aterrissagem que discute a funcionalidade do aplicativo. No canto superior direito, você verá um botão de entrada. Você pode se inscrever em uma conta ou entrar se já tiver uma. Uma vez conectado, você pode navegar e testar seus recursos. Toda a funcionalidade do aplicativo ao ser executado localmente depende da persistência na memória, do clustering local e usa o pacote NuGet Falso para gerar produtos falsos. Interrompa o aplicativo selecionando a opção Parar Depuração no Visual Studio ou pressionando Ctrl+C na CLI do .NET.
AAD B2C
Embora ensinar os conceitos de autenticação esteja além do escopo deste tutorial, você pode aprender como Criar um locatário do Azure Active Directory B2C e Registrar um aplicativo Web para consumi-lo. No caso desse aplicativo de exemplo de carrinho de compras, a URL dos Aplicativos de Contêiner implantada resultante precisará ser registrada no locatário B2C. Para obter mais informações, confira Autenticação e autorização no Blazor do ASP.NET Core.
Importante
Depois que o Aplicativo de Contêiner for implantado, você precisará registrar a URL do aplicativo no locatário B2C. Na maioria dos cenários de produção, você só precisará registrar a URL do aplicativo uma vez, pois ela não deve ser alterada.
Para ajudar a visualizar como o aplicativo é isolado no ambiente dos Aplicativos de Contêiner do Azure, confira o seguinte diagrama:
No diagrama anterior, todo o tráfego de entrada para o aplicativo é canalizado por meio de uma entrada HTTP protegida. O ambiente dos Aplicativos de Contêiner do Azure contém uma instância de aplicativo, que contém um host ASP.NET Core, que expõe a funcionalidade do aplicativo Blazor Server e Orleans.
Implantar nos Aplicativos de Contêiner do Azure
Para implantar o aplicativo nos Aplicativos de Contêiner do Azure, o repositório usa GitHub Actions. Antes que essa implantação possa ocorrer, você precisará de alguns recursos do Azure e precisará configurar o repositório GitHub corretamente.
Antes de implantar o aplicativo, você precisa criar um Grupo de Recursos do Azure (ou usar um existente). Para criar um novo Grupo de Recursos do Azure, use um dos seguintes artigos:
Anote o nome do grupo de recursos escolhido, você precisará dele mais tarde para implantar o aplicativo.
Criar uma entidade de serviço
Para automatizar a implantação do aplicativo, você precisará criar uma entidade de serviço. Essa é uma conta Microsoft que tem permissão para gerenciar 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 serão semelhantes às seguintes, mas com valores reais para seu cliente, assinatura e locatário:
{
"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 na área de transferência e continue para a próxima etapa.
Criar um segredo do GitHub
O GitHub fornece um mecanismo para criar segredos criptografados. Os segredos que você cria estão disponíveis para uso em fluxos de trabalho das GitHub Actions. Você verá como o GitHub Actions pode ser usado para automatizar a implantação do aplicativo, em conjunto com o Azure Bicep.
Bicep é uma DSL (linguagem específica de domínio) que usa uma sintaxe declarativa para implantar recursos do Azure. Para obter mais informações, confira O que é o Bicep? Usando a saída da etapa Criar uma entidade de serviço, você precisará criar o segredo AZURE_CREDENTIALS
do GitHub com as credenciais formatadas em JSON.
No repositório do GitHub, selecione Configurações>Segredos>Criar um novo segredo. Insira o nome AZURE_CREDENTIALS
e cole as credenciais JSON da etapa anterior no campo Valor.
Para obter mais informações, confira GitHub: segredos criptografados.
Preparar para a implantação do Azure
O aplicativo precisará ser empacotado para implantação. No projeto Orleans.ShoppingCart.Silos
, definimos um elemento Target
que é executado após a etapa Publish
. Isso vai compactar o diretório de publicação em um arquivo silo.zip:
<Target Name="ZipPublishOutput" AfterTargets="Publish">
<Delete Files="$(ProjectDir)\..\silo.zip" />
<ZipDirectory SourceDirectory="$(PublishDir)" DestinationFile="$(ProjectDir)\..\silo.zip" />
</Target>
Há muitas maneiras de implantar um aplicativo .NET nos Aplicativos de Contêiner do Azure. Neste tutorial, você usará os GitHub Actions, o Azure Bicep e os CLIs do .NET e do Azure. Considere o arquivo ./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 anterior do GitHub será:
- Publique o aplicativo de carrinho de compras como um arquivo zip, usando o comando dotnet publish.
- Faça logon no Azure usando as credenciais da etapa Criar uma entidade de serviço.
- Avalie o arquivo acr.bicep e inicie um grupo de implantação usando criar grupo de implantação de az.
- Obtenha o servidor de logon do ACR (Registro de Contêiner do Azure) do grupo de implantação.
- Faça logon no ACR usando o segredo dos repositórios
AZURE_CREDENTIALS
. - Compile e publique a imagem do silo no ACR.
- Avalie o arquivo main.bicep e inicie um grupo de implantação usando az deployment group create.
- Implantar o silo
- Logoff do Azure.
O fluxo de trabalho é acionado por um push na ramificação principal. Para obter mais informações, confira GitHub Actions e .NET.
Dica
Se você encontrar problemas ao executar o fluxo de trabalho, talvez seja necessário verificar se a entidade de serviço tem todos os namespaces de provedor necessários registrados. Os seguintes namespaces de provedor são obrigatórios:
Microsoft.App
Microsoft.ContainerRegistry
Microsoft.Insights
Microsoft.OperationalInsights
Microsoft.Storage
Para mais informações, confira Resolver erros de registro do provedor de recursos.
O Azure impõe convenções e restrições de nomenclatura para recursos. Você precisa atualizar os valores de arquivo deploy.yml para o seguinte:
UNIQUE_APP_NAME
SILO_IMAGE_NAME
AZURE_RESOURCE_GROUP_NAME
AZURE_RESOURCE_GROUP_LOCATION
Defina esses valores como o nome do aplicativo exclusivo, o nome e o local do grupo de recursos do Azure.
Para saber mais, confira Regras de nomenclatura e restrições para recursos do Azure.
Explorar os modelos do Bicep
Quando o comando az deployment group create
for executado, ele avaliará uma determinada referência de arquivo .bicep. Esse arquivo contém informações declarativas que detalham os recursos do Azure que você deseja implantar. Uma maneira de pensar nessa etapa é que ela provisiona todos os recursos para implantação.
Importante
Se você estiver usando o Visual Studio Code, a experiência de criação do bicep será melhorada ao usar a Extensão Bicep.
O primeiro arquivo Bicep avaliado é o arquivo acr.bicep. Esse arquivo contém os detalhes do recurso do servidor de logon do ACR (Registro de Contêiner do Azure):
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
Esse arquivo bicep gera o servidor de logon do ACR e o nome correspondente. O próximo arquivo Bicep encontrado contém mais do que apenas um único resource
. Considere o arquivo main.bicep composto principalmente por definições de delegação module
:
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 arquivo Bicep anterior:
- Faz referência a um recurso ACR
existing
, para obter mais informações, confira Azure Bicep: recursos existentes. - Define um
module env
delegado para o arquivo de definição environment.bicep. - Define um
module storageModule
delegado para o arquivo de definição storage.bicep. - Declara vários
envVars
compartilhados que são usados pelo módulo de silo. - Define um
module siloModule
delegado para o arquivo de definição container-app.bicep. - Gera a URL da ACA (isso pode ser usado potencialmente para atualizar um URI de redirecionamento de registro de aplicativo do AAD B2C existente).
O main.bicep é delegado para vários outros arquivos Bicep. O primeiro é o arquivo 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
O arquivo bicep define os recursos do Azure Log Analytics e do Application Insights. O recurso appInsights
é um tipo web
e o recurso logs
é um tipo PerGB2018
. O recurso appInsights
e o recurso logs
são provisionados no local do grupo de recursos. O recurso appInsights
está vinculado ao recurso logs
por meio da propriedade WorkspaceResourceId
. Há três saídas definidas neste bicep, usadas posteriormente pelos Aplicativos de Contêiner module
. Agora vamos examinar o arquivo 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 arquivo bicep anterior define o seguinte:
- Dois parâmetros para o nome do grupo de recursos e o nome do aplicativo.
- A definição de
resource storage
da conta de armazenamento. - Um único
output
que constrói a cadeia de conexão para a conta de armazenamento.
O último arquivo Bicep é o arquivo 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 mencionada anteriormente para o Bicep inclui um visualizador. Todos esses arquivos bicep são visualizados da seguinte maneira:
Resumo
À medida que você atualiza o código-fonte e push
é alterado para main
na ramificação do repositório, o fluxo de trabalho deploy.yml será executado. Ele provisiona os recursos do Azure definidos nos arquivos Bicep e implanta o aplicativo. As revisões são registradas automaticamente em seu Registro de Contêiner do Azure.
Além do visualizador da extensão bicep, a página do grupo de recursos portal do Azure seria semelhante ao exemplo a seguir após o provisionamento e a implantação do aplicativo: