Skip to end of metadata
Go to start of metadata

Why it's the right time for .Net developers to embrace Jenkins and Docker

The Agile movement in software has created a market for various different tools, each automating a specific part of the development process. For instance, the call to continuous integration (CI) has given rise to the likes of Hudson/Jenkins and Maven that allow you to concentrate on the task at hand while getting precious feedback within seconds.

The .Net platform and the ecosystem surrounding it have been latecomers in providing decent tools for CI. Team Foundation Server (TFS) took a long time to provide anything more than a glorified copy of Apache Ant. The introduction of NuGet has helped somewhat with dependency management. Jenkins has had a plugin for MSBuild since 2008, providing an alternative to TFS. However, most IT departments who are fully enslaved by invested in Microsoft's products are loath to take what they consider to be a huge risk.

However, in a somewhat surprising turnaround, Microsoft has recently declared its love for Linux and open source software. This sentiment has been followed by the release of the first fully Microsoft supported implementation of the .Net framework for Linux which enables building and running ASP.Net applications from a Linux command line. This should help companies to take a chance on using more and more open source tools, especially ones that are currently only available on Linux, like Docker for instance. Microsoft has even announced a partnership with Docker and are working on fully integrating it with Windows.

Contents

What's in this lab

This lab will show you how to set up a virtual machine with a Git repository, and an instance of Jenkins, each inside their own Docker containers. A very simple ASP.Net application without any tests will be pushed to the repository. Then using a Jenkins Pipeline-as-code build, we'll produce a Docker container. Finally we'll run that container and check that our application is in fact running.

Icon

For the most part this lab is written from the point of view of a Windows user. However, it can be done entirely on Linux or Mac OS X. (big grin)

Tools and versions used in this lab

ToolVersion
Docker1.11.0
Docker Compose1.7.0
Docker Machine0.7.0
VirtualBox5.0.18 r106667
Jenkins2
GitLabCommunity Edition 8.7.0

ASP.Net Core

.Net Core

1.0.0-rc1-update1

This lab assumes that you are already familiar with these tools.

Prerequisite

Make sure that your machine has 64bit CPU that supports virtualization. You may have to activate virtualization support via your machine's BIOS setup utility.

If you're on Linux, you also need Git installed.

Lab

Install VirtualBox

Download and install Oracle VM VirtualBox using the appropriate installer for your OS.

Install Docker & Docker Machine

On Windows or Mac OS X, install Docker Toolbox. This will install both Docker and Docker Machine, along with Git.

On Linux, follow Docker's instructions for installing Docker then Docker Machine.

Install Docker Compose

Again, follow Docker's instructions for installing Docker Compose.

Set up a virtual machine with Docker

Thanks to Docker Machine this is a very easy step. In your favorite terminal — on Windows I recommend PowerShell over CMD — type the following command to create a virtual machine named "default" that runs Linux and has Docker installed.

After it has been created, the machine boots up in headless mode. On the first run, Docker Machine generates keys for securing SSH connections to the machine as well as TCP connections to the Docker daemon running on it.

Docker Machine provides several commands for stopping and starting the machine, as well as connecting to it via SSH, and setting the appropriate environment variables for connecting to its Docker daemon.

Speaking of which, use the following command to find out how to do that on your terminal and do it.

On PowerShell under Windows, this would output something like this:

We can see that Docker Machine set up the Docker daemon on the virtual machine to listen to TCP connections on port 2376. However, not everybody has access; only those that use the right SSL certificates. Thankfully Docker Machine also placed those certificates in .docker/machine/machines/default in your home directory.

Once you execute the suggested command, any subsequent invocations of Docker will talk to the virtual machine's Docker daemon.

Example for Windows
Icon

For the purpose of this lab, I assume that Docker Machine assigned the IP address of the virtual machine it created to 192.168.99.100.

If yours is different, make sure to adjust that IP address in all subsequent commands and files.

Transfer SSL client keys to the virtual machine

In order for Jenkins to build and run Docker containers, it needs to be able to communicate with a running Docker daemon. One way to do this would be to install one inside the container alongside Jenkins: this has been dubbed "Docker in Docker" or DinD for short. This does not work, as someone else explains. Another way is to allow the Jenkins container to see the daemon that's running it: similarly this is called DooD. There are many blog posts out there that explain more or less convoluted ways of doing that.

In this lab, we'll have Jenkins connect to that same TCP port that the Docker daemon is already listening to. Since this port is encrypted, we need to provide certificates for making client connections. One easy way is to reuse the ones that Docker Machine has already created.

Use Docker Machine to copy those certificates to the virtual machine for later use.

Icon

If for some reason this doesn't work, you can use another SCP client, as long as it supports SSL key authentication. Log in to 192.168.99.100:22 as user docker and point the client to the SSL key at ~\.docker\machine\machines\default\id_rsa.

To check that this has worked, you can connect to the virtual machine and list the contents of /home/docker/ssl.

Create Docker containers for GitLab and Jenkins

Create a new directory called aspnetci and a new file within it called docker-compose.yml with the following contents.

docker-compose.yml
Icon

The dnx volume mentioned in this file will be used to cache NuGet packages between builds. This saves a lot of time and bandwidth since packages will not be downloaded more than once.

This is similar to a technique used in conjunction with Maven builds.

Once this is done, run the following command from the aspnetci directory.

Configure GitLab and create a project

An instance of GitLab is now available at http://192.168.99.100:8000. It will require some initial configuring so go to that address.

Firstly, it will prompt for a new password for the root user. Provide one (and remember it (wink) ).

Secondly, log in as root, and create a new empty project. Let's call it aspnet-hello.

Thirdly, create a new directory on your machine and open a terminal in that directory. Use the following commands to clone a simple ASP.Net application and commit it to GitLab.

Configure Jenkins and create a build

An instance of Jenkins is available at http://192.168.99.100:8001. It also requires some configuration.

Firstly, it will prompt for the initial password. This is generated randomly and stored in a file inside the Jenkins container. It can be retrieved using the following command.

Then, let Jenkins install suggested plugins. Once that is done, you will be prompted to create a new user.

Install the Docker Commons Plugin and add an installation for Docker entering the following information:

  • Name: Default
  • Install Automatically: check
  • Add installer: Extract *.zip/*.tar.gz
    • Download URL for binary archive: https://get.docker.com/builds/Linux/x86_64/docker-1.11.0.tgz
    • Subdirectory of extracted archive: docker

Finally, create a multibranch pipeline entering the following information :

  • Branch sources > Add source: Git
    • Project repository: http://192.168.99.100:8000/root/aspnet-hello.git
    • Credentials: root/******

Once you have saved this the build should trigger. It will scan the Git repository to find all branches that have a pipeline build script named Jenkinsfile, then use that script to build the branch.

Jenkinsfile

This script carries out the following steps:

  • check out the current branch from the Git repository
  • ask Jenkins for the directory where it installed a Docker client
  • add that directory to the PATH
  • run the following steps in a Docker image that has the ASP.Net runtime and development tools installed:
    • fetch dependencies from NuGet repository
    • package the project as a publishable artifact
    • assign ownership of all files created during the previous steps to the jenkins user (otherwise Jenkins won't be able to complete the next steps)
  • build a Docker image using the Dockerfile contained in the project, tagging it using a combination of the branch name and the build number
Icon

Using separate Docker images to run build steps is an instance of separation of concerns in the build environment! This keeps you from having to add to the base Jenkins image all of the tools for all of the different programming languages that you might use.

Once the build is finished, you can check that the Docker daemon knows of the image by using the following command.

Run the resulting Docker image

Run the Docker image with the following command.

The application should be available at http://192.168.99.100:5004.

Where to go from here

So now you have a simple ASP.Net application that can be built with a multibranch pipeline Jenkins build. If you create a new branch and add a feature, you can build and test drive it in a new container.

There's still some way to go before we have a production-ready application and build. Here are just a few things that could be added: