How to run self hosted agent on Azure Container Instance
Published: 2022-10-26 16:24:18

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0058qfg0c3cbrrlcs1ip.png)

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" ]
```

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 $!

```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ual5ikj3af7zqi9wjyx8.png)

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


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ob18rr7wzlsytfln0iqf.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aw0e9wsynxpc0nurj6bp.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1s6z0vbewobcz31rial.png)
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qhl8sidm8785qpr8i8g.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ldpcmrkwm14wzebsqoo6.png)
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/li5d461aw6i0kglrstmn.png)


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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dzyufb7aftla68kfp0c2.png)


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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3dzsb55qvmuvblfabnij.png)


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