Creating a Multiplatform Powershell Core App Container
Having consistent tools makes debugging issues across Linux and Windows easier. PowerShell Core is that tool for the job, in my opinion. It can run on both Windows and Linux, which makes it a good candidate for building debugging tools, and keeping it all one thing reduces the cognitive overload.
The PowerShell team produces Core images for Windows and Linux. There are only two tags that exist are multiplatform, which are LTS and Latest tags. Unfortunately, they use Server Core instead of Nano Server for the base, at least on Windows. I want the smallest possible images, which means using Nano Server requires a touch more setup on my side.
Now that I need to do the extra work to make changes for the Windows side, I will also change the Linux side to leverage Alpine.
Basic Dockerfile
Here is our basic Dockerfile using the LTS tag.
FROM mcr.microsoft.com/powershell:lts
CMD ["pwsh", "-Command", "Get-Uptime"]
The first step is to add an ARG to our Dockerfile called BASE
. Then we will change our tag from latest to using our build arg.
ARG BASE
FROM mcr.microsoft.com/powershell:${BASE}
CMD ["pwsh", "-Command", "Get-Uptime"]
Tagging
The last step is to leverage a tagging standard and create our manifest for multiplatform support.
I suggest the following tagging standard for Linux:
<app version>-<os>-<architrctiture>
Linux example:
v1.0-linux-amd64
The Windows standard needs to add the OS version.
<app version>-<os>-<os version>-<architecture>
Windows 2022 example:
v1.0-windows-ltsc2022-amd64
Building
When we run our build, we will pass a build arg to it specifying which base image we would like to use based on OS and our tag using our naming standard above.
# Linux
docker build --build-arg BASE=alpine-3.14 \
-t phillipsj/myapp:v0.0.1-linux-amd64 .
docker push phillipsj/myapp:v0.0.1-linux-amd64
# Windows 2019
docker build --build-arg BASE=nanoserver-1809 \
-t phillipsj/myapp:v0.0.1-windows-ltsc2019-amd64 .
docker push phillipsj/myapp:v0.0.1-windows-ltsc2019-amd64
# Windows 2022
docker build --build-arg BASE=nanoserver-ltsc2022 \
-t phillipsj/myapp:v0.0.1-windows-ltsc2022-amd64 .
docker push phillipsj/myapp:v0.0.1-windows-ltsc2022-amd64
Bringing it all together with the Manifest
Then we can create our manifest, which we will push tag as just version, and we will amend the images we built above. Let’s make our manifest now.
docker manifest create phillipsj/myapp:v0.0.1 \
--amend phillipsj/myapp:v0.0.1-linux-amd64 \
--amend phillipsj/myapp:v0.0.1-windows-ltsc2019-amd64 \
--amend phillipsj/myapp:v0.0.1-windows-ltsc2022-amd64
Next, we need to annotate our different versions to our manifest.
export DOCKER_CLI_EXPERIMENTAL=enabled
docker manifest annotate --os windows --arch amd64 \
--os-version "10.0.17763.1817" \
phillipsj/myapp:v0.0.1 phillipsj/myapp:v0.0.1-windows-ltsc2019-amd64
docker manifest annotate --os windows --arch amd64 \
--os-version "10.0.20348.169"\
phillipsj/myapp:v0.0.1 phillipsj/myapp:v0.0.1-windows-ltsc2022-amd64
The last thing we need to do is push our manifest to our registry.
docker manifest push phillipsj/myapp:v0.0.1
Now we have a PowerShell Core App with multiplatform support leveraging the smallest official bases provided by upstream. We can use the following manifest without worrying about specifying our platform image.
# On any supported platform in the manifest
docker pull phillipsj/myapp:v0.0.1
docker run --rm phillipsj/myapp:v0.0.1
Wrapping Up
Now we can deploy the same app or tools using the same technology to both Windows and Linux Kubernetes nodes to make debugging less difficult.
Thanks for reading,
Jamie
If you enjoy the content, then consider buying me a coffee.