Build for Windows containers

You can use buildpacks to build container images that run Windows containers on Windows (WCOW).

This page is not relevant if your host machine is Windows but you are running Linux containers on Windows (LCOW); in this case, no special configuration is required.

EXPERIMENTAL Windows support is experimental!

Enable experimental mode by running: pack config experimental true

Before You Start

Before trying out builds for Windows images, we recommend following the Linux image tutorial under Getting Started. Don’t worry, you can still run it on a Windows OS if you need to – just make sure to enable Linux containers for Docker first.

When you’re done, head back here.

Enable Windows container mode

In order to produce Windows container images, ensure Windows container mode is enabled in your Docker settings (available only in Docker for Windows).

Then, building a Windows app using Cloud Native Buildpacks is nearly identical to building for Linux.

Not using Windows?

pack can build Windows apps using a remote Windows Docker by setting a DOCKER_HOST. Learn more


0. Determine Windows Version

Before we can start, we’ll want to match your Windows environment.

Type the following command in PowerShell:

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | Format-Table -Property ReleaseId, CurrentBuild

Select the output that best matches your environment:

Learn more about compatibility.

1. Select a builder

To build an app you must first decide which builder you’re going to use. A builder includes the buildpacks that will be used as well as the environment for building your app.

For this guide we’re going to use a sample builder, cnbs/sample-builder:dotnet-framework-1809.

2. Build your app

Now we can build our app. For this example we’ll use our samples repo for simplicity.

# clone the repo
git clone https://github.com/buildpacks/samples

# change directory to samples
cd samples

# build the app
pack build sample-app --path apps/aspnet --builder cnbs/sample-builder:dotnet-framework-1809 --trust-builder

TIP: The builder may take a few minutes to download on the first use.

TIP: If you don’t want to keep specifying a builder every time you build, you can set it as your default builder by running pack config default-builder <BUILDER>.

3. Run it

docker run --rm -it -p 8080:80 sample-app

Congratulations!

The app should now be running and accessible via localhost:8080


Using remote Docker hosts

pack and your source code don’t need to be on the same machine as your Docker daemon, thanks to support for the DOCKER_HOST environment variable.

Essentially, this points your local Docker client (e.g. docker or pack CLI) to a remote Docker daemon. For instance, if the IP address of your host is 10.0.0.1 and its daemon is listening on port 2375, you can set DOCKER_HOST to tcp://10.0.0.1:2375. Any subsequent pack or docker commands would communicate with the daemon on that machine instead of a local daemon.

This can be used to make pack build Windows container images, as long as your remote Docker host is configured to support them (i.e. the host runs a Windows OS, has Windows container mode enabled).

Here’s an example where pack on a Linux/MacOS machine can access a Windows 10 machine with Docker Desktop, using the localhost:2375 listener and the built-in OpenSSH Server.

# ssh port-forward for localhost:2375 to remote daemon
ssh -f -N -L 2375:127.0.0.1:2375 10.0.0.1

# set to your local forwarded port
export DOCKER_HOST=tcp://localhost:2375

# build the app
pack build sample-app --path samples/apps/aspnet --builder cnbs/sample-builder:dotnet-framework-1809 --trust-builder

# run it
docker run --rm -it -p 8080:80 sample-app

# access your app on your remote docker host
curl http://10.0.0.1:8080

NOTE: When setting DOCKER_HOST, keep in mind:

  • never expose an insecure Docker daemon to an untrusted network. Use SSH port forwarding or mTLS instead.
  • any volumes mounted via pack build --volume <volume> ... or docker run --volume <volume> ... must exist on the docker host, not the client machine.
  • any ports published via docker run --publish <host-port>:<container-port> ... will be published on the docker host, not the client machine.