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 https://github.com/StefanScherer/whoami

My base image is https://hub.docker.com/r/microsoft/dotnet/ 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
WORKDIR /code
RUN dotnet build -c Release -o output
FROM microsoft/dotnet:${runtimeimagetag}
COPY –from=build /code/output .
EXPOSE 80
ENTRYPOINT ["dotnet","code.dll"]
ENV ASPNETCORE_URLS http://*:80

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 : 40.114.111.125
DnsNameLabel : whoamiwin
Fqdn : whoamiwin.eastus.azurecontainer.io
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}
Sleeping
Sleeping
Sleeping
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
a.ps1
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

ApplicationFrameHost_2018-06-09_09-25-26

CI/CD pipeline in VSTS

Build and Release pipeline are exported as JSON files and available in Github repo. File names are

https://github.com/artisticcheese/artisticcheesecontainer/blob/master/whoami/WhoamI-ASP.NET%20Core-CI.json is build definition and https://github.com/artisticcheese/artisticcheesecontainer/blob/master/whoami/Whoami-Release.json 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
ApplicationFrameHost_2018-06-09_09-37-56

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

ApplicationFrameHost_2018-06-09_09-39-20

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

ApplicationFrameHost_2018-06-09_09-41-37

Example of manifest file is below

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

view raw
manifest.yml
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

ApplicationFrameHost_2018-06-09_09-48-10