Building a multi Docker image solution using Visual Studio Team Services and Docker Compose
I have been looking at Docker and containers on and off for quite a few years and like many I’m very interested in the possibilities that the Docker ecosystem brings.
I’m primarily a .NET developer and now almost always choose .NET Core and ASP.NET Core when starting up new projects.
As most of us I started with the simple “Hello World” Docker getting started guides, and they are great to get you, well, started. But I believe strongly that everything from build, to testing, to deployment etc. should be as automated as possible. So a natural next step for me, when looking into the Docker ecosystem is, how do I automate the build of more complex applications?
When building and running a single docker image as a container, things are pretty straight forward, but when dealing with more complex systems, that contain many services and apps, building them also gets a bit more complicated.
Fortunately Docker comes with a great tool that helps with that, Docker Compose. I will not go into details of what all the different docker-compose commands do, there are plenty of guides out there for that.
I wanted to try setting up a build pipeline for a multi project solution on Visual Studio Team Services. Visual Studio Team Services integrates nicely with Azure, especially for the Container Registry, where the output of the docker builds will go. Also I really want a build solution where I do not have to maintain any infrastructure. VSTS provides that as well.
I have put together a sample app with multiple projects, you can find it here, https://github.com/christiansparre/VstsDockerBuild, and as you can probably see it took me a few tries before I was satisfied :)
It consists of a few projects
- The VstsDockerBuild.WebApp project
- The VstsDockerBuild.PongService project
- and the VstsDockerBuild.Shared project
It also contains a few test projects, I will cover that in a later post.
The WebApp is just an out of the box ASP.NET Core sample application with a few non significant changes like, a reference to the Shared project and an HTTP request to the PongService on the “Contact” page.
The Shared project is just to illustrate having references to other projects and how that fits in with the build process. Most simple getting started guides for Docker and ASP.NET Core only deal with a single project, this shows how to deal with this using Docker Compose.
The PongService just returns “Pong!” when processing an HTTP request, it is just the empty ASP.NET Core template.
I’m using the built in Docker support in Visual Studio. It gives us the scaffolding for doing multi image builds and running the application using Docker for Windows. Find more information about the Visual Studio tooling here.
So let’s jump over to VSTS, and get this set up. It’s actually pretty easy. I will not go into too much detail about VSTS build definitions, but focus more on the Docker Compose tasks.
I started with a new project and set up a build definition that points to the GitHub repository I linked to above. In the build definition tasks tab, under the “Agent phase”, press the “+” icon to add a new task and search for docker. Choose the “Docker Compose” task, as we are using Docker Compose to build our solution.
For now the build definition will only contain two tasks. One for building and tagging the images and one for pushing the images to Azure Container Registry.
The “Docker Compose” task comes with a set of predefined actions. I’m going to use the “Build service images” action.
I checked the “Qualify Image Names” option. This will cause the task to tag images with the correct, fully qualified image name. I will use the fully qualified image names in the second step to push the images to the registry I have chosen in the “Container Registry” settings.
I also filled out the “Additional Image Tags” with “$(Build.BuildNumber)”, this will tag the images with the build number that you can configure on the build definition options tab. I’m using the date and a counter “$(Date:yyyyMMdd)$(Rev:.r)”, but you could include branch names from source control etc.
I also checked the “Include Latest Tag” option, the latest tag will be used when running integration tests. Something I will go through in a later post.
That’s it for the build and tag step. The last step for now, the push step is equally simple.
As you can see it is almost identical to the build step, the action is “Push service images” and I include the image tag for the current build number. I have also left “Include Latest Tag” unchecked, but VSTS seems to push the latest tag anyway. I’m debating with my self if a “manual” push of each image is a better option. You can do that with the “Docker” task. I might cover this in a later post. Pushing the images individually might also have the benefit, that you have control over what images are pushed instead of all the service images defined in the docker-compose.yml file.
On last thing I did was ensuring I was using the Hosted Linux agent, that is currently in preview. It works just fine. That can be setup on the “Process” settings. It can also be overridden when queuing a new build.
Otherwise that is it, a set of projects built as docker images, pushed to an Azure Container Registry ready to use…