{"id":45897777,"url":"https://github.com/ppodgorsek/azure-pipelines-agent","last_synced_at":"2026-02-27T21:40:02.358Z","repository":{"id":323043768,"uuid":"1091724266","full_name":"ppodgorsek/azure-pipelines-agent","owner":"ppodgorsek","description":"A containerised agent for Azure Pipelines, with Docker-in-Docker enabled.","archived":false,"fork":false,"pushed_at":"2025-11-17T19:19:08.000Z","size":11,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-17T19:21:07.354Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ppodgorsek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"ppodgorsek","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2025-11-07T12:30:35.000Z","updated_at":"2025-11-17T19:18:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ppodgorsek/azure-pipelines-agent","commit_stats":null,"previous_names":["ppodgorsek/azure-pipelines-agent"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/ppodgorsek/azure-pipelines-agent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppodgorsek%2Fazure-pipelines-agent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppodgorsek%2Fazure-pipelines-agent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppodgorsek%2Fazure-pipelines-agent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppodgorsek%2Fazure-pipelines-agent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ppodgorsek","download_url":"https://codeload.github.com/ppodgorsek/azure-pipelines-agent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppodgorsek%2Fazure-pipelines-agent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29915660,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T19:37:42.220Z","status":"ssl_error","status_checked_at":"2026-02-27T19:37:41.463Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-27T21:40:01.898Z","updated_at":"2026-02-27T21:40:02.352Z","avatar_url":"https://github.com/ppodgorsek.png","language":"Dockerfile","funding_links":["https://github.com/sponsors/ppodgorsek"],"categories":[],"sub_categories":[],"readme":"# Azure Pipelines agent in Docker\n\n## Table of contents\n\n* [What is it?](#what-is-it)\n* [Versioning](#versioning)\n* [Running the container](#running-the-container)\n    * [Changing the name of the agent pool](#changing-agent-pool-name)\n    * [Initialising a self-hosted agent pool via the placeholder mode](#placeholder-mode)\n    * [Overriding the agent name](#overriding-agent-name)\n    * [Running Ansible](#running-ansible)\n* [Running the image on different platforms](#platforms)\n    * [Azure Container Apps](#platform-azure-container-apps)\n* [Please contribute!](#please-contribute)\n\n-----\n\n\u003ca name=\"what-is-it\"\u003e\u003c/a\u003e\n\n## What is it?\n\nThis project consists of an Azure Pipelines agent container image, including several useful build and deployment tools.\n\nThis image contains:\n* Ansible (with its major cloud collections)\n* gcc\n* git\n* Helm + kubectl\n* Java 21\n* make\n* Maven\n* .Net 10\n* Podman (with an alias for `docker`) + Buildah\n* PostgreSQL\n* Python 3\n* Rust\n* Terraform\n\nRunning Podman inside a container is based on RedHat's [excellent article](https://www.redhat.com/en/blog/podman-inside-container), the official [Podman tutorial for rootless executions](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md) and [Podman's official container image](https://quay.io/repository/podman/stable?tab=info).\n\n\u003e [!WARNING]  \n\u003e As mentioned in those articles, running Podman-in-Docker or Docker-in-Docker won't be possible on platforms such as Azure Container Apps where a privileged execution isn't possible. It is however possible in Kubernetes or on machines where such privileged execution is allowed.\n\n\u003e [!TIP]\n\u003e On platforms where privileged execution is impossible, one option can be to split the build pipeline into multiple stages and to run any container build/run steps on a Microsoft-hosted agent while the rest of the pipeline runs on a self-hosted agent.\n\n\u003ca name=\"versioning\"\u003e\u003c/a\u003e\n\n## Versioning\n\nThe versioning of this image follows the one of the [official Azure Pipelines agent](https://github.com/microsoft/azure-pipelines-agent):\n\n* Major, minor and patch versions match the one of the Azure Pipelines agent\n* Build version is specific to this project (allows to update the versions of the other dependencies)\n\n\u003ca name=\"running-the-container\"\u003e\u003c/a\u003e\n\n## Running the container\n\nThis container can be run using the following command:\n\n```sh\ndocker run --rm \\\n    -e AZURE_DEVOPS_TOKEN=\"CHANGEME\" \\\n    -e AZURE_DEVOPS_URL=\"CHANGEME\" \\\n    docker.io/ppodgorsek/azure-pipelines-agent:\u003cversion\u003e\n```\n\nA personal access token can be generated in Azure DevOps, and should be set using the `AZURE_DEVOPS_TOKEN` variable. Please note that this could also be a token from a service principal.\n\nThe `AZURE_DEVOPS_URL` variable represents the URL of your organisation's instance, for example `https://dev.azure.com/\u003corganisation ID\u003e`.\n\n\u003ca name=\"changing-agent-pool-name\"\u003e\u003c/a\u003e\n\n### Changing the name of the agent pool\n\nBy default, the agent pool name is simply `Default`.\n\nThis can be changed if needed via the `AZURE_DEVOPS_AGENT_POOL` environment variable:\n\n```sh\ndocker run --rm \\\n    -e AZURE_DEVOPS_AGENT_POOL='Azure Container Apps' \\\n    -e AZURE_DEVOPS_TOKEN=\"CHANGEME\" \\\n    -e AZURE_DEVOPS_URL=\"CHANGEME\" \\\n    docker.io/ppodgorsek/azure-pipelines-agent:\u003cversion\u003e\n```\n\n\u003ca name=\"placeholder-mode\"\u003e\u003c/a\u003e\n\n### Initialising a self-hosted agent pool using the placeholder mode\n\nIn order to be used by pipelines, self-hosted agent pools must be initialised by running an agent at least once within them. This allows Azure Pipelines to determine the agent version, its capabilities and other metadata to allocate build jobs.\n\n\u003e [!NOTE]  \n\u003e Placeholders are only relevant when deploying the agent to services which don't have at least one continuously-running instance, such as Azure Container Apps.\n\nAfter creating a new agent pool, the placeholder mode can be enabled using the `AZURE_DEVOPS_AGENT_PLACEHOLDER_MODE` environment variable:\n\n```sh\ndocker run --rm \\\n    -e AZURE_DEVOPS_AGENT_PLACEHOLDER_MODE=\"true\" \\\n    -e AZURE_DEVOPS_AGENT_POOL=\"Azure Container Apps\" \\\n    -e AZURE_DEVOPS_TOKEN=\"CHANGEME\" \\\n    -e AZURE_DEVOPS_URL=\"CHANGEME\" \\\n    docker.io/ppodgorsek/azure-pipelines-agent:\u003cversion\u003e\n```\n\nAgents run using the placeholder mode will follow a very simple lifecycle:\n1. Configure the agent,\n2. Register the agent in the Azure DevOps pool,\n2. Terminate.\n\n\u003e [!IMPORTANT]  \n\u003e Such placeholder agents cannot process any build jobs, the environment variable should therefore only be used for the initial placeholder agent, not all agents.\n\n\u003ca name=\"overriding-agent-name\"\u003e\u003c/a\u003e\n\n### Overriding the agent name\n\nBy default, the agent name within the pool will be its host name.\n\nThis can however be overriden if needed, by relying on the `AZURE_DEVOPS_AGENT_NAME` environment variable:\n\n```sh\ndocker run --rm \\\n    -e AZURE_DEVOPS_AGENT_NAME='custom-agent' \\\n    -e AZURE_DEVOPS_TOKEN=\"CHANGEME\" \\\n    -e AZURE_DEVOPS_URL=\"CHANGEME\" \\\n    docker.io/ppodgorsek/azure-pipelines-agent:\u003cversion\u003e\n```\n\n\u003ca name=\"running-ansible\"\u003e\u003c/a\u003e\n\n### Running Ansible\n\nWhen running Ansible in your build pipeline, remember to install the relevant Ansible collections, for example:\n\n```yml\n- script: |\n  cd $(Pipeline.Workspace)/$(INFRASTRUCTURE_AS_CODE_PATH)/\n\n  ansible-galaxy install -r collections/requirements.yml\n\n  ansible-playbook CHANGEME-playbook.yml -i inventories/CHANGEME/hosts\ndisplayName: Ansible\n```\n\n\u003ca name=\"platforms\"\u003e\u003c/a\u003e\n\n## Running the image on different platforms\n\n\u003ca name=\"platform-azure-container-apps\"\u003e\u003c/a\u003e\n\n### Azure Container Apps\n\nThe easiest way to run the agent in Azure is via an Azure Container App Job.\n\nSuch jobs can scale up and down according to various metrics and, luckily, one of those metrics is the number of pending jobs in Azure Pipelines.\n\nThe Terraform configuration will therefore look as follows:\n\n```tf\n# The placeholder job is used to initialise the agent pool\nresource \"azurerm_container_app_job\" \"azure_pipelines_agent_placeholder\" {\n  name                         = \"${var.azure_devops_container_app_azure_pipelines_agent_name}-init\"\n  location                     = azurerm_resource_group.azure_devops.location\n  resource_group_name          = azurerm_resource_group.azure_devops.name\n  container_app_environment_id = azurerm_container_app_environment.azure_devops.id\n\n  replica_timeout_in_seconds = 300\n  replica_retry_limit        = 0\n\n  manual_trigger_config {\n    parallelism              = 1\n    replica_completion_count = 1\n  }\n\n  identity {\n    identity_ids = [\n      azurerm_user_assigned_identity.azure_devops.id,\n    ]\n    type = \"UserAssigned\"\n  }\n\n  secret {\n    identity            = azurerm_user_assigned_identity.azure_devops.id\n    key_vault_secret_id = data.azurerm_key_vault_secret.azure_devops_access_token.id\n    name                = var.azure_devops_keyvault_access_token_secret_name\n  }\n\n  secret {\n    identity            = azurerm_user_assigned_identity.azure_devops.id\n    key_vault_secret_id = data.azurerm_key_vault_secret.azure_devops_organisation_url.id\n    name                = var.azure_devops_keyvault_organisation_url_secret_name\n  }\n\n  # Probes are currently not supported, as no endpoints are exposed\n  # https://github.com/microsoft/azure-pipelines-agent/issues/3478\n  template {\n    container {\n      image = var.azure_devops_pipelines_agent_image\n      name  = \"azure-devops-agent-init\"\n\n      cpu    = 2\n      memory = \"4Gi\"\n\n      env {\n        name  = \"AZURE_DEVOPS_AGENT_POOL\"\n        value = var.azure_devops_pipelines_agent_pool\n      }\n\n      env {\n        name  = \"AZURE_DEVOPS_AGENT_PLACEHOLDER_MODE\"\n        value = \"true\"\n      }\n\n      env {\n        name        = \"AZURE_DEVOPS_TOKEN\"\n        secret_name = var.azure_devops_keyvault_access_token_secret_name\n      }\n\n      env {\n        name        = \"AZURE_DEVOPS_URL\"\n        secret_name = var.azure_devops_keyvault_organisation_url_secret_name\n      }\n    }\n  }\n}\n\nresource \"azurerm_container_app_job\" \"azure_pipelines_agent\" {\n  name                         = var.azure_devops_container_app_azure_pipelines_agent_name\n  location                     = azurerm_resource_group.azure_devops.location\n  resource_group_name          = azurerm_resource_group.azure_devops.name\n  container_app_environment_id = azurerm_container_app_environment.azure_devops.id\n\n  replica_timeout_in_seconds = 7200\n  replica_retry_limit        = 0\n\n  event_trigger_config {\n    scale {\n      max_executions              = 3\n      min_executions              = 0\n      polling_interval_in_seconds = 30\n\n      rules {\n        custom_rule_type = \"azure-pipelines\"\n        metadata = {\n          poolName                   = var.azure_devops_pipelines_agent_pool\n          targetPipelinesQueueLength = 1\n        }\n        name = \"azure-pipelines-job-queue-length\"\n\n        authentication {\n          secret_name       = var.azure_devops_keyvault_access_token_secret_name\n          trigger_parameter = \"personalAccessToken\"\n        }\n\n        authentication {\n          secret_name       = var.azure_devops_keyvault_organisation_url_secret_name\n          trigger_parameter = \"organizationURL\"\n        }\n      }\n    }\n  }\n\n  identity {\n    identity_ids = [\n      azurerm_user_assigned_identity.azure_devops.id,\n    ]\n    type = \"UserAssigned\"\n  }\n\n  secret {\n    identity            = azurerm_user_assigned_identity.azure_devops.id\n    key_vault_secret_id = data.azurerm_key_vault_secret.azure_devops_access_token.id\n    name                = var.azure_devops_keyvault_access_token_secret_name\n  }\n\n  secret {\n    identity            = azurerm_user_assigned_identity.azure_devops.id\n    key_vault_secret_id = data.azurerm_key_vault_secret.azure_devops_organisation_url.id\n    name                = var.azure_devops_keyvault_organisation_url_secret_name\n  }\n\n  # Probes are currently not supported, as no endpoints are exposed\n  # https://github.com/microsoft/azure-pipelines-agent/issues/3478\n  template {\n    container {\n      image = var.azure_devops_pipelines_agent_image\n      name  = \"azure-devops-agent\"\n\n      cpu    = 2\n      memory = \"4Gi\"\n\n      env {\n        name  = \"AZURE_DEVOPS_AGENT_POOL\"\n        value = var.azure_devops_pipelines_agent_pool\n      }\n\n      env {\n        name        = \"AZURE_DEVOPS_TOKEN\"\n        secret_name = var.azure_devops_keyvault_access_token_secret_name\n      }\n\n      env {\n        name        = \"AZURE_DEVOPS_URL\"\n        secret_name = var.azure_devops_keyvault_organisation_url_secret_name\n      }\n    }\n  }\n}\n```\n\nOnce deployed, go to the Azure Portal, open the Container App Job named `caj-azure-pipelines-agent-init` and run it manually. The agent pool in Azure DevOps should then show at least one (disconnected) agent within it and the pool will be ready to use.\n\n\u003ca name=\"please-contribute\"\u003e\u003c/a\u003e\n\n## Please contribute!\n\nHave you found an issue? Do you have an idea for an improvement? Feel free to contribute by submitting it [on the GitHub project](https://github.com/ppodgorsek/azure-pipelines-agent/issues).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fppodgorsek%2Fazure-pipelines-agent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fppodgorsek%2Fazure-pipelines-agent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fppodgorsek%2Fazure-pipelines-agent/lists"}