Windows Weekly Dockerfile #24: Building Distributed .NET Apps

This is #24 in the Windows Dockerfile series, where I look at one pattern for building distributed .NET apps using Docker. This is the build-everything-together pattern, which is less common but good to understand.

Your whole stack is in source so a new joiner just clones the repo and runs something like docker-compose build and docker-compose up to compile, package and run the whole application.

Typically that's a build-everything-independently pattern. Each Dockerfile uses a multi-stage build, where the first stage compiles the app from source and the final stage packages the published app into the Docker image.

That's great because if you're only working on one component - and if you've created effective images - you get superfast in-container builds which are using the exact same toolset as the CI builds.

In Chapter 5 of the book I cover an alternative pattern which is more like traditional CI. The build-everything-together pattern where you have a single builder image that compiles the whole solution.

Build Everything Together

This idea starts to work well in very large projects, where you have separate teams working on verticals within the whole solution. Developers don't build the whole solution because it takes too long, so they just build their vertical slice when they're working on a feature.

That causes problems when there are dependencies between verticals. Say you have a project defining API contract classes. It's easy for team A to make a breaking change to the contract and fix it in their vertical, without realizing team Z rely on the same contract - so the Z build breaks and so does the master build.

So instead you have a builder image where the Dockerfile compiles the complete solution. Then you have a separate Dockerfile for each deliverable app within the solution - representing each vertical - and that Dockerfile packages the compiled code from the builder image.

All teams use this as the basis of their builds, so that team A know their contract change breaks the Z build, and they can fix it before checking in.

It's a pattern you won't use so often, but it's good to know about as an option.

This is one area where the technology has changed. Not in Docker or Windows Server, but in the build toolchain for .NET Core. I'm using .NET Core 1.1 in the book, and in that version the tools where still in flux - so that dotnet msbuild command isn't something you need anymore - as I explained in the last instalment.

But it all still builds just fine, 18 months down the line. That's because I used explicit version numbers for all the dependencies :)

Usage

You won't get far with this image on its own, it's the middle part of a build pipeline. But you can grab the source and build it in the usual way:

The output of that is an image with all the compiled components published, ready to be packaged in their individual Dockerfiles. This is the groundwork needed to build the Docker images for the ASP.NET Nerd Dinner website in #21 and the .NET Framework console message handler in #22.