Back to Blog
DevOps
3 min read

Running Azure DevOps Agents in Containers

Azure DevOpsDockerCI/CDContainers

Microsoft-hosted agents are convenient but sometimes you need self-hosted: private network access, specific software, or just more control. Running agents in containers gives you the best of both worlds.

Why Container Agents?

Compared to VM-based agents:

  • Faster provisioning - Seconds vs minutes
  • Better resource utilisation - Multiple agents per host
  • Consistent environment - Same image everywhere
  • Easy scaling - Spin up more containers as needed
  • Simpler updates - Rebuild the image, restart containers

Base Agent Dockerfile

FROM ubuntu:22.04

# Avoid prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive

# Install dependencies
RUN apt-get update && apt-get install -y \
    curl \
    git \
    jq \
    libicu70 \
    libssl3 \
    ca-certificates \
    apt-transport-https \
    software-properties-common \
    && rm -rf /var/lib/apt/lists/*

# Install Azure CLI
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash

# Install PowerShell
RUN curl -sSL https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
    && echo "deb https://packages.microsoft.com/repos/microsoft-ubuntu-jammy-prod jammy main" > /etc/apt/sources.list.d/microsoft.list \
    && apt-get update \
    && apt-get install -y powershell \
    && rm -rf /var/lib/apt/lists/*

# Install Terraform
RUN curl -sSL https://releases.hashicorp.com/terraform/1.6.0/terraform_1.6.0_linux_amd64.zip -o terraform.zip \
    && unzip terraform.zip \
    && mv terraform /usr/local/bin/ \
    && rm terraform.zip

# Create agent directory
WORKDIR /azp
RUN mkdir -p /azp/agent

# Download and extract agent
ARG AGENT_VERSION=3.227.2
RUN curl -sSL https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz | tar -xz -C /azp/agent

# Start script
COPY start.sh /azp/
RUN chmod +x /azp/start.sh

ENTRYPOINT ["/azp/start.sh"]

Start Script

#!/bin/bash
set -e

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

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

if [ -z "$AZP_POOL" ]; then
  AZP_POOL="Default"
fi

cd /azp/agent

# Configure the agent
./config.sh --unattended \
  --url "$AZP_URL" \
  --auth pat \
  --token "$AZP_TOKEN" \
  --pool "$AZP_POOL" \
  --agent "${AZP_AGENT_NAME:-$(hostname)}" \
  --replace \
  --acceptTeeEula

# Run the agent
./run.sh

Docker-in-Docker

If your pipelines need to build Docker images, you have two options:

Option 1: Docker Socket Mounting

Mount the host's Docker socket:

docker run -d \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e AZP_URL="https://dev.azure.com/yourorg" \
  -e AZP_TOKEN="your-pat" \
  -e AZP_POOL="ContainerAgents" \
  your-agent-image

Pros: Simpler, uses host's Docker daemon Cons: Security risk - container can access all host containers

Option 2: Docker-in-Docker (DinD)

Run Docker daemon inside the container:

# Add to Dockerfile
RUN curl -fsSL https://get.docker.com | sh

# Start script needs to start dockerd
dockerd &
sleep 5  # Wait for daemon to start

Run with privileged mode:

docker run -d --privileged \
  -e AZP_URL="https://dev.azure.com/yourorg" \
  -e AZP_TOKEN="your-pat" \
  your-agent-image

Pros: Isolated Docker daemon Cons: Requires privileged mode, more complex

Kubernetes Deployment

For Kubernetes, use a deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: azdo-agent
spec:
  replicas: 3
  selector:
    matchLabels:
      app: azdo-agent
  template:
    metadata:
      labels:
        app: azdo-agent
    spec:
      containers:
      - name: agent
        image: your-registry/azdo-agent:latest
        env:
        - name: AZP_URL
          value: "https://dev.azure.com/yourorg"
        - name: AZP_TOKEN
          valueFrom:
            secretKeyRef:
              name: azdo-pat
              key: token
        - name: AZP_POOL
          value: "K8sAgents"

Security Considerations

  • PAT tokens - Use minimal scope (Agent Pools read/manage)
  • Socket mounting - Only if you trust all pipeline code
  • Privileged mode - Avoid if possible
  • Image scanning - Scan your agent images for vulnerabilities
  • Network policies - Restrict agent egress in Kubernetes

Need help setting up CI/CD infrastructure? Get in touch - we help teams build efficient DevOps pipelines.

Need help with your Azure environment?

Get in touch for a free consultation.

Get in Touch