Using VSTS for complete CI/CD pipeline for multi-arch docker images

I needed to have multi-arch docker images to return all environment variables to screen as well as in response headers (so they be used in Fiddler or similar tools to extract data). Idea and implementation is inspired by Stefan Sherer’s whoami image avaialable here

My base image is which is multi-arch itself and hence allows me to have single DOCKERFILE for both UNIX and Windows builds. Entire code and additional artifacts are available at following Github repo in whoami folder.

DOCKERFILE is below which is the same file used for both Windows and UNIX builds.

ARG buildimagetag="2.1-sdk"
ARG runtimeimagetag="2.1-aspnetcore-runtime"
FROM microsoft/dotnet:${buildimagetag} AS build
COPY /code /code
RUN dotnet build -c Release -o output
FROM microsoft/dotnet:${runtimeimagetag}
COPY –from=build /code/output .
ENTRYPOINT ["dotnet","code.dll"]

Building this DOCKERFILE on Windows – will pull current nanoserver based image and on UNIX – current UNIX based image with no code changes necessary to DOCKERFILE itself or build process.

You can see how image works by instantiating Windows and UNIX containers in Azure Container Instance (cloud shell will work fine) and examining headers.

PS Azure:\> New-AzureRmResourceGroup Name CI Location EastUS
ResourceGroupName : CI
Location : eastus
ProvisioningState : Succeeded
Tags :
ResourceId : /subscriptions/b55607abc7034044a52672bd701b0d48/resourceGroups/CI
PS Azure:\> New-AzureRmContainerGroup ResourceGroupName CI Name whoamiwin Image artisticcheese/whoami OsType Windows DnsNameLabel whoamiwin
ResourceGroupName : CI
Id : /subscriptions/b55607abc7034044a52672bd701b0d48/resourceGroups/CI/providers/Microsoft.ContainerInstance/containerGroups/whoamiwin
Name : whoamiwin
Type : Microsoft.ContainerInstance/containerGroups
Location : eastus
Tags :
ProvisioningState : Pending
Containers : {whoamiwin}
ImageRegistryCredentials :
RestartPolicy : Always
IpAddress :
DnsNameLabel : whoamiwin
Fqdn :
Ports : {80}
OsType : Windows
Volumes :
State : Pending
Events :
PS Azure:\> while ((Get-AzureRMContainerGroup ResourceGroupName CI Name whoamiwin OutVariable state).State -ne "Running") {Write-Output "Current state $($state.State), Sleeping"; Start-Sleep 10}
PS Azure:\> $fqdn = (Get-AzureRmContainerGroup ResourceGroupName CI Name whoamiwin).Fqdn
PS Azure:\> curl I s $fqdn | select-string ^Path:
Path: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Users\ContainerAdministrator\AppData\Local\Microsoft\WindowsApps;C:\Program Files\dotnet;
PS Azure:\> New-AzureRmContainerGroup ResourceGroupName CI Name whoamiunix Image artisticcheese/whoami OsType Linux DnsNameLabel whoamiunix
PS Azure:\> while ((Get-AzureRMContainerGroup ResourceGroupName CI Name whoamiunix OutVariable state).State -ne "Running") {Write-Output "Current state $($state.State), Sleeping"; Start-Sleep 10}
PS Azure:\> $fqdn = (Get-AzureRmContainerGroup ResourceGroupName CI Name whoamiunix).Fqdn
PS Azure:\> curl I s $fqdn | select-string ^Path:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

view raw
hosted with ❤ by GitHub

Image in addition to response HTTP headers output information to HTML as well which might be useful for troubleshooting/demo purposes


CI/CD pipeline in VSTS

Build and Release pipeline are exported as JSON files and available in Github repo. File names are is build definition and is release defintion

Build consists of following steps:

  1. Download source code and artifacts from GitHub
  2. Run steps on hosted UNIX agent (provided for free by VSTS)
    • Build from DOCKERFILE
    • Push to Docker Hub
  3. Run steps on hosted Windows agent (provided for free by VSTS)
    • Build from DOCKERFILE
    • Push to Docker Hub
    • Rebase images for 1709 and 1803 images (work in progress currently)
  4. Run RegEx task to replace static data in manifest file which will be used to create multi-arch image with current BuildVersion
  5. Publish manifest as artifact for release pipeline
 This is how it looks like in UI

You can also enable real CI (instead of manually invoking build) in Options by checking “Enable Continuous Integration”


Result of successful build is YAML manifest file identifying image tags for UNIX/Windows images in docker hub


Example of manifest file is below

image: artisticcheese/whoami:latest
image: artisticcheese/whoami:unix-2018060858
architecture: amd64
os: linux
image: artisticcheese/whoami:nanolts-2018060858
architecture: amd64
os: windows

view raw
hosted with ❤ by GitHub

Release (CD) pipeline consists of following steps

  1. Install manifest tool from chocolatey on agent (courtesy of Stefan again)
  2. Download build artifact (manifest file) which contains information about current image tags
  3. Running tool from step 1 to update docker hub with latest image

CD is automatically triggered by successful build



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s