ASP.NET Deploy com GitHub Actions e Microsoft Azure
Fazer o deploy com GitHub Actions de aplicações ASP.NET no Microsoft Azure talvez seja a escolha mais simples e prática para manter a entrega contínua em dia. Neste artigo, você vai configurar todo o processo pela linha de comando, usando o Azure CLI e o GitHub CLI, com uma aplicação ASP.NET Core 3.1.
Também existe um vídeo que mostra essa mesma integração de forma visual, pelo portal. Ele complementa o passo a passo deste texto.
O que é CI/CD
Os termos CI e CD fazem parte da cultura DevOps. O objetivo deles é garantir a entrega e a integridade das nossas aplicações.
CI é a sigla para Continuous Integration, ou integração contínua. Na prática, é no CI que executamos o build e os testes para garantir que nada quebrou.
Continuous delivery e continuous deployment
CD pode significar Continuous Delivery ou Continuous Deployment. A entrega contínua tem um ritmo mais fixo, como releases diárias, semanais ou mensais, de acordo com o negócio.
Já o Continuous Deployment está um passo à frente. Nele, a publicação acontece sempre que as mudanças de código passam pelas etapas de integração.
Neste artigo, vamos cobrir o Continuous Deployment. Ou seja, cada push na branch master gera uma nova publicação automaticamente.
Ferramentas para o deploy com GitHub Actions
Antes de configurar o deploy com GitHub Actions, você precisa do Visual Studio Code e do SDK do .NET Core instalados. Caso ainda não tenha, siga o guia de instalação e primeiros passos com o .NET antes de prosseguir.
Também vale ter o Git configurado na máquina. Se precisar de ajuda, o artigo sobre Git e GitHub cobre a instalação e os primeiros comandos.
Azure CLI
A segunda instalação necessária é o Azure CLI. Ele habilita o comando az no terminal e permite criar e gerenciar recursos do Azure sem abrir o portal.
GitHub CLI
Em seguida, precisamos do GitHub CLI. Ele habilita o comando gh, que cria e clona repositórios direto do terminal.
Windows Terminal
Este item não é obrigatório, mas fica como recomendação. Se você usa Windows, o Windows Terminal torna o trabalho com várias abas e shells bem mais confortável.
Criando o Web App no Microsoft Azure
Tanto faz criar primeiro o Web App ou o repositório no GitHub. Por isso, vamos começar pela aplicação no Azure.
Autenticando no Azure
Depois de instalar o Azure CLI, abra o terminal e faça a autenticação com o comando abaixo.
az login
Em seguida, o navegador abre a tela de login da Microsoft. Assim que você se autenticar, o terminal já estará conectado à sua conta.
Caso tenha mais de uma assinatura ativa, use az account list para listar as assinaturas. Depois, use az account set --subscription NAME para tornar uma delas a padrão.
Criando um resource group
Os resource groups agrupam os recursos de uma solução. Além de ajudar na organização, eles facilitam o gerenciamento de permissões, custos e exclusão em lote.
Para esta demonstração, vamos criar um grupo chamado aspnetghcdeploy.
az group create --location brazilsouth --name aspnetghcdeploy
A flag --location define a região do grupo. Neste caso, usamos o Brazil South.
Criando o plano e o Web App
O próximo passo é criar a aplicação, e para isso precisamos de um App Service Plan. Ele define a faixa de preço e os recursos do servidor que o app utiliza.
Vamos criar um plano usando a SKU gratuita, para não gerar cobranças durante os testes.
az appservice plan create --name aspnetghcdeploy --resource-group aspnetghcdeploy --sku FREE
Os preços variam conforme a região, o sistema operacional e o tier escolhido. Portanto, consulte a página de preços do App Service antes de levar a aplicação para produção.
Com o plano pronto, criamos o Web App com o comando az webapp create.
az webapp create --name aspnetghcdeploy --resource-group aspnetghcdeploy --plan aspnetghcdeploy
Pronto, neste momento já temos uma aplicação rodando em https://aspnetghcdeploy.azurewebsites.net/. O nome do app precisa ser único em todo o Azure, então adapte-o ao seu caso.
Para conferir todos os comandos disponíveis, consulte a referência oficial do Azure CLI.
Criando o repositório para o deploy com GitHub Actions
Agora precisamos de um repositório no GitHub, que vai hospedar o código e o workflow do deploy com GitHub Actions. O comando gh repo create resolve isso.
gh repo create aspnetghcdeploy
Se preferir trabalhar com um repositório existente, use o comando gh repo clone.
gh repo clone andrebaltieri/aspnetghcdeploy
Na primeira execução do gh, o terminal pede uma autorização adicional. Então, o navegador abre a página do GitHub para concluir a associação da conta.
Notice: additional authorization required
Press Enter to open github.com in your browser...
Authentication complete. Press Enter to continue...
Criando a aplicação ASP.NET Core
Vamos aproveitar para criar a aplicação. Para ter algo mais visual, usamos o template padrão do ASP.NET Core MVC.
cd aspnetghcdeploy
dotnet new mvc
dotnet new gitignore
O comando dotnet new gitignore cria um arquivo .gitignore com tudo o que um projeto .NET precisa. Essa dica chegou pelo Ruan Silva, nos comentários do canal do YouTube.
Enviando o código
Agora enviamos o código local para o GitHub com os comandos abaixo.
git add --all
git commit -m "First version"
git push -u origin master
Note que usamos a branch master no git push. Se preferir, você também pode fazer esse processo de forma visual pelo Visual Studio Code.
Neste momento, o código da aplicação padrão do ASP.NET Core MVC já aparece no seu repositório.
Credenciais para o deploy com GitHub Actions
Para publicar o código no Azure a partir do GitHub, o deploy com GitHub Actions precisa de uma credencial. Aqui, usamos um service principal, que é uma identidade de aplicação com permissão sobre o Web App.
Essa credencial nada mais é do que um JSON com o identificador e o segredo da identidade. Esses dados são sensíveis, então nunca os deixe públicos.
Antes de tudo, precisamos do identificador da assinatura em que o Web App foi criado. Para listar as assinaturas ativas, execute o comando abaixo.
az account list --output table
Com o identificador em mãos, executamos o az ad sp create-for-rbac para gerar a credencial.
az ad sp create-for-rbac --name "aspnetghcdeploy" --role contributor --scopes /subscriptions/<ID>/resourceGroups/aspnetghcdeploy/providers/Microsoft.Web/sites/aspnetghcdeploy --sdk-auth
Repare que o escopo aponta apenas para o Web App, e não para a assinatura inteira. Dessa forma, seguimos o princípio do menor privilégio.
Como resultado, o terminal exibe um JSON parecido com o exemplo abaixo. Copie esse conteúdo, porque vamos usá-lo em breve.
{
"clientId": "XXXXXXXXXXXXXXXXXXXXXX",
"clientSecret": "XXXXXXXXXXXXXXXXXXXXXX",
"subscriptionId": "XXXXXXXXXXXXXXXXXXXXXX",
"tenantId": "XXXXXXXXXXXXXXXXXXXXXX",
"activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
"resourceManagerEndpointUrl": "https://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/"
}
Armazenando as credenciais nos secrets
Como comentamos, essas informações não podem ficar expostas. O melhor lugar para guardá-las é a área de Secrets do repositório no GitHub.
Abra as configurações do repositório, acesse a seção de secrets e crie um novo segredo chamado AZURE_DEPLOY. O valor dessa chave é o JSON obtido no passo anterior.
O nome AZURE_DEPLOY não é reservado. Você pode usar qualquer nome, desde que ele não tenha espaços nem caracteres especiais.
Como funciona o deploy com GitHub Actions
As GitHub Actions são ações organizadas em workflows, ou fluxos, que automatizam o CI/CD da aplicação. Cada deploy com GitHub Actions nasce de um desses fluxos.
Um workflow nada mais é do que um arquivo YAML com os passos que o GitHub deve executar. Além disso, qualquer repositório pode ter um ou mais workflows, disparados conforme as regras de cada arquivo.
Para facilitar, abra o projeto no Visual Studio Code com o comando code . dentro da pasta.
cd aspnetghcdeploy
code .
Por padrão, os workflows ficam na pasta .github/workflows, na raiz do repositório. Então, crie o arquivo abaixo.
.github/workflows/azure-deploy.yml
Durante cada push, o GitHub procura arquivos .yml nessa pasta e executa os que se aplicam ao evento.
Gatilho do deploy com GitHub Actions
Um workflow tem basicamente duas partes: on e jobs. A primeira define quando o fluxo roda, e a segunda define o que ele executa.
name: Deploy to Azure
on:
jobs:
A propriedade name dá nome ao workflow. Vale lembrar que, no YAML, a indentação importa, então mantenha exatamente o mesmo espaçamento.
Nesta aplicação, o deploy com GitHub Actions deve acontecer somente quando o código mudar na branch master. Mudanças em desenvolvimento, homologação ou outras branches não geram publicação.
name: Deploy to Azure
on:
push:
branches:
- master
Como podemos notar, o disparo fica bem intuitivo. A cada push na branch master, o fluxo segue adiante.
Definindo a máquina do job
O primeiro passo é informar o sistema operacional da máquina que executa o job. Para isso, usamos o atributo runs-on.
Neste exemplo, teremos apenas um job, chamado build-and-deploy, que compila e publica o código.
jobs:
build-and-deploy:
runs-on: ubuntu-latest
Checkout e instalação do .NET
A máquina Ubuntu nasce apenas com o básico do sistema operacional. Portanto, precisamos baixar o código e instalar o .NET.
Aqui entra a grande vantagem das actions. Milhares de pessoas fazem deploy de aplicações ASP.NET Core no Azure todos os dias, e os passos repetitivos já existem prontos para reuso.
Com a palavra uses, reaproveitamos actions públicas no workflow. Para baixar o código, usamos a action checkout, mantida pelo próprio GitHub.
Em seguida, instalamos o .NET com a action setup-dotnet. O bloco with informa a versão do SDK.
steps:
- uses: actions/checkout@master
- name: Set up .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: "3.1.102"
Build e publish
Para compilar a aplicação, não precisamos de nenhuma action adicional. Afinal, o .NET já está instalado, então basta executar o dotnet build.
- name: Build with dotnet
run: dotnet build --configuration Release
Note a flag --configuration Release. Sem ela, a aplicação compilaria em modo Debug.
Da mesma forma, o dotnet publish gera os arquivos finais em uma pasta de saída, sem exigir outra action.
- name: dotnet publish
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
Login e deploy com GitHub Actions no Azure
Com o pacote pronto, precisamos autenticar no Azure. Nesse passo, a action azure/login usa a credencial guardada nos secrets do repositório.
- name: Azure Login
uses: azure/login@v1.1
with:
creds: ${{ secrets.AZURE_DEPLOY }}
Qualquer segredo do repositório fica criptografado. No YAML, você o acessa pela sintaxe ${{ secrets.KEY }}.
O último passo é o deploy com GitHub Actions propriamente dito, feito pela action azure/webapps-deploy. Veja o workflow completo.
name: Deploy to Azure
on:
push:
branches:
- master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Set up .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: "3.1.102"
- name: Build with dotnet
run: dotnet build --configuration Release
- name: dotnet publish
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
- name: Azure Login
uses: azure/login@v1.1
with:
creds: ${{ secrets.AZURE_DEPLOY }}
- name: Deploy to Azure Web App
uses: azure/webapps-deploy@v1
with:
app-name: "aspnetghcdeploy"
slot-name: "production"
package: ${{env.DOTNET_ROOT}}/myapp
O parâmetro app-name indica o Web App de destino. Enquanto isso, o package aponta para a pasta gerada pelo dotnet publish.
Enviando o workflow e integrando o Azure
Até aqui, o workflow existe apenas na sua máquina. Vamos enviá-lo para a branch master com os comandos abaixo, ou pelo painel de controle de versão do Visual Studio Code.
git add --all
git commit -m "First deploy test"
git push -u origin master
Por fim, informamos ao Azure que o deploy desta aplicação vem do GitHub. Isso acontece pela configuração de deployment source, com o comando abaixo.
az webapp deployment source config --name aspnetghcdeploy --resource-group aspnetghcdeploy --repo-url https://github.com/andrebaltieri/aspnetghcdeploy --branch master
A partir de agora, qualquer alteração enviada para a branch master dispara uma nova publicação no Azure.
Acompanhando o deploy com GitHub Actions
Você pode acompanhar ao vivo cada deploy com GitHub Actions na aba Actions do repositório. A URL segue o formato https://github.com/USER/REPOSITORY/actions.
Nessa tela, cada execução mostra os passos do job, o tempo de cada um e os logs completos. Assim, fica fácil descobrir em qual etapa uma falha aconteceu.
Quando o job termina com sucesso, basta abrir o endereço do Web App. Em poucos minutos, a nova versão já está no ar.
Boas práticas atuais para deploy com GitHub Actions
Este tutorial usa o .NET Core 3.1 e as versões das actions daquela época. No entanto, vale conhecer o que a documentação recomenda hoje para o deploy com GitHub Actions.
Primeiro, a Microsoft recomenda autenticar com OpenID Connect, que usa tokens de curta duração. Dessa forma, o repositório não precisa guardar um segredo de longa duração.
Além disso, as versões atuais do Azure CLI usam a flag --json-auth no lugar da antiga --sdk-auth. A documentação também sugere o papel Website Contributor, mais restrito que o Contributor.
As actions também evoluíram. Hoje, a documentação de deploy no App Service usa azure/login@v2 e azure/webapps-deploy@v3.
Outra mudança é o nome da branch padrão. Atualmente, o GitHub cria repositórios com a branch main, então ajuste o gatilho do workflow conforme o seu projeto.
Se quiser outra abordagem para o mesmo cenário, o artigo sobre deploy no Azure via GitHub Actions também cria a infraestrutura pela linha de comando.
Conclusão sobre o deploy com GitHub Actions
Publicar uma aplicação ASP.NET Core no Azure sem abrir o portal é totalmente possível. Com o Azure CLI e o GitHub CLI, criamos o resource group, o plano, o Web App, o repositório e a credencial de publicação.
Em seguida, o workflow em YAML fez o restante: checkout, instalação do .NET, build, publish, login e deploy. Portanto, o deploy com GitHub Actions transforma cada push na master em uma nova versão no ar.
Não esqueça de conferir o vídeo no começo do artigo. Nele, você vê o mesmo processo pelo portal e aprende mais sobre GitHub, ASP.NET, Azure e variáveis de ambiente.
FAQ
Preciso pagar para fazer deploy com GitHub Actions no Azure?
Não necessariamente. O plano Free do App Service atende testes, e o GitHub oferece minutos gratuitos de Actions conforme o tipo de conta.
Qual a diferença entre continuous delivery e continuous deployment?
No continuous delivery, a publicação segue um ritmo definido pelo negócio. Já no continuous deployment, toda mudança aprovada nas etapas de integração vai direto para produção.
Onde devo guardar as credenciais do Azure?
Nos secrets do repositório no GitHub. Assim, o valor fica criptografado e o workflow o acessa por ${{ secrets.NAME }}.
Posso usar o publish profile em vez do service principal?
Sim. O publish profile é uma credencial no nível do app, mas exige a autenticação básica habilitada no App Service.
O workflow funciona com a branch main?
Sim. Basta trocar master por main na seção on.push.branches do arquivo YAML.