Skip to content

Commit ae2a14a

Browse files
[feat] added azure pipelines guide (#22777)
This PR introduces a new CI pipeline using Azure Pipelines to automate the process of building and pushing Docker images to Docker Hub. --------- Co-authored-by: Julien Maitrehenry <[email protected]>
1 parent 46349c4 commit ae2a14a

File tree

1 file changed

+311
-0
lines changed

1 file changed

+311
-0
lines changed

content/guides/azure-pipelines.md

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
---
2+
title: Introduction to Azure Pipelines with Docker
3+
linkTitle: Azure Pipelines and Docker
4+
summary: |
5+
Learn how to automate Docker image build and push using Azure Pipelines.
6+
params:
7+
tags: [devops]
8+
time: 10 minutes
9+
---
10+
11+
> This guide is a community contribution. Docker would like to thank [Kristiyan Velkov](https://www.linkedin.com/in/kristiyan-velkov-763130b3/) for his valuable contribution.
12+
13+
## Prerequisites
14+
15+
Before you begin, ensure you have the following requirements:
16+
17+
- A [Docker Hub account](https://hub.docker.com) with a generated access token.
18+
- An active [Azure DevOps project](https://dev.azure.com/) with a connected [Git repository](https://learn.microsoft.com/en-us/azure/devops/repos/git/?view=azure-devops).
19+
- A project that includes a valid [`Dockerfile`](https://docs.docker.com/engine/reference/builder/) at its root or appropriate build context.
20+
21+
## Overview
22+
23+
This guide walks you through building and pushing Docker images using [Azure Pipelines](https://azure.microsoft.com/en-us/products/devops/pipelines), enabling a streamlined and secure CI workflow for containerized applications. You’ll learn how to:
24+
25+
- Configure Docker authentication securely.
26+
- Set up an automated pipeline to build and push images.
27+
28+
## Set up Azure DevOps to work with Docker Hub
29+
30+
### Step 1: Configure a Docker Hub service connection
31+
32+
To securely authenticate with Docker Hub using Azure Pipelines:
33+
34+
1. Navigate to **Project Settings > Service Connections** in your Azure DevOps project.
35+
2. Select **New service connection > Docker Registry**.
36+
3. Choose **Docker Hub** and provide your Docker Hub credentials or access token.
37+
4. Give the service connection a recognizable name, such as `my-docker-registry`.
38+
5. Grant access only to the specific pipeline(s) that require it for improved security and least privilege.
39+
40+
> [!IMPORTANT]
41+
>
42+
> Avoid selecting the option to grant access to all pipelines unless absolutely necessary. Always apply the principle of least privilege.
43+
44+
### Step 2: Create your pipeline
45+
46+
Add the following `azure-pipelines.yml` file to the root of your repository:
47+
48+
```yaml
49+
# Trigger pipeline on commits to the main branch
50+
trigger:
51+
- main
52+
53+
# Trigger pipeline on pull requests targeting the main branch
54+
pr:
55+
- main
56+
57+
# Define variables for reuse across the pipeline
58+
variables:
59+
imageName: 'docker.io/$(dockerUsername)/my-image'
60+
buildTag: '$(Build.BuildId)'
61+
latestTag: 'latest'
62+
63+
stages:
64+
- stage: BuildAndPush
65+
displayName: Build and Push Docker Image
66+
jobs:
67+
- job: DockerJob
68+
displayName: Build and Push
69+
pool:
70+
vmImage: ubuntu-latest
71+
demands:
72+
- docker
73+
steps:
74+
- checkout: self
75+
displayName: Checkout Code
76+
77+
- task: Docker@2
78+
displayName: Docker Login
79+
inputs:
80+
command: login
81+
containerRegistry: 'my-docker-registry' # Service connection name
82+
83+
- task: Docker@2
84+
displayName: Build Docker Image
85+
inputs:
86+
command: build
87+
repository: $(imageName)
88+
tags: |
89+
$(buildTag)
90+
$(latestTag)
91+
dockerfile: './Dockerfile'
92+
arguments: |
93+
--sbom=true
94+
--attest type=provenance
95+
--cache-from $(imageName):latest
96+
env:
97+
DOCKER_BUILDKIT: 1
98+
99+
- task: Docker@2
100+
displayName: Push Docker Image
101+
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
102+
inputs:
103+
command: push
104+
repository: $(imageName)
105+
tags: |
106+
$(buildTag)
107+
$(latestTag)
108+
109+
# Optional: logout for self-hosted agents
110+
- script: docker logout
111+
displayName: Docker Logout (Self-hosted only)
112+
condition: ne(variables['Agent.OS'], 'Windows_NT')
113+
```
114+
115+
## What this pipeline does
116+
117+
This pipeline automates the Docker image build and deployment process for the main branch. It ensures a secure and efficient workflow with best practices like caching, tagging, and conditional cleanup. Here's what it does:
118+
119+
- Triggers on commits and pull requests targeting the `main` branch.
120+
- Authenticates securely with Docker Hub using an Azure DevOps service connection.
121+
- Builds and tags the Docker image using Docker BuildKit for caching.
122+
- Pushes both buildId and latest tags to Docker Hub.
123+
- Logs out from Docker if running on a self-hosted Linux agent.
124+
125+
126+
## How the pipeline works
127+
128+
### Step 1: Define pipeline triggers
129+
130+
```yaml
131+
trigger:
132+
- main
133+
134+
pr:
135+
- main
136+
```
137+
138+
This pipeline is triggered automatically on:
139+
- Commits pushed to the `main` branch
140+
- Pull requests targeting `main` main branch
141+
142+
> [!TIP]
143+
> Learn more: [Define pipeline triggers in Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/build/triggers?view=azure-devops)
144+
145+
### Step 2: Define common variables
146+
147+
```yaml
148+
variables:
149+
imageName: 'docker.io/$(dockerUsername)/my-image'
150+
buildTag: '$(Build.BuildId)'
151+
latestTag: 'latest'
152+
```
153+
154+
These variables ensure consistent naming, versioning, and reuse throughout the pipeline steps:
155+
156+
- `imageName`: your image path on Docker Hub
157+
- `buildTag`: a unique tag for each pipeline run
158+
- `latestTag`: a stable alias for your most recent image
159+
160+
> [!IMPORTANT]
161+
>
162+
> The variable `dockerUsername` is not set automatically.
163+
> Set it securely in your Azure DevOps pipeline variables:
164+
> 1. Go to **Pipelines > Edit > Variables**
165+
> 2. Add `dockerUsername` with your Docker Hub username
166+
>
167+
> Learn more: [Define and use variables in Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch)
168+
169+
### Step 3: Define pipeline stages and jobs
170+
171+
```yaml
172+
stages:
173+
- stage: BuildAndPush
174+
displayName: Build and Push Docker Image
175+
```
176+
177+
This stage executes only if the source branch is `main`.
178+
179+
> [!TIP]
180+
>
181+
> Learn more: [Stage conditions in Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&tabs=yaml)
182+
183+
184+
### Step 4: Job configuration
185+
186+
```yaml
187+
jobs:
188+
- job: DockerJob
189+
displayName: Build and Push
190+
pool:
191+
vmImage: ubuntu-latest
192+
demands:
193+
- docker
194+
```
195+
196+
This job utilizes the latest Ubuntu VM image with Docker support, provided by Microsoft-hosted agents. It can be replaced with a custom pool for self-hosted agents if necessary.
197+
198+
> [!TIP]
199+
>
200+
> Learn more: [Specify a pool in your pipeline](https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/pools-queues?view=azure-devops&tabs=yaml%2Cbrowser)
201+
202+
#### Step 4.1: Checkout code
203+
204+
```yaml
205+
steps:
206+
- checkout: self
207+
displayName: Checkout Code
208+
```
209+
210+
This step pulls your repository code into the build agent, so the pipeline can access the Dockerfile and application files.
211+
212+
> [!TIP]
213+
>
214+
> Learn more: [checkout step documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/steps-checkout?view=azure-pipelines)
215+
216+
#### Step 4.2: Authenticate to Docker Hub
217+
218+
```yaml
219+
- task: Docker@2
220+
displayName: Docker Login
221+
inputs:
222+
command: login
223+
containerRegistry: 'my-docker-registry' # Replace with your service connection name
224+
```
225+
226+
Uses a pre-configured Azure DevOps Docker registry service connection to authenticate securely without exposing credentials directly.
227+
228+
> [!TIP]
229+
>
230+
> Learn more: [Use service connections for Docker Hub](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops#docker-hub-or-others)
231+
232+
#### Step 4.3: Build the Docker image
233+
234+
```yaml
235+
- task: Docker@2
236+
displayName: Build Docker Image
237+
inputs:
238+
command: build
239+
repository: $(imageName)
240+
tags: |
241+
$(buildTag)
242+
$(latestTag)
243+
dockerfile: './Dockerfile'
244+
arguments: |
245+
--sbom=true
246+
--attest type=provenance
247+
--cache-from $(imageName):latest
248+
env:
249+
DOCKER_BUILDKIT: 1
250+
```
251+
252+
This builds the image with:
253+
254+
- Two tags: one with the unique Build ID and one as latest
255+
- Docker BuildKit enabled for faster builds and efficient layer caching
256+
- Cache pull from the most recent pushed latest image
257+
- Software Bill of Materials (SBOM) for supply chain transparency
258+
- Provenance attestation to verify how and where the image was built
259+
260+
> [!TIP]
261+
>
262+
> Learn more:
263+
> - [Docker task for Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/docker-v2?view=azure-pipelines&tabs=yaml)
264+
> - [Docker SBOM Attestations](/manuals/build/metadata/attestations/slsa-provenance.md)
265+
266+
#### Step 4.4: Push the Docker image
267+
268+
```yaml
269+
- task: Docker@2
270+
displayName: Push Docker Image
271+
condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
272+
inputs:
273+
command: push
274+
repository: $(imageName)
275+
tags: |
276+
$(buildTag)
277+
$(latestTag)
278+
```
279+
280+
By applying this condition, the pipeline builds the Docker image on every run to ensure early detection of issues, but only pushes the image to the registry when changes are merged into the main branch—keeping your Docker Hub clean and focused
281+
282+
This uploads both tags to Docker Hub:
283+
- `$(buildTag)` ensures traceability per run.
284+
- `latest` is used for most recent image references.
285+
286+
#### Step 4.5 Logout of Docker (self-hosted agents)
287+
288+
```yaml
289+
- script: docker logout
290+
displayName: Docker Logout (Self-hosted only)
291+
condition: ne(variables['Agent.OS'], 'Windows_NT')
292+
```
293+
294+
Executes docker logout at the end of the pipeline on Linux-based self-hosted agents to proactively clean up credentials and enhance security posture.
295+
296+
## Summary
297+
298+
With this Azure Pipelines CI setup, you get:
299+
300+
- Secure Docker authentication using a built-in service connection.
301+
- Automated image building and tagging triggered by code changes.
302+
- Efficient builds leveraging Docker BuildKit cache.
303+
- Safe cleanup with logout on persistent agents.
304+
- Build images that meet modern software supply chain requirements with SBOM and attestation
305+
306+
## Learn more
307+
308+
- [Azure Pipelines Documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops): Comprehensive guide to configuring and managing CI/CD pipelines in Azure DevOps.
309+
- [Docker Task for Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/build/docker): Detailed reference for using the Docker task in Azure Pipelines to build and push images.
310+
- [Docker Buildx Bake](/manuals/build/bake/_index.md): Explore Docker's advanced build tool for complex, multi-stage, and multi-platform build setups. See also the [Mastering Buildx Bake Guide](/guides/bake/index.md) for practical examples and best practices.
311+
- [Docker Build Cloud](/guides/docker-build-cloud/_index.md): Learn about Docker's managed build service for faster, scalable, and multi-platform image builds in the cloud.

0 commit comments

Comments
 (0)