DEV Community

Lord Jake
Lord Jake

Posted on

How to run self hosted agent on Azure Container Instance

Azure Container Instance may be a good idea for some who don't want to run a full blown VM to run the Devops agent, which is light and probably cost effective.

1 Create a container registry via portal or CLI.

Image description

2 Create docker agent image and upload to the created container registry. The docker agent will depend on the OS to be used - I am using Ubuntu 20.04.

3 I assume you have already a running docker engine or else please install and make the service up and running.

4 mkdir ~/dockeragent
mkdir ~/dockeragent

5 Save the following content to ~/dockeragent/Dockerfile

FROM ubuntu:20.04
RUN DEBIAN_FRONTEND=noninteractive apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get upgrade -y

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \
    apt-transport-https \
    apt-utils \
    ca-certificates \
    curl \
    git \
    iputils-ping \
    jq \
    lsb-release \
    software-properties-common

RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash

# Can be 'linux-x64', 'linux-arm64', 'linux-arm', 'rhel.6-x64'.
ENV TARGETARCH=linux-x64

WORKDIR /azp

COPY ./start.sh .
RUN chmod +x start.sh

ENTRYPOINT [ "./start.sh" ]
Enter fullscreen mode Exit fullscreen mode

6 Save the following content to ~/dockeragent/start.sh

#!/bin/bash
set -e

if [ -z "$AZP_URL" ]; then
  echo 1>&2 "error: missing AZP_URL environment variable"
  exit 1
fi

if [ -z "$AZP_TOKEN_FILE" ]; then
  if [ -z "$AZP_TOKEN" ]; then
    echo 1>&2 "error: missing AZP_TOKEN environment variable"
    exit 1
  fi

  AZP_TOKEN_FILE=/azp/.token
  echo -n $AZP_TOKEN > "$AZP_TOKEN_FILE"
fi

unset AZP_TOKEN

if [ -n "$AZP_WORK" ]; then
  mkdir -p "$AZP_WORK"
fi

export AGENT_ALLOW_RUNASROOT="1"

cleanup() {
  if [ -e config.sh ]; then
    print_header "Cleanup. Removing Azure Pipelines agent..."

    # If the agent has some running jobs, the configuration removal process will fail.
    # So, give it some time to finish the job.
    while true; do
      ./config.sh remove --unattended --auth PAT --token $(cat "$AZP_TOKEN_FILE") && break

      echo "Retrying in 30 seconds..."
      sleep 30
    done
  fi
}

print_header() {
  lightcyan='\033[1;36m'
  nocolor='\033[0m'
  echo -e "${lightcyan}$1${nocolor}"
}

# Let the agent ignore the token env variables
export VSO_AGENT_IGNORE=AZP_TOKEN,AZP_TOKEN_FILE

print_header "1. Determining matching Azure Pipelines agent..."

AZP_AGENT_PACKAGES=$(curl -LsS \
    -u user:$(cat "$AZP_TOKEN_FILE") \
    -H 'Accept:application/json;' \
    "$AZP_URL/_apis/distributedtask/packages/agent?platform=$TARGETARCH&top=1")

AZP_AGENT_PACKAGE_LATEST_URL=$(echo "$AZP_AGENT_PACKAGES" | jq -r '.value[0].downloadUrl')

if [ -z "$AZP_AGENT_PACKAGE_LATEST_URL" -o "$AZP_AGENT_PACKAGE_LATEST_URL" == "null" ]; then
  echo 1>&2 "error: could not determine a matching Azure Pipelines agent"
  echo 1>&2 "check that account '$AZP_URL' is correct and the token is valid for that account"
  exit 1
fi

print_header "2. Downloading and extracting Azure Pipelines agent..."

curl -LsS $AZP_AGENT_PACKAGE_LATEST_URL | tar -xz & wait $!

source ./env.sh

print_header "3. Configuring Azure Pipelines agent..."

./config.sh --unattended \
  --agent "${AZP_AGENT_NAME:-$(hostname)}" \
  --url "$AZP_URL" \
  --auth PAT \
  --token $(cat "$AZP_TOKEN_FILE") \
  --pool "${AZP_POOL:-Default}" \
  --work "${AZP_WORK:-_work}" \
  --replace \
  --acceptTeeEula & wait $!

print_header "4. Running Azure Pipelines agent..."

trap 'cleanup; exit 0' EXIT
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM

chmod +x ./run-docker.sh

# To be aware of TERM and INT signals call run.sh
# Running it with the --once flag at the end will shut down the agent after the build is executed
./run-docker.sh "$@" & wait $!

Enter fullscreen mode Exit fullscreen mode

7 Build the docker image

docker build -t <your-acr-name>.azurecr.io/dockeragent:latest .

8 Upload the image to the already created container registry via CLI or portal;

az acr login --name <acr name> --username <adminUsername> --password <adminPassword>

docker push <your-acr-name>.azurecr.io/dockeragent:latest

9 Verify the image is in the azure container registry repository from portal

Image description

10 Create an Azure container Instance from either portal or via CLI , using the container registry attached.

Image description

Image description

Image description
NB: You need to provide the environment variables here itself. I found it not able to edit the variables once after the container instance is provisioned.

Below four are the variables required.
AZP_URL=https: your devops url
AZP_TOKEN=<Pat-Token-from-Azure-Devops>
AZP_AGENT_NAME=<Your-agent-name-which will be displayed in ADO>
AZP_POOL=<Pool-name- can be 'Default' as well>

To get the PAT Token. Navigate to Azure Devops, select Personal Access Tokens from User Settings Menu, and select New Token

Image description

Image description
Give it a name, and select Custom defined permission for Agent Pools - Read & Manage. If you are not able to see it, click on the bottom link to show all scopes
Once created copy the token, it won't be shown again.

Once created the container instance should spin up and the agent should be start listening to.

Image description

You can verify it checking in the AzureDevops Agent Pools too from Organization Settings.

Image description

I ran a sample pipeline using the container pool and it ran succesfully.

Image description

References:
https://jan-v.nl/post/2021/create-build-agent-with-azure-container-instances/

https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/docker?view=azure-devops&WT.mc_id=AZ-MVP-5003246#create-and-build-the-dockerfile-1

Top comments (0)