The Way You Publish Apps Is Changing | .NET 7
Transcript
Hi, my name is Stu and in this video I'm going to be showing you the new experience you can get for publishing Docker images in .NET 7. Writing Dockerfiles can be easy to get up and running but tricky to ensure that you follow the best practices such as multi-stage builds and non-root users.
In this video I want to show you the following: the new .NET 7 publish experience, how to make this work today with .NET 6, how to customize your experience, and if you stay to the end I have a bonus tip for you.
Here I have a standard .NET 7 API, and to utilize the new publish experience we need to add a package called Microsoft.NET.Build.Containers. This brand new package is only possible because of some of the latest changes in .NET 7. There's a link on the screen and in the description if you want to find out more about other changes in .NET 7.
When we install this package, we get a new publish profile available for us to use when we run our
dotnet publish command. We need to include one additional parameter: -p:PublishProfile=DefaultContainer. If we execute our dotnet publish with this new flag, a new Docker image will appear in your images section of Docker after it completes.
As soon as it's available, we can run the new image and hit it from our browser to make sure everything works as we expect. But how does this work? If we remove the NuGet package and then run the build with a binary log flag, we can open this up in MSBuild Log Viewer. In here we can see that the .NET 7 SDK is looking for a new target called PublishContainer. This PublishContainer target is exactly what the NuGet package provides. The discovery of this target is baked into the SDK, so you will need the .NET 7 SDK to publish.
Under the hood, the NuGet package automatically selects the most appropriate image based on your settings. For example, if you pass in the self-contained flag, you will get a different base image. So how do we make this work with
.NET 6? Let's head over to our .csproj and downgrade the project. Then we run the same command. Remember that this is only possible because we have .NET 6 and .NET 7 installed. If we run our container, we can see that the .NET 6 image is up and running as expected. The NuGet package has automatically detected that we are running the .NET 6 TFM and automatically selected the best image for us.
So let's take a look at how we can customize this experience. First let's switch back to .NET 7. There are three main customizations that I think you'll want to apply: ContainerRegistry, ContainerImageName, and ContainerImageTag.
With the ContainerRegistry property, we control where the SDK will publish the Docker image on a successful build. By default, this publishes to the local Docker daemon. With the ContainerImageName property, we control the name of the Docker image. By default, the SDK transforms the project name into a compliant version, for example it will do it all in lowercase. With the ContainerImageTag property, we can set one or more tags for the image using a semicolon-delimited format. So if you want to set the version of the image from say GitVersion, you can. There are many more options available, so I'll leave you a link in the description so that you can see all of the possibilities.
Earlier I promised you a bonus tip. I've not seen much fanfare about this, but it's something that I think is huge for the ecosystem. Ubuntu has been a popular choice for developers using containers ever since the first days of Docker. They now offer a new chiseled image that contains only the strict set of packages and files required at runtime. These chiseled images provide a minimal Ubuntu image optimized for OCI containers, addressing developer feedback around attack surface and image size without sacrificing Ubuntu stability and familiarity.
We can use the .csproj setting ContainerBaseImage to work with these new chiseled images by setting it to the value we want. If I wanted to publish a self-contained image, then I can use the runtime-deps image as shown here. It's still in a beta state so you need to take that into account, but overall the resulting images are tiny compared to the original Ubuntu images. I've included a link in the description for more information.
If you enjoyed this video, consider subscribing to the YouTube channel for more content like this.