Since working with .NET Core from the release candidate days, the framework continues to get updated. That’s a great thing, but living on the edge of a framework sometimes also comes with a few caveats.
The .NET Core work I’m doing gets deployed to Linux-based Docker containers. The CI/CD process is driven by Drone. Using this process, there are a few configuration files to maintain. Being on the edge of .NET Core at this moment in time where there is a lot of churn in the framework and the tooling is all at a preview version, things get can get interesting.
When using Docker, you maintain a Dockerfile that serves as a configuration for the Docker image that your solution needs. At the moment of this post, .NET core recently rev’d from version 1.0.0 to 1.0.1. Living on the edge, I naturally updated my solution to use 1.0.1 and also updated the Dockerfile to use a 1.0.1 container:
Everything’s good so far. Now let’s ship it! In order to do that, Drone also has its own configuration that has to be modified. The first step in the drone configuration is pulling a Docker image to build the application and run the unit tests. However, unlike my Dockerfile, we can’t use the runtime .NET Core Docker image for that. Instead, the SDK image is needed:
build: compile: image: microsoft/dotnet:1.0.0-preview2-sdk commands: - dotnet restore - dotnet test ./tests/myproject.Tests - dotnet publish ./src/myproject/project.json --configuration Release
There’s one problem here, and it has to do with one of the great benefits of Docker – caching. Docker images are ingeniously made up of pieces, or layers. For instance, the official dotnet Docker image from Microsoft is made up of several dependencies (framework pieces, OS pieces, etc) each of which are tagged with a version in Docker Hub (the public Docker image repository). Docker only downloads the pieces it needs to make up containers and uses pieces from cached Docker images when it can. For some reason the maintainers of the dotnet SDK Docker image updated the image to use .NET Core 1.0.1 but didn’t update the Docker Hub image name from dotnet:1.0.0-preview2-sdk. The result was when Drone ran the CI process, it saw the dotnet sdk image tag was the same and didn’t attempt to re-download the dotnet sdk image that contained the 1.0.1 update. When Drone ran the CI process, it attempted to execute the project’s unit tests but couldn’t due to a .NET Core version mismatch because it was using a cached dotnet sdk Docker image that used .NET version 1.0.0.
The specified framework 'Microsoft.NETCore.App', version '1.0.1' was not found. - Check application dependencies and target a framework version installed at: /usr/share/dotnet/shared/Microsoft.NETCore.App - The following versions are installed: 1.0.0
The fix to this is to force Drone to update the dotnet sdk Docker image. Luckily I found a GitHub issue asking how to do that. The answer was to add a command to force pull (note line 5 below) the image in the Drone config:
build: compile: image: microsoft/dotnet:1.0.0-preview2-sdk pull: true commands: - dotnet restore - dotnet test ./tests/myproject.Tests - dotnet publish ./src/myproject/project.json --configuration Release
Voila! Drone force pulled the latest dotnet sdk Docker image that included .NET Core 1.0.1 and the deployment succeeded!