Đây là bài mình vừa học vừa ghi lại trong quá trình thực hành DevOps — từ việc cài Docker Desktop, tạo Dockerfile cho ứng dụng C#, đến việc tự động build và push image lên Docker Hub bằng Azure Pipelines.
Mục tiêu là tự hiểu – tự làm – tự note, để khi quay lại sau này có thể triển khai lại toàn bộ mà không cần tìm lại tài liệu.
Giới thiệu
Trong DevOps, Docker Image là “bản đóng gói” (package) toàn bộ ứng dụng, môi trường và dependency.
Khi bạn build một image, bạn đang tạo ra một “snapshot” mà có thể chạy ở bất kỳ môi trường nào — từ máy local đến cloud.
Quy trình chuẩn để đưa image lên cloud registry gồm 3 bước:
- Build image – dùng Dockerfile.
- Tag image – đặt tên định danh (vd: username/app:latest).
- Push image – đẩy lên Docker Hub (hoặc ACR, ECR...).
Với Azure Pipelines, ta có thể tự động hoá toàn bộ quy trình đó bằng một YAML pipeline.
Chuẩn bị
- Self-hosted agent: Xem lại Day 2
- Docker Desktop for Windows
Kiểm tra lại Docker:
docker version
docker info
Nếu có thông tin client/server thì Docker CLI đã sẵn sàng.
Tạo Dockerfile
Đặt Dockerfile ở thư mục gốc của Project# Stage 1: Build .NET app
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY HelloWorldApp/*.csproj HelloWorldApp/
RUN dotnet restore HelloWorldApp/HelloWorldApp.csproj
COPY . .
RUN dotnet publish HelloWorldApp/HelloWorldApp.csproj -c Release -o /app/publish
# Stage 2: Runtime
FROM mcr.microsoft.com/dotnet/runtime:9.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "HelloWorldApp.dll"]
Build và push Docker image
Trong Azure DevOps:
- Vào Project Settings → Service Connections → New service connection
- Chọn Docker Registry
- Điền:
- Registry type: Docker Hub
- Registry URL: https://index.docker.io/v1/
- Username: tài khoản Docker Hub
- Password/Token: Docker Hub Access Token (an toàn hơn password)
- Đặt tên: dockerhub-conn
Viết Pipeline YAML
Tạo file azure-pipelines-docker.yml trong repo
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger: none
pool:
name: Default
demands:
- Agent.Name -equals MySelfHostedAgent-ABT
- docker
variables:
imageName: 'yourdockerhubuser/helloworld'
steps:
- checkout: self
- task: PowerShell@2
displayName: 'Check Docker environment'
inputs:
targetType: inline
script: |
docker version
docker info
- task: Docker@2
displayName: 'Build and Push image to Docker Hub'
inputs:
containerRegistry: 'dockerhub-conn' # service connection to Docker Hub
repository: '$(imageName)'
command: 'buildAndPush'
Dockerfile: '**/Dockerfile'
tags: |
$(Build.SourceVersion)
latestLưu ý:
- Docker@2 nghĩa là dùng Docker task, version 2, do Microsoft cung cấp sẵn, tương đương việc chạy các lệnh Docker CLI (docker build, docker push) nhưng được đóng gói lại, dễ quản lý và tái sử dụng.
- containerRegistry: 'dockerhub-conn'
Đây là Service Connection bạn đã tạo trong Azure DevOps (mục Project Settings → Service connections).
dockerhub-conn chứa thông tin đăng nhập Docker Hub (username + access token).
Khi chạy pipeline, Azure DevOps tự docker login vào Docker Hub bằng connection này. - repository: '$(imageName)': repository là tên repo trên Docker Hub nơi image sẽ được push lên.
- Dấu $() gọi là Azure Pipeline variable syntax.
- command: 'buildAndPush': Là chế độ hoạt động của Docker task.
buildAndPush =
docker build -t <imageName>:<tag> .
docker push <imageName>:<tag>- Dockerfile: '**/Dockerfile': chỉ đường dẫn đến Dockerfile để task biết nơi build. **/Dockerfile là pattern tìm kiếm đệ quy (glob pattern), tìm trong tất cả thư mục con.
- tags: |
Đây là danh sách tag gắn cho image khi build/push lên Docker Hub. Dấu | cho phép viết nhiều dòng - $(Build.SourceVersion): biến hệ thống mặc định của Azure Pipelines, chứa mã commit SHA đầy đủ (40 ký tự) của lần chạy pipeline đó
Ví dụ nếu bạn vừa commit lên branch main:
commit 9f1e27ac4d87b63c8d2f1b8d0e8212cf3e39aabc
trong pipeline:
$(Build.SourceVersion) = 9f1e27ac4d87b63c8d2f1b8d0e8212cf3e39aabc
Khi build image, tag của bạn sẽ là:
yourdockerhubuser/helloworld:9f1e27ac4d87b63c8d2f1b8d0e8212cf3e39aabc
giúp truy vết chính xác image đó build từ commit nào.
Bạn cũng có thể rút gọn tag bằng:
tags: |
$(Build.SourceVersion:0:7)
latest→ chỉ lấy 7 ký tự đầu của SHA (ví dụ: 9f1e27a).
Kết quả Pipline
* branch 9a4bb752fa16b15c936a5585019815925edd73aa -> FETCH_HEAD
git checkout --progress --force refs/remotes/origin/9a4bb752fa16b15c936a5585019815925edd73aa
Note: switching to 'refs/remotes/origin/9a4bb752fa16b15c936a5585019815925edd73aa'.
...
REPOSITORY TAG IMAGE ID CREATED SIZE
***/helloworld 9a4bb752fa16b15c936a5585019815925edd73aa 67592544cf34 Less than a second ago 293MB
***/helloworld latest 67592544cf34 Less than a second ago 293MB
Hiểu về Task trong Azure Pipeline
Một Task là đơn vị công việc (step) trong pipeline — mỗi task có nhiệm vụ riêng biệt.Cấu trúc
- task: <task-name>@<version>
displayName: <description>
inputs:
<tham_số>: <value>
Task: PowerShell@2
PowerShell@2 là task dùng để chạy câu lệnh hoặc script PowerShell trên agent. Phù hợp cho các bước kiểm tra môi trường, thao tác file, gọi công cụ CLI, hoặc thực hiện các logic tùy biến trong pipeline.
Task: Docker@2
Docker@2 là task chuyên dụng cho các thao tác Docker như login, build, tag, push, và buildAndPush. Kết hợp với Service Connection để xác thực an toàn với Docker Hub (hoặc registry khác).
Một số task khác hay dùng
- Checkout — Lấy source code từ repository vào agent workspace để các bước sau sử dụng.
- DotNetCoreCLI@2 — Thực thi các lệnh .NET (restore, build, test, publish) dành cho ứng dụng .NET Core/.NET.
- Bash@3 — Chạy shell script trên agent Linux/macOS; hữu ích khi cần môi trường POSIX hoặc lệnh đặc thù Unix.
- CmdLine@2 — Chạy lệnh dòng lệnh thuần (cmd) trên Windows agent; thích hợp cho các công cụ không cần Power
Xóa Docker Image để giải phóng dung lượng
Sau một thời gian sử dụng, bạn có thể có hàng chục image cũ không còn dùng đến — đặc biệt khi thường xuyên build hoặc pull từ registry.
Những image này chiếm rất nhiều dung lượng, đôi khi lên đến vài GB.
Dưới đây là các cách dọn dẹp image hiệu quả
docker system df -v
-v nghĩa là hiển thị chi tiết từng phần tử

Nhận xét
Đăng nhận xét