Nowadays with Kubernetes being so popular, building a Docker image is a must thing for CI/CD pipeline. For this kind of pipelines, an artifact is not a simple zip file wich compiled application, but a Docker image pushed to container registry. There is plenty of benefits of this approach but there is also price for this. We need to handle this in our pipelines. Hopefully, this price is not high. And we will explore today how we can build a Docker image for our dotnet core web app on Azure DevOps.
Our app is straightforward. It’s nothing more than scaffolding provided by Visual Studio on creating dotnet core web app. So let’s skip this part and move to DOCKERFILE. We use multi-stage build where in the first stage we use
mcr.microsoft.com/dotnet/core/sdk:3.1 image as our build environment to switch later to
mcr.microsoft.com/dotnet/core/aspnet:3.1 as our runtime, just to provide a minimal image.
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env WORKDIR /app # Copy csproj and restore as distinct layers COPY *.csproj ./ RUN dotnet restore # Copy everything else and build COPY . ./ RUN dotnet publish -c Release -o out --no-restore # Build runtime image FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "SampleAppForDocker.dll"]
Building Docker image on host agent
We will push our images to Azure Container Registry, but before that we need to create one.
Create first a resource group using az cli:
az group create --name TheCodeManual --location westeurope
Then create Azure container registry:
az acr create --resource-group TheCodeManual --name devopsmanual --sku Basic
I selected Basic tier. Primary differences between Basic and Standard are included storage and number of web hooks. For our puproses Basic is enough.
Now we need to define service connection on Azure DevOps. You will need to navigate to
Service connections* under your
Project settings. Then click
New service connection select
Docker Registry and fill form like below:
Now we are ready to define our pipeline:
We have here three very simple steps:
- Login to Azure Container Registry
- Build and push Docker image
- Logout from Azure Container Registry
This build took 55 seconds.
Building Docker image on Azure Container Registry
Another approach is to use ACR tasks. But what is ACR task? The codumentation explains this very well:
ACR Tasks is a suite of features within Azure Container Registry. It provides cloud-based container image building for platforms including Linux, Windows, and ARM, and can automate OS and framework patching for your Docker containers. ACR Tasks not only extends your “inner-loop” development cycle to the cloud with on-demand container image builds, but also enables automated builds triggered by source code updates, updates to a container’s base image, or timers. For example, with base image update triggers, you can automate your OS and application framework patching workflow, maintaining secure environments while adhering to the principles of immutable containers.
So basicly it will allow us to offload some part of CI steps to ACR. In our case it will be build and push docker image. You may wonder how much does cost. At the momen of writing this text it is $0.0001/second per CPU.
Our pipeline definition for this approach has single step which calls
az acr build.
This build took 94 seconds to create and publish the image. It is almost twice longer, however for such simple projects we should not pay too much attention to these results. The purpose here was to show how we can build image and for benchmarking we should do more than this.
Building Docker image on host agent with Build Kit
Looking at options how we can build Docker images on Azure DevOps I found a Build Kit project. You may ask what it is. Let me cyte the offical site:
BuildKit is a toolkit for converting source code to build artifacts in an efficient, expressive and repeatable manner. Key features:
- Automatic garbage collection
- Extendable frontend formats
- Concurrent dependency resolution
- Efficient instruction caching
- Build cache import/export
- Nested build job invocations
- Distributable workers
- Multiple output formats
- Pluggable architecture
- Execution without root privileges
I recommend you read this article which will give you general overview about Build Kit. But, to sum up, this is a software whch speed up bulding Docker images. We can enable Build Kit on Azure DevOps by setting DOCKER_BUILDKIT in the pipeline.
You may wonder how such simple change impacts on build performance ;) It took only 45 seconds.
In this post, I presented two ways of building docker images. I will not point which is better. It all depends on your preferences. Besides, ACR tasks have more capabilities than I presented here, but this is for the next post.