Build and deploy .NET 5 app with GitHub Actions
Tags: azure, dotnet, docker, bicep
Published: 2021-01-19 09:47:18

As a personal project, I'm learning about GitHub Actions and DevOps in general. I'm a former .NET developer so it's my prefered technology to work with. 
My goal on this post, is to deploy a sample .NET 5 application to Azure App Service as a container with GitHub Actions. I will author the ARM template using Bicep.
I work on MacOS but the same process can be achieved on Windows or Linux.

Let's start.

# Tooling

Few tools used on this project:

- An Azure Subscription to deploy resources
- A GitHub repository to store the source code and use GitHub Actions
- [Azure CLI](https://github.com/Azure/azure-cli)
- [Bicep](https://github.com/Azure/bicep)
- I recommend [Visual Studio Code](https://code.visualstudio.com)
- [Dotnet 5](https://dotnet.microsoft.com/download/dotnet/5.0)
- A terminal to execute commands

# Create new .NET 5 project

First, we have to create a new project.
In my case I created a repository called *demoaspnet5container*

The command to clone the repository to local folder is:
```bash 
git clone https://github.com/MCKLMT/demoaspnet5container.git
```
We now have a copy of our repository locally.
We will create a new .NET 5 project.
Go in the cloned folder and execute the following command. In my case, my project will be called *WebApp*:

```bash
dotnet new project WebApp
```
Our new project has been created and you can run it locally using the command:
```bash
dotnet run
```
And now, you can browse the web site locally using your browser at *http://localhost:5000*

You can create a .gitignore file to avoid to push build artetifacts to GitHub with the following command:

```bash
dotnet new gitignore
```

# Authoring the Docker image

Now we have our application, we want to containerize it.
To do so, we create a Dockerfile file in the same folder than the application.
The Dockerfile looks like this one:

```Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
WORKDIR /app

RUN dotnet --version

COPY *.csproj ./
RUN dotnet restore

COPY . ./
RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "WebApp.dll"]
```
This file is pretty simple.
First, we use a build image to restore dependencies and publish the content of the web site and secondly, we copy the resulting of the build to a new image.

# Using Bicep to author ARM template

Bicep is a recent open source project which aims to simplify the authoring of Azure Resource Manager templates.
Once the template is created, you have to run the following command to build the ARM file:

```bash
bicep build main.bicep
```
This command will output the ARM file you can deploy using Azure CLI for instance.

I would like to share few things about it.

First, in my case, I want to use Azure App Service on Linux to host the container I built previously. The container image will be built and stored with Azure Container registry. To do so, Azure App Service will need to have the rights to pull the image from Azure Container Registry. To achieve this goal, I will create a user managed identity and affect this identity to App Service. Afterwards, I assign the permission to pull the registry to the identity. Voilà, our App Service can safely access the registry.

The bicep code of user managed identity and the role assignment:

```
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: 'webAppIdentity'
  location: location
}

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: roleAssignmentName
  scope: containerRegistry
  properties: {
    roleDefinitionId: roleDefinitionId
    principalId: managedIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}
```
The complete bicep file is [available on GitHub](https://github.com/MCKLMT/demoaspnet5container/blob/master/Infrastructure/main.bicep)

# Create our GitHub workflow

We have all the code to be deployed on Azure.
- The bicep file which will be converted to ARM template
- The Docker image to deploy to App Service

We will create a *.github/workflows/dotnet-core.yaml* file. This file will contain all the steps needed and will be executed at each commit push on the master branch.

First, we will deploy the infrastructure. We have to build our bicep file, connect to Azure and deploy the resulting template:

```yaml
- name: Run Bicep build
uses: aliencube/bicep-build-actions@v0.1
with:
    files: Infrastructure/main.bicep

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

- name: Deploy Azure Resource Manager (ARM) Template
uses: azure/arm-deploy@v1
id: deploy
with:
    scope: resourcegroup
    subscriptionId: ${{ secrets.SUBSCRIPTION_ID }}
    resourceGroupName: demoaspnet5container-rg
    template: ./Infrastructure/main.json
    deploymentMode: Incremental
```
Secondly, we will build the container using Azure Container Registry:
```yaml
- name: Build image with ACR
  uses: azure/CLI@v1
  with:
    azcliversion: latest
    inlineScript: |
    az acr build --registry ${{ steps.deploy.outputs.registryNameOutput }} --image aspnet5webapp:${{ env.COMMIT_REF }} ./WebApp/
```
The source code will be zipped, uploaded to Azure Container Registry and built in the cloud.

The final step is to tell to App Service where to get the image:

```yaml
- name: Deploy the image to App Service
  uses: azure/CLI@v1
  with:
    azcliversion: latest
    inlineScript: |
    az webapp config container set --name ${{ steps.deploy.outputs.webAppNameOutput }} --resource-group ${{ steps.deploy.outputs.resourceGroupOutput }} 
```
Congratulations, your website should be up and running!

![Capture d’écran 2021-01-19 à 10.35.57](https://dev-to-uploads.s3.amazonaws.com/i/v6acghi8dv137iimi554.png)

I hope you liked this post and feel free to contact me on Twitter if you want to discuss about it!

# Resources

The complete source code is available on GitHub:
{% github MCKLMT/demoaspnet5container no-readme %}

Few resources to go deep on this topic:

- [Tutorial: Build and deploy container images in the cloud with Azure Container Registry Tasks](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-tutorial-quick-task)
- [Migrate custom software to Azure App Service using a custom container](https://docs.microsoft.com/en-us/azure/app-service/tutorial-custom-container?pivots=container-linux)
- [GitHub Actions for deploying to Azure](https://github.com/Azure/actions)