Window Containers
This is a dive into using Windows Containers without Docker. The starting point of this was evaluating the Host Compute System (HCS) of Microsoft Windows. HCS provides a sets of APIs for controlling VMs and containers and is essentially built as a low-level API for other container tools such as Docker to be built upon.
The middle-level system is hcsshim which is tooling written in Go that uses HCS and is used in Docker (Moby) and containerd.
I quickly realised that most public code that uses the HCS is written in Go. The other realisation is rather than trying to use the low-level API straight away, it would be best making sure I could try it out with existing software first to evaluate what it can do. Enter containerd.
containerd
- containerd is a container runtime with an emphasis on simplicity, robustness, and portability.
- containerd is a graduated member of Cloud Native Computing Foundation (CNCF).
- Supports Windows which is what I was interested in.
- Relatively simple as its made up of a small number of executables.
- Uses plug-ins to provide additional functionality such as networking.
- Networking aspect uses Container Network Interface (CNI).
Downloads
curl.exe -LO https://github.com/containerd/containerd/releases/download/v1.7.14/containerd-1.7.14-windows-amd64.tar.gz
curl.exe -LO https://github.com/containerd/nerdctl/releases/download/v1.7.4/nerdctl-1.7.4-windows-amd64.tar.gz
The contents of these tarballs are as follows:
containerd-1.7.14-windows-amd64.tar.gzctr.exe- containerd CLI program (front-end) - however it is an unsupported debug and administive tool, basically for testing and development. It however provides a good way to check that the basics work.containerd.exe- The container runtime and main program that manages the containers. On Windows, this calls through to the HCS.containerd-stress.exe- A tool to stress test a containerd daemon.containerd-shim-runhcs-v1.exe- I assume this is the tool that containerd uses to talk to the Host Compute System on Windows.
nerdctl-1.7.4-windows-amd64.tar.gznerdctl.exe- a command line interface for containerd and it is the end-user ready tool. The tool aims to be compatible with Docker command line tool and feature rich.
Future downloads
curl.exe -LO https://github.com/microsoft/windows-container-networking/releases/download/v0.3.0/windows-container-networking-cni-amd64-v0.3.0.zip
curl.exe -LO https://github.com/containernetworking/plugins/releases/download/v1.4.1/cni-plugins-windows-amd64-v1.4.1.tgz
curl.exe -LO https://github.com/moby/buildkit/releases/download/v0.13.0/buildkit-v0.13.0.windows-amd64.tar.gz
Ideally a newer version of the first download can be used for networking. Thatt particular version doesn’t work as it doesn’t support the newer CNI format. While the pull request that I used to test this was stuck and not merged. I since noticed another pull request that was closed that added same thing.
The second download might work but requires more set-up to create and configure
the bridge and overlay networks. From what I could tell nerdctl doesn’t know
about them so it can’t help set it up for you.
Compiling for Network
To allow the containers to contact the Internet (ping, curl, etc), I needed to build CNI plugin that supported NAT and CNI version 1.0.0. There was no prebuilt build at the time of writing.
- To get networking work need the fixes from Paul “TBBle” Hampson for supporting CNI 1.0.0 as Microsoft’s code only supports 0.2.0 and 0.3.0.
git clone https://github.com/TBBle/windows-container-networking.gitgit checkout cni_1.0.0-supportmake nat- Copy the nat.exe to
c:\Program Files\containerd\cni\bin\
The building was done in Ubuntu within Windows Subsystem for Linux as the Makefile is set-up to cross-compile for Windows.
You may find that that the master branch from https://github.com/microsoft/windows-container-networking.git also works as a different pull request which added 1.0.0 support was merged, Christmas Day 2023.
Set-up
- Extract the containerd tarball.
- Create the default config
bin\containerd.exe config default > config.toml -
Copy
nat.exebuilt from thewindows-container-networkingtoC:\Program Files\containerd\cni\bin.The default configuration expects plugins to be in
c:\Program Files\containerd\and you could customise it if needed.
Running
Daemon
bin\containerd.exe --config config.toml
Client
bin\ctr.exe image pull mcr.microsoft.com/windows/nanoserver:10.0.19041.1415
bin\ctr.exe image pull quay.io/quay/busybox:latest
nerdctl.exe pull mcr.microsoft.com/windows/nanoserver:ltsc2019-amd64
nerdctl.exe run --rm --isolation=hyperv --net none mcr.microsoft.com/windows/nanoserver:ltsc2019-amd64
nerdctl.exe run mcr.microsoft.com/windows/nanoserver:2004-amd64 -- cmd /c echo hello
nerdctl.exe run mcr.microsoft.com/windows/nanoserver:2004-amd64 -- ping google.com
- The busybox pull failed with error about “failed to extract layer” stating the “The program issued a command but the command length is incorrect”.
- The nerdctl run with Hyper-V isolation works for nanoserver.
- Without the -amd64 on the end it fails.
- For my machine the combination of 2004-amd64 works without the isolation mode.
If you want to stick to the basics then the ctr tool is fine but if you are looking to almost daily drive using containerd then nerdctl is what you want.
Minimal Working Steps.
bin\containerd.exe config default > config.toml
bin\containerd.exe --config config.toml
nerdctl.exe run --rm --isolation=hyperv --net none mcr.microsoft.com/windows/nanoserver:ltsc2019-amd64
- As I understand it, the Hyper-V isolation should allow you to run containers that don’t match your host Windows version.
- The
--net noneoption simply means it works without networking so you don’t need to set that up.
Building images
The next thing to investigate is building container images.
The nerdctl.exe build command issues an error:
error msg=”
buildctlneeds to be installed andbuildkitdneeds to be running, see https://github.com/moby/buildkit”
My timing of going down this whole rabbit hole wasn’t too bad because about a week before I did, a new version of buildkit was released (0.13.0) and with it comes experimental Windows Containers support. This is specifically now available with a containerd worker and the Windows release artifacts also contains the buildkitd.exe binary.
- Download
curl.exe -LO https://github.com/moby/buildkit/releases/download/v0.13.0/buildkit-v0.13.0.windows-amd64.tar.gz - Extract the tarball
- The tarball contains
buildkitd.exe(the daemon/backend) andbuildctl.exewhich is the front-end / CLI tool.
- The tarball contains
- Run the daemon:
.\bin\buildkitd.exe - To check it works, try building simple hello world image from the Example
Build section of the project’s Windows documentation.
- Create Dockerfile with:
FROM mcr.microsoft.com/windows/nanoserver:ltsc2022 USER ContainerAdministrator COPY hello.txt C:/ RUN echo "Goodbye!" >> hello.txt CMD ["cmd", "/C", "type C:\\hello.txt"]As mentioned below my FROM line ended up using the tag 2004-amd64.
- Create hello.txt with:
Hello from buildkit! This message shows that your installation appears to be working correctly. - Build the image.
buildctl.exe build ` --frontend=dockerfile.v0 ` --local context=. \ ` --local dockerfile=. ` --output type=image,name=example.com/buildkit-test/hello-buildkit,push=false
- Create Dockerfile with:
Trouble-shooting
- No match for platform in manifest.
- The full message looks like this
error: failed to solve: mcr.microsoft.com/windows/nanoserver:2004: failed to resolve source metadata for mcr.microsoft.com/windows/nanoserver:2004: no match for platform in manifest: not found` failed to resolve source metadata for mcr.microsoft.com/windows/nanoserver:2004: no match for platform in manifest: not found - Fix is to modify the file so the tag is
ltsc2022-amd64. - Unconfirmed but the reason seems to be Microsoft published several multi-arch images and its confusing the tooling.
- The full message looks like this
- RUN command fails to create the container.
- The full message looks likes this:
error: failed to solve: process "cmd /S /C echo \"Goodbye!\" >> hello.txt" did not complete successfully: failed to create shim task: hcs::CreateComputeSystem tx71wvgg9bgup1xrkkllqlgpc: The container operating system does not match the host operating system.: unknown - The workaround for me was to find the image that matches my host, in my case 2002-amd64.
- Unconfirmed but again the reason seems to be same as above, however in this
case to run the nanoserver ltsc2022-amd64 image through
nerdctl.exe, I would need to do--isolation=hypervand I haven’t been unable to find the equivalent setting ot make that the default for containerd or have buildkit do the same.
- The full message looks likes this:
What’s next?
With the buildkit support being so fresh the nerdctl tool doesn’t yet
work with it. The command line help shows that the default address is the pipe
that buildkitd.exe runs on. Based on a pull request that was looking to add
Windows support it sounded like most the work is already in place but it was
simply disabled as it couldn’t be tested or used before now.
Once this is in place it will mean nerdctl should be able to build images and
with the combination of containerd, nerdctl and buildkit a usable container
environment works.
Investigate Linux Containers on Windows (LCOW) with containerd, this seems to be an unsupported and abandoned project. A few observerations are:
- There was an experimental LCOW project using LinuxKit that wrapped up in 2022.
- The containerd config contains references to windows-lcow. I’m haven’t done a deep dive but it seems the issue with using it is there is no snapshotter to support it.
- The hcsshim project still contains code for LCOW.
- One of the heighest levels seems to be
createLinuxContainerDocument. calling ontocreateLCOWSpec. - The facility to create unitiy VM for running a container in it,
uvm.CreateLCOW()is still referenced if the context os contains “linux” otherwise it usesuvm.CreateWCOW(). - The tests for lcow were removed from hcsshim in pull #1998.
- One of the heighest levels seems to be
- Moby/Docker removed their support for LCOW in Docker 23.0 in June 2023.
Other things of interest
The install-containerd-runtime.ps1 by Microsoft might be interesting to check over. This is more of an all encompassing script for setting it up as it includes enabling the Windows Features.
It is worth pointing out that Windows Containers running from containerd work at the same time as Linux Containers from Podman. This may be the result of Podman on Windows using the Windows Subsystem for Linux to run the containers rather than using the Host Compute System.
It would be nice if Podman Desktop supported containerd and could talk to podman-machine for Linux containers and containerd for Windows container.