Using Azure Artifacts in Docker builds

One of the projects I work on recently transitioned from running on Azure Web Apps to running on Azure AKS. As part of that transition, all the individual components needed to be built into Docker container images. This turned out to be a non-trivial exercise, because we were using private NuGet feeds on Azure Artifacts to host our shared internal tools.

We run our builds on Azure Pipelines, and while it has decent support for Azure Artifacts repositories in particular, it doesn’t really help with builds that occur inside Docker. I’m going to spare you the gory details of all the weird and wonderful workarounds I attempted, including building a NuGet package cache image (with every version of every private package in it!) as a separate task, and go to the solution that actually works.

Include the Azure Artifacts credential provider in your build image

For now, you’ll probably find it easiest to have a custom build image based off of the .NET core SDK image. This is changing with .NET Core 3.0, because the SDK image is slated to include the Azure Artifacts Credential Provider out of the box. Meanwhile, you can do something like this:

First, I’m copying nuget.config over, because it defines the feeds we are using. It does not contain any credentials to the feed.

Second, I’m using the previously built image someregistry.example.com/tools/dotnet-build:2.2-sdk as the build environment instead of the regular microsoft/dotnet:2.2-sdk.

Finally, I’m defining a build argument called nuget_external_endpoints and setting the value of that argument to the environment variable VSS_NUGET_EXTERNAL_FEED_ENDPOINTS.

Generate a Personal Access Token in Azure DevOps

In order to keep things secure, we’ll opt to use an access token that only has read access to the Azure Artifacts feed. Navigate to https://<yourtenant>.visualstudio.com/_usersSettings/tokens and create a new token. Name the token, select a suitable lifetime for it, then click on “Show all scopes” at the bottom of the screen. Select the Read permission for Packages, and create the token:

Test the build locally

At this point, it’s a good idea to see if things work in your development environment. Try building your image, by running:

Quoting the JSON here is not necessary. The build task will pass the argument along intact.

After that, once you add a build variable named AzureDevOpsAccessToken, you’re good to go.

Caveats

Having a custom build image means that when Microsoft releases a new version of the SDK, it’s up to you to update your image to match that. It’s equally possible to set up the Azure Artifacts credential provider inside the actual app Dockerfile, and depending on your circumstances, you may want to do that instead.