You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/pipelines/process/container-phases.md
+51-65Lines changed: 51 additions & 65 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,73 +1,63 @@
1
1
---
2
-
title: Container jobs in YAML
3
-
description: Learn about configuring and running pipeline jobs inside containers.
2
+
title: YAML pipeline container jobs
3
+
description: Learn about configuring and running Azure Pipelines YAML pipeline jobs inside containers.
4
4
ms.assetid: 8d35f78a-f386-4699-9280-7bd933de9e7b
5
5
ms.topic: conceptual
6
-
ms.date: 07/08/2024
6
+
ms.date: 08/19/2025
7
7
monikerRange: "<=azure-devops"
8
+
#customer intent: As an Azure Pipelines builder and tester, I want to learn about running pipeline jobs in containers so I can build and test pipelines in various agent configurations.
This article explains container jobs in Azure Pipelines.
15
+
This article explains container jobs in Azure Pipelines. Containers are lightweight abstractions from the host operating system that provide all the necessary elements to run a job in a specific environment.
15
16
16
-
By default, Azure Pipelines [jobs](phases.md) run directly on the host machines where the agent is installed. Hosted agent jobs are convenient, require little initial setup and infrastructure to maintain, and are well-suited for basic projects.
17
+
By default, Azure Pipelines [jobs](phases.md) run directly on [agents](../agents/agents.md) installed on host machines. Hosted agent jobs are convenient, require little initial setup or infrastructure maintenance, and are well-suited for basic projects. For more control over task context, you can define and run pipeline jobs in containers to get the exact versions of operating systems, tools, and dependencies you want.
17
18
18
-
If you want more control over task context, you can define and run jobs in containers. Containers are a lightweight abstraction over the host operating system that provides isolation from the host. When you run jobs in containers, you can select the exact versions of operating systems, tools, and dependencies that your build requires.
19
+
For a container job, the agent first fetches and starts the container, and then runs each step of the job inside the container. If you need finer-grained control of individual build steps, you can use [step targets](tasks.md#step-target) to choose a container or host for each step.
19
20
20
-
Linux and Windows [agents](../agents/agents.md) can run pipeline jobs directly on the host or in containers. Container jobs aren't available on macOS.
21
+
## Requirements for container jobs
21
22
22
-
For a container job, the agent first fetches and starts the container. Then each step of the job runs inside the container.
23
-
24
-
::: moniker range="<=azure-devops"
25
-
If you need fine-grained control at the individual build step level, [step targets](tasks.md#step-target) let you choose a container or host for each step.
26
-
::: moniker-end
27
-
28
-
## Prerequisites
29
-
30
-
- Use a YAML pipeline. Classic pipelines do not support container jobs.
31
-
- Use a hosted Windows or Ubuntu agent. Only `windows-*` and `ubuntu-*` agents support running containers. The `macos-*` agents don't support running containers.
32
-
- Your agent is set up for container jobs.
33
-
- Windows and Linux agents must have Docker installed, and need permission to access the Docker daemon.
34
-
- Containers aren't supported when the agent is already running inside a container. You can't have nested containers.
35
-
36
-
### Additional container requirements
23
+
- A YAML-based pipeline. Classic pipelines don't support container jobs.
24
+
- A Windows or Ubuntu hosted agent. MacOS agents don't support containers. To use non-Ubuntu Linux agents, see [Nonglibc-based containers](#nonglibc-based-containers).
25
+
- Docker installed on the agent, with permission to access the Docker daemon.
26
+
- Agent running directly on the host, not already inside a container. Nested containers aren't supported.
37
27
38
28
### [Linux](#tab/linux)
39
29
40
-
Linux-based containers have the following requirements. For workarounds, see [Nonglibc-based containers](#nonglibc-based-containers).
30
+
Linux-based containers also have the following requirements:
41
31
42
-
- Bash installed
43
-
- GNU C Library (glibc)-based
44
-
- No `ENTRYPOINT`
45
-
-Provide `USER` with access to `groupadd` and other privileged commands without using `sudo`
46
-
-Can run Node.js, which the agent provides
47
-
>[!NOTE]
48
-
>Node.js must be pre-installed for Linux containers on Windows hosts.
32
+
- Bash installed.
33
+
- GNU C Library (`glibc`)-based. Nonglibc containers require added setup. For more information, see [Nonglibc-based containers](#nonglibc-based-containers).
34
+
- No `ENTRYPOINT`. Containers with an `ENTRYPOINT` might not work, because [docker exec](https://docs.docker.com/reference/cli/docker/container/exec) expects the container to always be running.
35
+
-`USER`provided with access to `groupadd` and other privileged commands without using `sudo`.
36
+
-Ability to run Node.js, which the agent provides.
37
+
>[!NOTE]
38
+
>Node.js must be preinstalled for Linux containers on Windows hosts.
49
39
50
-
Some stripped-down containers available on Docker Hub, especially containers based on Alpine Linux, don't satisfy these requirements. Containers with an `ENTRYPOINT` might not work because Azure Pipelines `docker create` and `docker exec` expect that the container is always up and running.
40
+
Some stripped-down containers available on Docker Hub, especially containers based on Alpine Linux, don't satisfy these requirements. For more information, see [Nonglibc-based containers](#nonglibc-based-containers).
51
41
52
42
### [Windows](#tab/windows)
53
43
54
-
[Windows containers](/virtualization/windowscontainers/about/)must meet the following requirements:
44
+
[Windows containers](/virtualization/windowscontainers/about/)also have the following requirements:
55
45
56
-
- Windows Server version 1803 or higher
57
-
- Matching host and container kernel versions
58
-
-Can run Node.js
59
-
>[!NOTE]
60
-
>A base Windows Nano Server container doesn't have the required dependencies to run Node.js.
46
+
- Windows Server version 1803 or higher.
47
+
- Matching host and container kernel versions.
48
+
-Ability to run Node.js, which the agent provides.
49
+
>[!NOTE]
50
+
>A base Windows Nano Server container doesn't have the required dependencies to run Node.js.
61
51
62
52
---
63
53
64
-
## Single job examples
54
+
## Single job
65
55
66
-
The following examples define a Windows or Linux container for a singlejob.
56
+
The following example defines a Windows or Linux single-job container.
67
57
68
58
### [Linux](#tab/linux)
69
59
70
-
The following simple example defines a Linux container:
60
+
This example tells the system to fetch the `ubuntu` image tagged `18.04` from [Docker Hub](https://hub.docker.com) and then start the container. The `printenv` command runs inside the `ubuntu:18.04` container.
71
61
72
62
```yaml
73
63
pool:
@@ -79,11 +69,9 @@ steps:
79
69
- script: printenv
80
70
```
81
71
82
-
The preceding example tells the system to fetch the `ubuntu` image tagged `18.04` from [Docker Hub](https://hub.docker.com) and then start the container. The `printenv` command runs inside the `ubuntu:18.04` container.
83
-
84
72
### [Windows](#tab/windows)
85
73
86
-
The following example defines a Windows container:
74
+
For Windows, the kernel version of the host and container must match. Since the following example uses a Windows 2019 host image, it uses the `2019` tag for the container.
87
75
88
76
```yaml
89
77
pool:
@@ -95,13 +83,11 @@ steps:
95
83
- script: set
96
84
```
97
85
98
-
For Windows, the kernel version of the host and container must match. Since the preceding example uses a Windows 2019 host image, it uses the `2019` tag for the container.
99
-
100
86
---
101
87
102
88
## Multiple jobs
103
89
104
-
You can use containers to run the same step in multiple jobs. The following example runs the same step in multiple versions of Ubuntu Linux. You don't have to mention the `jobs` keyword because only a single job is defined.
90
+
You can use containers to run the same step in multiple jobs. The following example runs the same step in multiple versions of Ubuntu Linux. You don't have to use the `jobs` keyword, because only a single job is defined.
105
91
106
92
```yaml
107
93
pool:
@@ -122,11 +108,13 @@ steps:
122
108
- script: printenv
123
109
```
124
110
125
-
### Multiple jobs with agent pools on a single agent host
111
+
### Multiple jobs on a single agent host
126
112
127
-
A container job uses the underlying host agent's Docker configuration file for image registry authorization. This file signs out at the end of the Docker registry container initialization. Registry image pulls for subsequent container jobs might be denied for `unauthorized authentication` because another job running in parallel already signed out the Docker configuration file.
113
+
A container job uses the underlying host agent's Docker configuration file for image registry authorization. This file signs out at the end of the Docker registry container initialization.
128
114
129
-
The solution is to set a Docker environment variable `DOCKER_CONFIG` that's specific to each agent pool running on the hosted agent. Export the `DOCKER_CONFIG` in each agent pool's *runsvc.sh* script as follows:
115
+
Registry image pulls for container jobs could be denied for unauthorized authentication if another job running in parallel on the agent already signed out the Docker configuration file. The solution is to set a Docker environment variable called `DOCKER_CONFIG` for each agent pool running on the hosted agent.
116
+
117
+
Export the `DOCKER_CONFIG` in each agent pool's *runsvc.sh* script as follows:
You can specify `options` to control container startup, as in the following example:
126
+
You can use the `options` property to specify options for container startup.
139
127
140
128
```yaml
141
129
container:
@@ -146,13 +134,13 @@ steps:
146
134
- script: echo hello
147
135
```
148
136
149
-
Running `docker create --help` gives you the list of options that you can pass to Docker invocation. Not all of these options are guaranteed to work with Azure DevOps. Check first to see if you can use a `container` property to accomplish the same goal.
137
+
Run `docker create --help` to get the list of options you can pass to Docker invocation. Not all these options are guaranteed to work with Azure Pipelines. Check first to see if you can use a `container` property for the same purpose.
150
138
151
-
For more information, see the [docker create](https://docs.docker.com/engine/reference/commandline/create) command reference and the [resources.containers.container definition](/azure/devops/pipelines/yaml-schema/resources-containers-container) in the Azure DevOps YAML schema reference.
139
+
For more information, see the [docker container create](https://docs.docker.com/reference/cli/docker/container/create/) command reference and the [resources.containers.container](/azure/devops/pipelines/yaml-schema/resources-containers-container) definition in the [YAML schema reference for Azure Pipelines](/azure/devops/pipelines/yaml-schema).
152
140
153
141
## Reusable container definition
154
142
155
-
The following example defines the containers in the `resources` section, and then references them by their assigned aliases. The `jobs` keyword is explicitly listed for clarity.
143
+
The following YAML example defines the containers in the `resources` section, and then references them by their assigned aliases. The `jobs` keyword is used for clarity.
156
144
157
145
```yaml
158
146
resources:
@@ -188,7 +176,7 @@ jobs:
188
176
189
177
## Service endpoints
190
178
191
-
You can host containers on other registries than public Docker Hub. To host an image on [Azure Container Registry](/azure/container-registry/) or another private container registry, including a private Docker Hub registry, add a [service connection](../library/service-endpoints.md) to access the registry. Then you can reference the endpoint in the container definition.
179
+
You can host containers on registries other than public Docker Hub. To host an image on [Azure Container Registry](/azure/container-registry/) or another private container registry, including a private Docker Hub registry, add a [service connection](../library/service-endpoints.md#docker-registry-service-connection) to access the registry. Then you can reference the endpoint in the container definition.
192
180
193
181
Private Docker Hub connection:
194
182
@@ -207,25 +195,23 @@ container:
207
195
```
208
196
209
197
>[!NOTE]
210
-
>Azure Pipelines can't set up a service connection for Amazon Elastic Container Registry (ECR), because Amazon ECR requires other client tools to convert AWS credentials into something Docker can use to authenticate.
198
+
>Azure Pipelines can't set up a service connection for Amazon Elastic Container Registry (ECR), because Amazon ECR requires other client tools to convert Amazon Web Services (AWS) credentials to be usable for Docker authentication.
211
199
212
200
## Nonglibc-based containers
213
201
214
-
The Azure Pipelines agent supplies a copy of Node.js, which is required to run tasks and scripts. To find out the version of Node.js for a hosted agent, see [Microsoft-hosted agents](../agents/hosted.md#software).
215
-
216
-
The version of Node.js compiles against the C runtime used in the hosted cloud, typically glibc. Some Linux variants use other C runtimes. For instance, Alpine Linux uses musl.
202
+
The hosted Azure Pipelines agents supply Node.js, which is required to run tasks and scripts. The Node.js version compiles against the C runtime used in the hosted cloud, typically `glibc`. Some Linux variants use other C runtimes. For instance, Alpine Linux uses `musl`. For more information, see [Microsoft-hosted agents](../agents/hosted.md#software).
217
203
218
-
If you want to use a nonglibc-based container, you need to:
204
+
If you want to use a nonglibc-based container in a pipeline, you must:
219
205
220
206
- Supply your own copy of Node.js.
221
-
- Add a label to your image telling the agent where to find the Node.js binary.
222
-
- Provide other dependencies that Azure Pipelines depends on: `bash`, `sudo`, `which`, and `groupadd`.
207
+
- Add a label to your image pointing to the location of the Node.js binary.
208
+
- Provide the `bash`, `sudo`, `which`, and `groupadd` Azure Pipelines dependencies.
223
209
224
210
### Supply your own Node.js
225
211
226
-
If you use a nonglibc-based container, you're responsible for adding a Node binary to your container. Node.js 18 is a safe choice. Start from the `node:18-alpine` image.
212
+
If you use a nonglibc-based container, you must add a Node binary to your container. Node.js 18 is a safe choice. Start from the `node:18-alpine` image.
227
213
228
-
### Tell the agent about Node.js
214
+
### Direct the agent to Node.js
229
215
230
216
The agent reads the container label `"com.azure.dev.pipelines.handler.node.path"`. If this label exists, it must be the path to the Node.js binary.
Azure Pipelines assumes a Bash-based system with common administrative packages installed. Alpine Linux in particular doesn't come with several of the packages needed. Install `bash`, `sudo`, and `shadow` to cover the basic needs.
226
+
Azure Pipelines requires a Bash-based system to have common administrative packages installed. Alpine Linux doesn't have several of the needed packages. Install `bash`, `sudo`, and `shadow` to cover basic needs.
241
227
242
228
```dockerfile
243
229
RUN apk add bash sudo shadow
244
230
```
245
231
246
-
If you depend on any in-box or Marketplace tasks, also supply the binaries they require.
232
+
If you depend on any built-in or Marketplace tasks, also supply the binaries they require.
0 commit comments