Skip to content

Instantly share code, notes, and snippets.

@nongvantinh
Last active May 20, 2025 08:31
Show Gist options
  • Save nongvantinh/97b557df9a25be0dd6e17e124dd8fea8 to your computer and use it in GitHub Desktop.
Save nongvantinh/97b557df9a25be0dd6e17e124dd8fea8 to your computer and use it in GitHub Desktop.
Building a Windows Docker image on Windows OS

Building Windows Docker Images on Windows

This guide provides instructions on setting up and installing a Windows Server 2022 Virtual Machine on Ubuntu 22.04 to build Docker images for Windows.

Preface

Instead of building Windows Docker images on a physical machine, we set up a virtual machine to avoid OS version and kernel mismatches. Initially, I attempted to build a Windows Docker image on my Windows 10 laptop, but encountered errors during the base image pull stage.

Upon investigation, I discovered that my laptop was running Windows 10.0.26100, a Windows Insider Preview build. The error message:

hcsshim::ImportLayer failed in Win32: The system cannot find the path specified. (0x3)

indicated an incompatibility between the Windows version and the container OS version. To resolve this, I opted to use a virtual machine instead.


1. Installing Windows VM on Ubuntu 22.04 Using QEMU

System Requirements

I used a Dell laptop with the following specifications:

  • CPU: Intel(R) Core(TM) Ultra 7 165H
  • Architecture: 64-bit
  • Cores/Threads: 16 cores, 22 threads

Downloading Windows ISO

First, download the Windows Server 2022 ISO from a reliable source. I downloaded it here, but I'm not sure if it's a trusted source; however, the ISO works: https://thuegpu.vn/link-download-windows-server/. Then, create a qcow2 file for the virtual machine.

First, install the QEMU program on Ubuntu:

sudo apt update
sudo apt install qemu qemu-kvm qemu-system qemu-utils virt-manager libvirt-bin libvirt-daemon-system libvirt-clients bridge-utils

Then, navigate to the project folder where you preferred to store the files related to the project and create a backing store for the virtual machine. The command below creates a new 100 GB disk image file called windows_vm.qcow2 using the qcow2 format. It will be used as the virtual hard disk for a virtual machine, and the file will grow in size dynamically as data is added to it, up to a maximum of 100 GB. However, later I discovered that 100GB was not enough to build the Windows Docker with the redundant packages I installed in Visual Studio, including C++ and C#. Therefore, I need to resize the partition later.

cd /home/$USER/Projects/qemu/
qemu-img create -f qcow2 windows_vm.qcow2 100G

Now, boot into the Windows installer. Since my Ubuntu device has 32GB of RAM and 16 cores, I allocate half of the RAM and 10 cores for this virtual machine.

qemu-system-x86_64 \
    -m 16G \
    -smp 10 \
    -drive file=windows_vm.qcow2,format=qcow2 \
    -cdrom /home/$USER/Projects/qemu/Windows_Server_2022.iso \
    -boot d \
    -net nic -net user \
    -enable-kvm \
    -vga std

During installation, choose Windows Server 2022 Standard Evaluation (Desktop Experience). Be sure to manually allocate the partition that will be used to install the OS to prevent issues when resizing the disk later because the unallocated space it's not directly adjacent to the C: partition in Disk Management.

After the installation is complete, shut down the Virtual Machine to boot with another option that persists the state.

Resizing the Disk

Since 100GB was insufficient, I later increased the size to 500GB:

qemu-img resize windows_vm.qcow2 500G

To verify the new size:

qemu-img info windows_vm.qcow2

After booting into Windows, extend the partition:

  1. Open Disk Management (diskmgmt.msc).
  2. Locate unallocated space.
  3. Right-click on the C: partition and select Extend Volume.
  4. Follow the wizard to complete the expansion.

2. Setting Up Necessary Tools

To enable clipboard sharing and better display support, install SPICE on Ubuntu:

sudo apt install spice-vdagent virt-viewer spice-client-vdagent

Start QEMU with SPICE support:

qemu-system-x86_64 \
    -m 16G \
    -smp 10 \
    -drive file=windows_vm.qcow2,format=qcow2 \
    -boot c \
    -net nic -net user \
    -enable-kvm \
    -vga qxl \
    -device virtio-mouse-pci \
    -spice port=5900,addr=127.0.0.1,disable-ticketing=on \
    -device qxl \
    -device virtio-serial \
    -chardev spicevmc,id=vdagent,name=vdagent \
    -device virtserialport,chardev=vdagent,name=com.redhat.spice.0

To connect to the VM:

remote-viewer spice://127.0.0.1:5900

Install SPICE Guest Tools on Window Virtual Machine

Download and install Windows SPICE Guest Tools from:

https://www.spice-space.org/download.html

Restart the VM after installation.


3. Enabling Hyper-V and Installing Docker

Open PowerShell as Administrator and enable Hyper-V:

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

Restart Windows and follow the official Docker instructions:

Docker Installation Guide

Summary of Docker Installation Steps

Download Docker binaries:

Expand-Archive C:\Users\Administrator\Downloads\docker-28.0.2.zip -DestinationPath $Env:ProgramFiles
&$Env:ProgramFiles\docker\dockerd --register-service
Start-Service docker
&$Env:ProgramFiles\docker\docker run hello-world:nanoserver
icacls "C:\ProgramData\docker" /grant Everyone:F /T

After the step above, you should have C:\Program Files\docker. If so, add this path to the system PATH environment variable:

[System.Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\Program Files\docker', [System.EnvironmentVariableTarget]::Machine)

4. Test the new windows docker:

Make sure all the step above produce a windows environment:

docker info | Select-String "OSType"

it should print out "windows".

5. Building and Publishing Docker Images

Log in to the registry:

docker login your-registry.com

Build the image:

cd C:\Users\YourUser\Projects\your-docker-project
docker build -t windows-container .

Tag and push the image:

docker tag windows-container:latest your-registry.com/your-image:tag
docker push your-registry.com/your-image:tag

This completes the setup for building Windows Docker images in a VM on Ubuntu.


Install Linux docker and Windows docker at the same time

These are the documented steps I collected while debugging the reason why my Windows 10 laptop cannot build Windows Docker images. I think this is valuable knowledge that I might need in the future. But why would anyone want to set up both Linux and Windows Docker side by side on a Windows machine? That would cause unnecessary conflicts. Why not just set up another Ubuntu virtual machine to make your life easier?

Cleanup Previous Installations

If needed, remove previous Docker installations:

Stop-Service docker -Force
Stop-Service docker-win -Force
taskkill /F /IM dockerd.exe
sc.exe delete docker
Remove-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\docker" -Force
Remove-Item -Path "C:\ProgramData\docker\volumes" -Force

Install and Configure New Docker Versions

Install WSL on Windows to support Linux:

wsl --install

Register Linux Docker

docker context use default
&$Env:ProgramFiles\docker\dockerd --register-service

Register Windows Docker

dockerd.exe -H npipe:////./pipe/docker_windows --service-name docker-win --register-service
docker context create win --docker host=npipe:////./pipe/docker_windows

Start Docker Services

Start-Service docker
Start-Service docker-win

Check the active container type:

docker info | Select-String "OSType"
docker -c win info | Select-String "OSType"

# escape=`
# https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/manage-windows-dockerfile#escape-character
# https://hub.docker.com/r/microsoft/dotnet-framework-sdk
ARG FROM_IMAGE=mcr.microsoft.com/dotnet/framework/sdk:3.5-20241008-windowsservercore-ltsc2022
FROM ${FROM_IMAGE}
SHELL ["cmd", "/S", "/C"]
ADD https://aka.ms/vscollect.exe C:\collect.exe
ADD https://nodejs.org/dist/v16.15.1/node-v16.15.1-x64.msi C:\node-v16.15.1-x64.msi
RUN start /wait msiexec.exe /i C:\node-v16.15.1-x64.msi /l*vx "%TEMP%\MSI-node-install.log" /qn ADDLOCAL=ALL
ADD https://awscli.amazonaws.com/AWSCLIV2.msi C:\AWSCLIV2.msi
RUN msiexec.exe /i C:\AWSCLIV2.msi /quiet /norestart
ADD https://www.python.org/ftp/python/3.10.6/python-3.10.6-amd64.exe C:\python-3.10.6-amd64.exe
RUN start /wait C:\python-3.10.6-amd64.exe /quiet InstallAllUsers=1 PrependPath=1
ADD https://slproweb.com/download/Win64OpenSSL_Light-3_5_0.msi C:\Win64OpenSSL_Light-3_5_0.msi
RUN start /wait msiexec.exe /i C:\Win64OpenSSL_Light-3_5_0.msi /quiet /norestart
RUN powershell -Command "[System.Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\Program Files\OpenSSL-Win64\bin', [System.EnvironmentVariableTarget]::Machine)"
# Download and install Build Tools for Visual Studio 2022.
# https://github.com/microsoft/vs-dockerfiles
ARG CHANNEL_URL=https://aka.ms/vs/17/release/channel
ADD ${CHANNEL_URL} C:\VisualStudio.chman
ADD https://aka.ms/vs/17/release/vs_buildtools.exe C:\vs_buildtools.exe
RUN C:\vs_buildtools.exe --quiet --wait --norestart --nocache `
--channelUri C:\VisualStudio.chman `
--installChannelUri C:\VisualStudio.chman `
--add Microsoft.Component.MSBuild `
--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
--add Microsoft.VisualStudio.Component.Windows11SDK.22621 `
--add Microsoft.VisualStudio.Component.VC.ATL `
--add Microsoft.VisualStudio.Component.VC.ATLMFC `
--add Microsoft.VisualStudio.Component.VC.Redist.14.Latest `
--add Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core `
--add Microsoft.VisualStudio.Workload.NativeDesktop `
--installPath C:\BuildTools `
&& exit /b 0 `
|| if "%ERRORLEVEL%"=="3010" (exit /b 0) else (C:\collect.exe -zip:C:\vslogs.zip && exit /b %ERRORLEVEL%)
RUN del C:\collect.exe `
&& del C:\node-v16.15.1-x64.msi `
&& del C:\AWSCLIV2.msi `
&& del C:\python-3.10.6-amd64.exe `
&& del C:\Win64OpenSSL_Light-3_5_0.msi `
&& del C:\VisualStudio.chman `
&& del C:\vs_buildtools.exe
CMD ["powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment