Blog Post

Containers
4 MIN READ

Getting Started - Build a Basic Hello World Image with BuildKit and Windows Containers

lucillexiong's avatar
lucillexiong
Icon for Microsoft rankMicrosoft
Mar 25, 2024

We’ve recently announced the release of experimental Windows Containers support in BuildKit v0.13.0. Developers can now benefit from improved performance and caching by building Windows Container images with BuildKit instead of docker build. This guide will follow the documentation where we will discuss the necessary prerequisites, setting up BuildKit, and how to build a basic Windows image with BuildKit. For feedback and issues, please file a ticket here 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
  • Supported OS: Windows Server 2019, Windows Server 2022, Windows 11.
  • Base images: servercore:ltsc2019servercore:ltsc2022nanoserver:ltsc2022. See the compatibility map here.

 

Setup

 

1. Start up a PowerShell terminal in admin privilege mode. Run the following command to ensure the Containers feature is enabled. If you see RestartNeeded as True on your setup, restart your machine and reopen an Administrator PowerShell terminal. Otherwise, continue to the next step.

 

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

 

 

2. 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.14" # 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. 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

 

4. Next, run the following commands to setup the BuildKit binaries.

 

# 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")

 

5. Run buildkit.exe. You should expect to see something as follows:

 

 

6. To test if your setup is good, open another admin PowerShell terminal and run a buildctl command such as the one below

 

buildctl debug info

 

 

Build Hello World Image

 

We will be building a simple hello world image as shown by the Dockerfile below.

 

 

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

 

mkdir sample_dockerfile
cd sample_dockerfile

 

2. Run the script below 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.
"@@

 

3. If you are utilizing Docker Hub as your registry, make sure to run docker login before running buildctl build.

 

 

4. Run buildctl build to build and push your image to your registry.

 

buildctl build `
--frontend=dockerfile.v0 `
--local context=. \ `
--local dockerfile=. `
--output type=image,name=docker.io/<your_username>/hello-buildkit,push=true

 

You should see an output like the one below after building and pushing your container image.

 

 

Congratulations! You can now create containers with the client (docker run, ctr run, nerdctl run) of your choice.

 

 

For more guides, please keep an eye out for additional documentation in the coming months.

Updated Mar 25, 2024
Version 2.0

7 Comments

  • realflash's avatar
    realflash
    Copper Contributor

    The versions used in this documentation don't work any more; containerd 1.7.7 or later is required. See https://github.com/moby/buildkit/blob/master/docs/windows.md If you use the versions specified above, you will get 

    Solve failed to create scratch layer: no parent layers present: unknown

    I used the following latest versions at the time of comment instead, and succeeded with them:
    - containerd 1.7.18

    - nerdctl 1.7.6

     

  • pl4nty's avatar
    pl4nty
    Copper Contributor

    nandaa thanks, I've been testing v0.13.2 for a few days and it's working really well. I've https://github.com/moby/buildkit/issues/4892 for the frontend bug.

  • pl4nty -- and thanks for testing this out! On your previous comment, now the bug on COPY for nested folders has been fixed and released in v0.13.2, last Thursday. Give it a try and let me know.

  • pl4nty's avatar
    pl4nty
    Copper Contributor

    MatthewTeeterCg the first-party frontends like #syntax=docker/dockerfile:master don't have Windows images, so I built one at ghcr.io/pl4nty/dockerfile:master. But it doesn't seem to be supported - my builds fail with

     

    ERROR: failed to solve: hcsshim::ProcessBaseLayer \\?\C:\ProgramData\containerd\root\io.containerd.snapshotter.v1.windows\snapshots\5: The system cannot find the path specified.: unknown

     

  • MatthewTeeterCg's avatar
    MatthewTeeterCg
    Copper Contributor

    Can #syntax=some-image be used when building for Windows containers with BuildKit?

  • pl4nty's avatar
    pl4nty
    Copper Contributor

    Is there a timeline on adding BuildKit to GitHub's hosted Windows runners? https://github.com/actions/runner-images/issues/9478

    I've https://github.com/pl4nty/containers/blob/f25808ad3179f7a3fa1772f056d0aac316da639a/.github/workflows/release.yaml#L121-L146 in the meantime. There's also a https://github.com/moby/buildkit/issues/4741, which might be worth mentioning in the announcement - it breaks a lot of Dockerfiles, including most of mine eg https://github.com/microsoft/garnet