Building a Linux-Based Visual Studio Team Service Build Machine with Docker Support

After writing ASP.NET Core RC2, Meet Docker, I was asked to help create a .NET Core Docker demo.  My role on the team was to handle the Visual Studio Team Services part which included building a single Linux VM that would act as the build agent and the Docker host.

The goal of this post is to show you how I built that Linux-based build agent with Docker installed. This will allow you to use a single machine for Team Services builds and build & publish Docker images.  To change it up a little, I will use PowerShell instead of the command prompt.

We are going to begin by using Docker Machine to create a Linux VM with Docker installed.  Then I will show you how to convert the SSH keys to work with Putty.  Once on the machine with Putty, we will install all types of tools to make an awesome build machine. Once we are done, we will have a new Linux build machine with the following tools:

  • Docker
  • .NET Core 1.0
  • Java JDK
  • Nodejs
  • NPM
  • Gulp
  • Grunt
  • Bower
  • Maven
  • Ant
  • Gradle

The first thing we are going to need is a Docker host.  We are going to use Docker Machine to provision our host in Azure for us. To get Docker Machine, you need to install the Docker Toolbox from here.

  1. Download Docker Toolbox from https://www.docker.com/products/docker-toolbox
  2. Double-click the exe
  3. Click Next
  4. Click Next
    For our purposes, the only required options are Docker Client for Windows and Docker Machine for Windows.
  5. Click Next
  6. Check Add docker binaries to PATH
  7. Click Next
  8. Click Install
  9. Click Finish

image_thumb2With Docker Toolbox installed, we can use Docker Machine to create our host in Azure.  Docker Machine requires your Azure Subscription ID to create your host, so we need go get that now.

  1. Log in to the Azure Portal
  2. Click Subscriptions from the menu
  3. Copy your Subscription Id

With your Azure Subscription Id, we can now create a Docker host in Azure.

  1. Open the PowerShell
  2. Enter the following command:
    docker-machine create -d azure --azure-subscription-id {Azure Subscription ID} --azure-open-port 80 --azure-resource-group {resource group name} {vm name in all lowercase}

    If you care to see all the options, you can read the Azure driver docs here.

  3. Copy the code presented
    The console window will appear to freeze. At this point, copy the code presented and proceed to the next step.
  4. Visit https://aka.ms/devicelogin
  5. Enter the code
  6. Press Continue
  7. Log in to your Azure Subscription
  8. Enter the following command and make note of the IP address and the DOCKER_CERT_PATH which we will need to connect to the machine:
    docker-machine env {vm name in all lowercase}

Docker Machine will now generate certificates, create a Linux Virtual Machine in Azure, and configure Docker on that machine.

To install all the other tools we have to connect to the machine. When Docker Machine creates the image, it only enables certificate based SSH connections.  I use Putty as my SSH client. However, the certificates generated are not compatible with Putty. Good news is there is a tool that can convert the certificates generated by Docker Machine into certificates supported by Putty so we can connect to the machine.  From the Putty Download Page, download the following tools:

  • putty.exe
  • puttygen.exe

The first thing we need to do is use puttygen.exe to convert the generated id_rsa file to a Putty ppk file.

  1. Start puttygen.exe
  2. Click Load
  3. Browse to the folder copied from the docker-machine env command above
  4. Open id_rsa
    image
  5. Click OK
  6. Click Save private key
  7. Click Yes
    image
  8. Save file as id_rsa.ppk in the same folder as the id_rsa file
  9. Select File / Exit

With the key generated, we can now connect to the VM using Putty.

  1. Start putty.exe
  2. Enter the IP copied from the docker-machine env command above into Host Name (or IP address)
  3. Select Data under the Connection node
  4. Enter docker-user into Auto-login username
  5. Select Auth under the Connection / SSH node
  6. Click Browse…
  7. Browse to the folder copied from the docker-machine env command above
  8. Open id_rsa.ppk
  9. Select the Session node
  10. Enter {vm name in all lowercase} into Saved Sessions
  11. Click Save
  12. Click Open
  13. Click Yes
    image

You are now connected to your Linux machine. Docker is already installed and configured. It is now time to install the tools and build agent.  We are actually going to do this using a Bash script you can download from GitHub. This will install all the tools listed above for you.

Before we can use the script, we need to collect a couple of pieces of information.  The first is a Personal Access Token.

  1. Log into Visual Studio Team Services
  2. Click your name in the upper right-hand corner
    image_thumb[15]
  3. Click My security
  4. Click Add
  5. Enter appropriate values
  6. Click Create Token
  7. Copy the token value and store it somewhere safe
    image

If you are the owner of the account you should be good to go. If however, you are not the owner of the account you need to make sure your account has permissions to add an agent.  Add the user you created the Personal Access Token for to both Agent Pool Administrators and Agent Pool Service Accounts.

  1. Log into your Visual Studio Team Services account
    Stay at the account level. Do not browse to a project. 
    image_thumb[1]
  2. Click the Collection settings gear icon in the upper right-hand corner
    If the tool tip for the gear reads Project settings, you are at the wrong level. Click Team Services in the upper left-hand corner to return to the account level.
    image
  3. Click the Agent pools tab
  4. Select the desired pool
  5. Click Roles
    image
  6. Select the Agent Pool Administrators group
  7. Click the Add… button
    Field Value
    User or group email of the desired user
  8. Select the Agent Pool Service Accounts group
  9. Click the Add… button
    Field Value
    User or group email of the desired user
  10. Click Save changes

Before we run the script, I like to make sure no other processes have locks on any of the files we will be modifying during the setup.  You can do this by issuing the following command:

sudo apt-get install -f
If you get any errors or warnings, correct those before you continue. Once you get output similar to the one below, you are ready to go.
image

One nice thing about Putty is you can paste text into the terminal.  I normally open Notepad or some other simple text editor to get the command right before I paste it into putty. 

  1. Replace all values in {} with your data.
    wget -O - https://raw.githubusercontent.com/DarqueWarrior/linuxSetup/master/linuxSetup.sh | bash && cd ~/Agents/a1 && ./config.sh --acceptteeeula --runasservice --url https://{YourAccount}.visualstudio.com --auth PAT --pool {AgentQueue} --token {YourToken} --agent {NameForAgent} --work _work && sudo ./svc.sh install && sudo ./svc.sh start
  2. Copy to clipboard
  3. Right-click in Putty window
  4. Press Enter
  5. Enter your sudo password
  6. Sit back and relax
    image

Once the script completes, you can view your agent in Team Services.
image

Comments (5) -

  • Girish

    7/3/2016 9:30:04 AM | Reply

    Do this work for asp.net core 1.0 RTM version

    • Donovan

      7/10/2016 8:18:47 AM | Reply

      Yes.

  • Alex Zevenbergen

    9/5/2016 10:13:41 AM | Reply

    The vm fails to create with the following message:

    Error creating machine: Error in driver during machine creation: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=404 -- Original Error: Long running operation terminated with status 'Failed': Code="ImageNotFound" Message="The platform image 'canonical:UbuntuServer:15.10:latest' is not available. Verify that all fields in thestorage profile are correct."

    • Ricardo Serradas

      11/17/2016 4:37:49 PM | Reply

      Hi Alex,

      Did you specify an image in your docker-machine command, using --azure-image parameter? If not, you can check the default value for it, using:

      docker-machine create -d "azure" --help

      Can you please share the command you used that generated this error?

      I could get this working with the following command structure:

      docker-machine create [machine-name] --driver "azure" --azure-subscription-id "[subscription-id]" --azure-location "[desired-region]" --azure-resource-group "[Resource-Group]" --azure-ssh-user [desired-user-name] --azure-static-public-ip

      You can get the available azure regions for your subscription using this powershell command:

      Get-AzureRmLocation

      @Donovan, thank you for the very useful content!

      Ricardo Serradas

  • Michael Henderson

    5/31/2017 12:32:27 AM | Reply

    nice work!

Pingbacks and trackbacks (4)+

Add comment

Loading