.Net Core 3.1 ARM Build Agent for Azure Dev Ops

If you want to compile your .Net Core app or build a Docker Image to run on an ARM device, you will need an ARM build agent. There are a few ways to do this, such as using QEMU on Linux to emulate a Raspberry Pi. This is fairly straightforward to do, however does not work well on a Hyper-V virtual machine due to issues with audio.

This solution uses a real Raspberry Pi, and describes how to add it to your Azure Dev Ops build agent pool. The instructions for creating a Linux x86 or x64 build agent are broadly the same, and you can follow these steps but taking care to use the correct downloads for your target architecture.

Install Raspberry Pi Operating System

  • Using your Windows or Mac desktop, go to the downloads page and download the latest Raspberry Pi OS (32-bit) Lite. This is the leanest version with no desktop or user interface. Extract the downloaded zip file.
  • Download Balena Etcher (or your favourite image writing tool)
  • Write the unzipped image to a MicroSD card, ideally you'll want one that is 64GB or more, particularly if creating Docker images
  • Put the SD card into your Raspberry Pi, power it up and you should end up at a login prompt. The default username is 'pi' with password 'raspberry'
  • Update the package list, and upgrade everything by running these commands:


    sudo apt update
    sudo apt upgrade

Initial Configuration

  • Start the config tool


    sudo raspi-config

  • Enable SSH by starting the config utility and going to Interfacing Options → SSH
  • Set the host name to something sensible (e.g. pi-azdo-build) in Network Options → Hostname
  • Change the default password by going to Change User Password
  • You can now disconnect your Raspberry Pi from your monitor and connect via SSH if you prefer using XShell or your other favourite client software.

Install .Net Core 3.1 SDK

  • Use the script below to download, unzip and configure the latest .Net Core 3.1 SDK. If you want to install a different version of .Net Core, go to the .Net Core downloads page and choose the version of .Net Core you want to be able to build. You need to look for the latest Linux ARM32 binaries in the SDK section on the left hand side.


    sudo wget https://download.visualstudio.microsoft.com/download/pr/8f0dffe3-18f0-4d32-beb0-dbcb9a0d91a1/abe9a34e3f8916478f0bd80402b01b38/dotnet-sdk-3.1.402-linux-arm.tar.gz
    mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-3.1.402-linux-arm.tar.gz -C $HOME/dotnet

  • Add the dotnet folder to your PATH variable. Open the file using the command below and add :$HOME/dotnet on the end. To save and exit, press CTRL+X, then 'Y', followed by Return. You may want to reboot at this point to pick up the change.


    sudo nano /etc/profile


    if [ "`id -u`" -eq 0 ]; then
        PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$HOME/dotnet"
    else
        PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:$HOME/dotnet"
    fi
    export PATH

  • Test that .Net Core is all working properly by running this command:


    dotnet --info

Install Build Agent

  • In Azure Dev Ops go to Organization Settings → Pools → New Agent and select 'Linux' / 'ARM'. This will give you the URL for the latest build agent binaries. Create a folder, download the zip file and extract everything. The build agent will require Git to grab the source code, so install that too.


    sudo mkdir /agent
    cd /agent
    sudo wget https://vstsagentpackage.azureedge.net/agent/2.155.1/vsts-agent-linux-arm-2.155.1.tar.gz
    sudo tar zxvf vsts-agent-linux-arm-2.155.1.tar.gz
    sudo apt install git

  • Install agent dependencies


    sudo ./bin/installdependencies.sh

  • Create a Personal Access Token. Go to Azure Dev Ops, click your profile avatar in the top right corner and select 'Azure Dev Ops Profile' Click on Personal Access Tokens on the left hand menu, under 'Security'. Create a token and make a note of it.
  • Configure the agent without sudo. You will be asked for your server url, authentication type (Personal Access Token) and various other things. Mostly the defaults will be fine, unless you have specific requirements.


    ./config.sh

  • Set the agent to run as a service


    sudo ./svc.sh install
    sudo ./svc.sh start

  • A snapshot of salient environment variables is taken by the agent on install. At this point it is usually worth refreshing this snapshot


    ./env.sh
    sudo ./svc.sh stop
    sudo ./svc.sh start

At this point, reboot your Raspberry Pi and when it comes back up you should have a fully functioning ARM build agent available to your Azure Dev Ops instance.

Build ARM Compatible Docker Images

To also build an ARM-compatible Docker image using your new build agent, you will need to install Docker and configure some permissions.

  • Install Docker. For Debian Stretch or earlier, use the following command:


    sudo apt install docker

  • For Debian Buster, use this command:


    curl -sL get.docker.com | sed 's/9)/10)/' | sh

  • To get Docker to work without needing sudo, first a add the docker group if it doesn't already exist, and add the current (Pi) user to it. The final command will make the grouop changes take hold, but you could just as easily log out and back in again.


    sudo groupadd docker
    sudo gpasswd -a $USER docker
    newgrp docker

  • Test that Docker is working correctly by running the following commands. If the first command shows access denied or permissions errors in the second section, this is usually because the commands above have not been run.


    docker version
    docker run hello-world

Your build agent will now be able to create an ARM compatible image. You can actually run an ARM image on your x86 installation of Docker for Desktop on Windows or Mac due to a clever shim that uses QEMU to emulate the ARM architecture - just use 'docker run' in the usual way.