Last Updated: 29 September 2020

.Net 6 ARM64 Build Agent for Azure DevOps

It is possible to run .Net 6 (and also .Net Core) code on ARM CPU-based devices. For example, you might want to run a .Net Core API or web app on a Raspberry Pi. However, you cannot just use an x64 machine - such as the Microsoft-provided build agents - to build the binaries or Docker images.

This guide shows you how to convert a Raspberry Pi into your own ARM build agent that your Azure DevOps pipelines can use. You can build for 32 or 64-bit if you have a Raspberry Pi 2B v1.2, 3B, 3B+ or 4B. Older Raspberry Pi models are 32-bit only.

Install Raspberry Pi Operating System

  • Using your Windows or Mac desktop, go to the downloads page and download the latest Raspberry Pi OS Lite for 32 or 64-bit. If you are unsure, choose the 64 bit flavour. 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 Interface Options → SSH
  • Set the host name to something sensible (e.g. pi-azdo-build) in System Options → Hostname
  • 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 6 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/a567a07f-af9d-451a-834c-a746ac299e6b/1d9d74b54cf580f93cad71a6bf7b32be/dotnet-sdk-6.0.401-linux-arm64.tar.gz
    mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-6.0.401-linux-arm64.tar.gz -C $HOME/dotnet

  • Add the dotnet folder to your PATH variable. Open the file using the command below:


    sudo nano /etc/profile

  • Find the two PATH= statements near the top of the file, and add :$HOME/dotnet to the end of each, inside the double quotes. The file section should now look something like this:


    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

  • To save the file and exit Nano, press CTRL+X, then 'Y', followed by Return.
  • Reboot the Raspberry pi


    sudo reboot now

  • 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 → Add Pool. Select 'Self Hosted' and give it a name, e.g. 'ARM Build Agent Pool'.
  • Go into the new agent pool, and select 'New Agent'.
  • Choose the 'Linux' tab from the top of the window that appears, then ARM or ARM64 depending on which operating system you installed, and which Raspberry Pi you have. If in doubt, choose ARM64.
  • At the top, in the 'Download the agent' section, click the icon to the right of the 'download' option to copy the URL to the clipboard.
  • Copy the script below, and replace the url after 'sudo wget' with the one you copied. Also update the filename after 'sudo tar' to make sure it corresponds with your download URL.
  • Run your modified version of the script below.


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

  • Install agent dependencies


    sudo ./bin/installdependencies.sh

  • Now create a Personal Access Token (PAT) so that your agent can communicate with Azure DevOps. Log into Azure Dev Ops and click on the people icon in the top right hand corner.
  • From the menu, select 'Peronal Access Token', and then click 'New Token'. Select 'Full Access' as the scope, and an expiration date. The longest validity of the PAT is one year from now.
  • Click 'create' and then copy the resulting token. It will not be displayed again, so keep this safe!
  • Configure the agent, note that this command should not be run with sudo!


    ./config.sh

  • Read and aaccept the license
  • Enter your Azure DevOps organization's url (e.g. https://dev.azure.com/your-organization)
  • Select Personal Access Token as the authentication type.
  • Enter the name of the agent pool you created above, e.g. 'ARM Build Agent Pool'
  • Enter a name for your agent, e.g. 'pi-azdo-build'
  • Enter a work folder, e.g. _work

  • Set the agent to run as a service, and start it. After a short while, you will notice that your new agent is listed in Azure DevOps as being online.


    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

If you want to build ARM-compatible Docker images using your new build agent, you will need to install Docker and configure some permissions. A future article will discuss how to create both x64 and ARM docker images in the same manifest.

  • Install Docker and reboot


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

  • To run the Docker daemon as a non-privleged user:



    sudo sh -eux <<EOF
    # Install newuidmap & newgidmap binaries
    apt-get install -y uidmap
    EOF
    
    dockerd-rootless-setuptool.sh install

    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.