There’s so much talk — and a fair bit of hype — surrounding containers. We’ve all heard their advantages: run anywhere, reliability, and scalability. All of these things are true. Yet containers aren’t without their own pitfalls. And those pitfalls can make for a painful and potentially failed experience if the wrong project is chosen for a first experiment with containers.
I’m still getting up to speed when it comes to containers, and as a first step to understanding them better I’ve been trying to grasp when, where and how they should be used in .NET projects. This article chronicles that research.
Before Moving To Containers
Be ready to invest lots of time (and therefore money) at the outset of a project like this. Containers require an investment in developer training to learn how to package an application for containerization. DevOps engineers will need to spend a significant amount of time learning how to build an appropriate CI/CD pipeline, understand the networking and security concepts, as well as mastering more traditional needs like configuration, deployment, load balancing and scaling. The concepts may be familiar but the implementation details are different with containers than they would be with virtual instances, PaaS, or anything else for that matter.
Expect a significant productivity drop for the first few months that developers and operations teams are working with containers. The first project hosted on a container is going to take longer than it normally would because of the learning curve, hands-on practice and back and forth between the development and operations team members. The longer delivery time should be planned for and the project undertaken only when the circumstances are right.
Clean Slate vs Migration
The first approach to container adoption is to choose an existing component of your technology stack, modify, re-package, deploy and replace the production component with the containerized version.
This approach can work. There is definetly lots of documentation on the web to support the “lift and shift” model. I don’t recommend it as a first attempt with containers for a few reasons. First, there’s a potential for networking issues between the container and the other components of your tech stack. The second reason is pragmatism. The cost of re-packaging something that is already working won’t be offset by the cost savings that containers provide. In other words, if it ain’t broke, why fix it?
My preferred approach is to start with a new project that has little to do with anything else and isn’t on the critical path of your system architecture. This isolates the risk of adopting a new technology. The last thing you want is to build a key component into a container only to have it negatively affect the rest of the system. That first project is as-yet unproven in production; it could have performance, networking, reliability or scalability issues that need to be resolved before containers can be integrated to more critical cloud applications.
.NET Framework vs .NET Core
For the longest time, containers were limited to Linux-based operating systems only. Microsoft’s investment in Docker has given us highly usable Windows images that can run .NET Core or .NET Framework applications.
.NET Core applications have an extra ace up their sleeve: they can also be run on Linux. That’s why I recommend that a new container project should be developed using the latest bits of .NET Core. The ability to run a cloud application on different operating systems gives you more ways to optimize the cost of the application. It can also make the adoption of .NET Core in predominantly Linux-based environments much smoother.
Don’t feel left out if you’re developing cloud applications with .NET Framework though. Windows containers have come a long way in the past year and are supported on both AWS and Azure. Keep in mind that there are still some caveats to using them on AWS and to a lesser extent on Azure. The most notable caveat being the Windows Server 2016 image size (~10 GB). I also suspect the major cloud providers are focusing on improving their Linux-based container offerings moreso than Windows Server since the target audience for the latter is limited.
Background Worker vs Web App
If at all possible, make that first .NET container project a background worker that performs some calculations based on a schedule or event. My reasoning is again more pragmatic than technical. A failure in an asynchronous job can be re-triggered easily once the issue is resolved, whilst a problem with a web app needs to be patched immediately to avoid losing user-taken actions.
There’s also less moving parts in a background worker. Event-based workers are usually connected to a queue or notification event, do some processing, and terminate. A web app, on the other hand, interacts with users, triggers asynchronous jobs, and invokes any number of different APIs to accomplish a single action taken by a user. Keeping the number of moving parts down helps keep the complexity of the container down as well.
As a side note, I found this article has some great guidance for understanding the concepts and possibilities of running background jobs within Azure.
Things To Avoid Entirely
Regardless of the chosen approach, there are a few things that can be done to make that first container project get off the ground easier.
Choose a project that has few external dependencies such as remote disk drives or local storage. They are harder to work with in containers due to their stateless nature. Speaking of which, ensure that the application is completely stateless itself. Starting with a stateful service is bound to be wrought with pain.
Don’t try to containerize more than one application at a time. Instead focus on getting the first application completely across the line before starting the next one. You run the risk of having too many different types of problems at once with little progress on any of them.
Pick something that doesn’t have extreme performance or security requirements. You don’t want to worry about optimizing something before you even get it into production. Container security is still a bit of a moving target so it’s best to choose something that doesn’t have to be Fort Knox.
Document The Process
I’ve said this in other posts but will repeat it here as well. There aren’t enough in-depth case studies, whitepapers, and the like for .NET projects that have embraced containers. Documenting and sharing your experiences getting started in the container space helps all other development teams struggling with the same problems.