Experimental Windows Containers Support for BuildKit Released in v0.13.0

We are excited to announce that the latest BuildKit release, v0.13.0, contains experimental Windows Containers support. BuildKit has been around for many years and has been the default build engine on Linux since Docker Engine 23.0.0. 

BuildKit is a toolkit for converting source code to build artifacts (like container images) in an efficient, expressive, and repeatable manner. BuildKit introduced the following benefits as compared with the previous Docker Builder:

  • Parallelize building independent build stages and skip any unused stages.
  • Incrementally transfer only the changed files in your build context between builds, also skip the transfer of unused files in your build context.
  • Use Dockerfile frontend implementations with many new features.
  • Avoid side effects with the rest of the API (intermediate images and containers).
  • Prioritize your build cache for automatic pruning.

Since 2018, Windows Container customers have been asking for Windows support for BuildKit, as seen in the BuildKit repo and Windows Containers repo, with hundreds of reactions and comments. We have listened to our users and focused resources in the past year to light up Windows Containers support on BuildKit.

Until now, we only shipped the Buildx client on Windows for building Linux images and some very limited Windows images using cross-compilation. Today, we are introducing experimental support for Windows Containers in BuildKit, with the aim of making this available soon in your standard Docker Build.

2400x1260 buildkit support for windows containers on windows 1

What’s next?

In the upcoming months, we will work toward further improvements, including:

  1. General Availability (GA) ready: Improving release materials, including guides and documentation.
  2. Integration with Docker Engine: So you can just run docker build.
  3. OCI worker support: On Linux, there is an option to run BuildKit with only runc using the OCI worker. Currently, only the containerd worker is supported for Windows.
  4. Container driver: Add support for running in the container driver.
  5. Image outputs: Some image outputs supported by Linux may not work on Windows and need to be tested and assessed. These include exporting an image to multiple registries, checking if keys for image output are supported, and testing multi-platform image-building support.
  6. Building other artifacts: BuildKit can be used to build other artifacts beyond container images. Work needs to be done in this area to cross-check whether other artifacts, such as binaries, libraries, and documentation, are also supported on Windows as it is on Linux.
  7. Running buildkitd doesn’t require Admin: Currently, running buildkitd on Windows requires admin privileges. We will be looking into running buildkitd on low privileges, aka “rootless”.
  8. Export cache: Investigations need to be done to confirm whether specific cache exporters (inline, registry, local, gha [GitHub Actions], 3, azblob) are also supported on Windows.
  9. Linux parity: Identifying, accessing, and closing the feature parity gap between Windows and Linux.

Walkthrough — Build a basic “Hello World” image with BuildKit and Windows Containers 

Let’s walk through the process of setting up BuildKit, including the necessary dependencies, and show how to build a basic Windows image. For feedback and issues, file a ticket at Issues · moby/buildkit (github.com) tagged with area/windows

The platform requirements are listed below. In our scenario, we will be running a nanoserver:ltsc2022 base image with AMD64. 

  • Architecture: AMD64, Arm64 (binaries available but not officially tested yet). 
  • Supported operating systems: Windows Server 2019, Windows Server 2022, Windows 11. 
  • Base images: servercore:ltsc2019, servercore:ltsc2022, nanoserver:ltsc2022. See the  compatibility map

The workflow will cover the following steps:

  1. Enable Windows Containers.
  2. Install containerd.
  3. Install BuildKit.
  4. Build a simple “Hello World” image.

1. Enable Windows Containers 

Start a PowerShell terminal in admin privilege mode. Run the following command to ensure the Containers feature is enabled:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V, Containers -All

If you see RestartNeeded as True on your setup, restart your machine and reopen an Administrator PowerShell terminal (Figure 1). Otherwise, continue to the next step.

Screenshot of windows powershell enabling windows containers.
Figure 1: Enabling Windows Containers in PowerShell.

2. Install containerd

Next, we need to install containerd, which is used as the container runtime for managing containers and images.

Note: We currently only support the containerd worker. In the future, we plan to add support for the OCI worker, which uses runc and will therefore remove this dependency

Run the following script to install the latest containerd release. If you have containerd already installed, skip the script below and run Start-Service containerd to start the containerd service. 

Note: containerd v1.7.7+ is required.

# If containerd previously installed run:
Stop-Service containerd

# Download and extract desired containerd Windows binaries
$Version="1.7.13" # update to your preferred version
curl.exe -L https://github.com/containerd/containerd/releases/download/v$Version/containerd-$Version-windows-amd64.tar.gz -o containerd-windows-amd64.tar.gz
tar.exe xvf .\containerd-windows-amd64.tar.gz

# Copy and configure
Copy-Item -Path ".\bin" -Destination "$Env:ProgramFiles\containerd" -Recurse -Container:$false -Force
cd $Env:ProgramFiles\containerd\
.\containerd.exe config default | Out-File config.toml -Encoding ascii

# Copy
Copy-Item -Path .\bin\* -Destination (New-Item -Type Directory $Env:ProgramFiles\containerd -Force) -Recurse -Force

# add the binaries (containerd.exe, ctr.exe) in $env:Path
$Path = [Environment]::GetEnvironmentVariable("PATH", "Machine") + [IO.Path]::PathSeparator + "$Env:ProgramFiles\containerd"
[Environment]::SetEnvironmentVariable( "Path", $Path, "Machine")
# reload path, so you don't have to open a new PS terminal later if needed
$Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")

# configure
containerd.exe config default | Out-File $Env:ProgramFiles\containerd\config.toml -Encoding ascii
# Review the configuration. Depending on setup you may want to adjust:
# - the sandbox_image (Kubernetes pause image)
# - cni bin_dir and conf_dir locations
Get-Content $Env:ProgramFiles\containerd\config.toml

# Register and start service
containerd.exe --register-service
Start-Service containerd

3. Install BuildKit

Note: Ensure you have updated to the latest version of Docker Desktop.

Run the following script to download and extract the latest BuildKit release.

$version = "v0.13.0" # specify the release version, v0.13+
$arch = "amd64" # arm64 binary available too
curl.exe -LO https://github.com/moby/buildkit/releases/download/$version/buildkit-$version.windows-$arch.tar.gz
# there could be another `.\bin` directory from containerd instructions
# you can move those
mv bin bin2
tar.exe xvf .\buildkit-$version.windows-$arch.tar.gz
## x bin/
## x bin/buildctl.exe
## x bin/buildkitd.exe

Next, run the following commands to add the BuildKit binaries to your Program Files directory, then add them to the PATH so they can be called directly.

# after the binaries are extracted in the bin directory
# move them to an appropriate path in your $Env:PATH directories or:
Copy-Item -Path ".\bin" -Destination "$Env:ProgramFiles\buildkit" -Recurse -Force
# add `buildkitd.exe` and `buildctl.exe` binaries in the $Env:PATH
$Path = [Environment]::GetEnvironmentVariable("PATH", "Machine") + `
    [IO.Path]::PathSeparator + "$Env:ProgramFiles\buildkit"
[Environment]::SetEnvironmentVariable( "Path", $Path, "Machine")
$Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + `
    [System.Environment]::GetEnvironmentVariable("Path","User")

Run buildkitd.exe. You should expect to see something as shown in Figure 2:

Screenshot of windows powershell running buildkit. Exe and showing successful start.
Figure 2: Successfully starting buildkitd without any errors in the logs.

Now we can set up buildx (the BuildKit client) to use our BuildKit instance. Here we will create a Builder item that points to our Buildkit instance we just started, by running:

docker buildx create --name buildkit-exp --use --driver=remote npipe:////./pipe/buildkitd

Here we are creating a new instance of a builder and pointing it to our BuildKit instance. BuildKit will listen on npipe:////./pipe/buildkitd.

Notice that we also name the builder, here, we call it buildkit-exp, but you can name it whatever you want. Just remember to add --use to set this as the current builder.

Let’s test our connection by running docker buildx inspect (Figure 3):

Screenshot of windows powershell running `docker buildx inspect` to test connection.
Figure 3: Docker buildx inspect shows that our new builder is connected.

All good!

You can also list and manage your builders. Run docker buildx ls (Figure 4).

Screenshot of windows powershell running `docker buildx ls` showing the list of builders and nodes.
Figure 4: Run docker buildx ls to return a list of all builders and nodes. Here we can see our new builder added to the list.

4. Build “Hello World” image 

We will be building a simple “hello world” image as shown in the following the Dockerfile.

FROM mcr.microsoft.com/windows/nanoserver:ltsc2022
COPY hello.txt C:
CMD ["cmd", "/C", "type C:\\hello.txt"]

Run the following commands to create a directory and change directory to sample_dockerfile.

mkdir sample_dockerfile
cd sample_dockerfile

Run the following script to add the Dockerfile shown above and hello.txt to the sample_dockerfile directory.

Set-Content Dockerfile @"
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"]
"@

Set-Content hello.txt @"
Hello from buildkit!
This message shows that your installation appears to be working correctly.
"@

Now we can use buildx to build our image and push it to the registry (see Figure 5):

docker buildx build --builder buildkit-exp --push -t <your_username>/hello-buildkit .
Screenshot of windows powershell showing successful build.
Figure 5: Here we can see our build running to a successful completion.

If you are utilizing Docker Hub as your registry, run docker login before running buildx build (Figure 6).

Screenshot of windows powershell showing successful login to docker hub.
Figure 6: Successful login to Docker Hub so we can publish our images.

Congratulations! You can now run containers with standard docker run:

docker run <HUB ACCOUNT NAME>/hello-buildkit

Get started with BuildKit

We encourage you to test out the released experimental Windows BuildKit support v0.13.0. To start out, feel free to follow the documentation or blog, which will walk you through building a simple Windows image with BuildKit. File feedback and issues at Issues · moby/buildkit (github.com) tagged with area/windows.

Learn more

Thank you

A big thanks to @gabriel-samfira, @TBBle, @tonistiigi, @AkihiroSuda, @crazy-max, @jedevc, @thaJeztah, @profnandaa, @iankingori[LX11] , and many other key community members who have contributed to enabling Windows Containers support on BuildKit. We also thank Windows Container developers who continue to provide valuable feedback and insights.