First post in quite a while. Mouthful title! Before we go further, let’s get the definitions done:
- .NET Core - specifically, I’m using .NET core MVC
- ACS - Azure container service. Very very, different from AWS ECS. And that’s good. ECS is Amazon’s try at building their own container cluster orchestrator. “Try” being the operative word, it is as half-baked as any orchestrator can come. No service discovery, no persistent storage, no messaging, no K/V store, i could go on. ACS however, is not a container orchestrator. It’s a container orchestrator orchestrator. Let that sink in a bit. It basically handles Azure Compute Management, Supporting infrastructure (VNETs, NSGs, Storage Accounts), and provisions the orchestrator of your choice. Options today are Kubernetes, DC/OS, Swarm.
- Kubernetes - Container orchestrator build by ex-Googlers. Fun fact - Brendan Burns, creator of Kubernetes joins Microsoft.
- VSTS - Really?
Now, I could start slow, purely talk about Kubernetes basics, or maybe talk about dotnetcore and how to docker-ize it. But I believe that any piece of tech only delivers value in one place, and no, that’s not in your dev machine nor the Git repo. It’s in production.
Hence, I’d like to take you on the journey of building a build/release pipeline for running .NET core in production systems on a Kubernetes cluster. This will be a 3-part series: Part 1 will be .NET core, docker basics and stuff, some container best practices. Part 2 will be about Azure Container Services, Kubernetes, talking about key concepts like Pods, Services, and YAML IaC files, and putting it all together Part 3 will be about VSTS, setting up the build agent, build & release pipelines.
Strap in, here’s part 1!
Scaffolding using Yeoman
Devs nowadays shouldn’t handcraft projects and workspaces. Yeoman’s the man (or woman)!
We’ll choose Web Application here, obviously.
Building and Running .NET core
For this example, I’m using the .NET core MVC sample application (.NET core MVC, Bootstrap JS:
With the following folder structure:
By navigating to the project folder, then running the command:
That allows us to build our .NET core app.
Compiling and docker-izing
Now that we can run that .NET core app, it’s time to dockerize! (okay that sounded terrible).
To start off, we need a dockerfile. A dockerfile tells the docker engine what to put into your docker image, which base docker image to use, and what you want it to use as an entrypoint.
One thing to note (actually, three things): Container best practice tells us that we should have at least 3 different types of docker images to use per app, for different purposes. That means, three different dockerfiles.
- Dev image - This is dev-controlled, dev tells what’s in it, dev manages it, dev uses it. Not for production use. Here’s the dev dockerfile:
Build image - Ops-controlled. Tailor-made for build agents and build tasks, test agents and tasks. Used by devs for build workflows. Used only for production build agents, still not for production workload.
Here’s the build agent dockerfile (yes, the build agents are on a docker container - docker building docker!).
Production image - Ops-controlled. Locked down. Lean. Purpose-built for production workload.
And here’s the build/production dockerfile:
Image #2 is simple enough, we point it to the Microsoft-provided build agent for VSTS, using start.sh as the entry point to run the VSTS agent.
Image #1 and #3 are very similar. I’ll point out the difference in the code block below. The code block below is the block present in #1, but absent in #3.
What this does basically, is:
- Copy the .NET project file (csproj)
- Restore dependencies
- Copy the application source code
- Build/Compile the Debug build profile for said app
Since this is the “dev” docker image, we’re doing a build on our local dev machine. This is the “dev” part of the workflow.
So, our docker dev workflow would be:
- Clean the workspace of non-docker build files! Namely /publish, /bin and /obj. This is because if you run docker build with these folders in your local workspace, these would be copied along into the docker staging environment.
- Run Docker build
- Run Docker run
To prove I’m not cheating, here’s a view of the container thru Kitematic:
That’s it for part 1! We now have an app, and have established a typical dev machine workflow.
Part 2 is about Kubernetes, ACS, and the bits necessary to run our UAT environments, PROD environment, and stuff.
You can find the source code, and future stuff I’ll be showing in here