Hello everyone,
I would like to share a tutorial with you which I wrote for the german linux forum https://forum.linuxguides.de/.
I hope the translation is reasonably readable.
Big thanks to deepl
Theory
Motivation
We use the Docker repository from this GitHub page for our project: https://github.com/dockur/windows
And that’s exactly where all the credits are and my thanks go to this great project.
Personally, the documentation was too poor for me and I had a lot of try & error moments.
Now I’ve got the hang of it and would like to share my newly acquired knowledge and experience with you.
Hopefully you will find it easier to get started than I did
Requirements
- Any Linux as host system
- CPU with KVM support
- Installed Docker and Docker Compose
- Internet connection
- Web browser (tested Firefox and Brave)
- Terminal
- Optional: RDP client
- Optional: Hard disk or partition with NTFS or FATx
- Approx. 15-20 minutes + download and installation time
Check KVM support
lscpu | grep Virt
The output should either be Virtualization: VT-x for Intel CPUs or Virtualization: AMD-SVM.
If this is not the case, check whether you have activated the function in the BIOS.
What this tutorial shows you
This tutorial explains step by step how to install an “arbitrary” Windows version in a Docker container.
Once as a so-called unattended installation, i.e. completely automatic, and once as a normal, manual installation.
We will also
- Integrate several virtual hard disks
- Implement USB stick forwarding
- Share files with the host
- Pass-through of an NTFS or FAT partition
What this tutorial will not show you
You will not learn how to install Docker and the required components, nor what Docker is and how to use it.
Basic concept
It is as simple as it is ingenious: With the help of a single configuration file (YAML format), we define our Docker container.
Structure of a .YML file
The following is the simplest variant for a configuration file.
services:
windows:
image: dockurr/windows
container_name: windows
devices:
- /dev/kvm
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
stop_grace_period: 2m
restart: on-failure
environment:
VERSION: "win11"
RAM_SIZE: "4G"
CPU_CORES: "4"
DISK_SIZE: "64G"
volumes:
- /var/win:/storage
The “image” parameter tells Docker which image it is and where it is located for the download.
“container_name” is simply the name we want to give our new container and is purely cosmetic.
Ports
In the Ports section, the ports for VNC (8006) and RDP (3389) are specified and ready to use.
Enviroment
The parameters and Enviroment and Volumes are the most interesting for us.
Under Enviroment we specify the Windows version to be installed (see table in the appendix).
The rest should be self-explanatory:
RAM_SIZE determines how much memory we want to give the container from our physical RAM.
The same applies to CPU_CORES, i.e. how many cores of its own CPU the container can use.
With DISK_SIZE we specify how large the virtual hard disk should be.
Volumes
/var/win:/storage
/var/win is simply the path where we want to save our virtual hard disk. The path can be customized as desired.
The storage parameter simply says that it is a storage device.
Practice Part 1 - (Automatic) Installation
Enough theory for now, let’s start our first Linux > Docker > Windows container!
Step 1
- create a directory where the container should be stored (e.g. /home/docker)
- create a file with the name docker-compose.yml in the same directory
- copy the following code (version 1 or version 2) into the file and customize it according to your wishes.
Version 1
services:
windows:
image: dockurr/windows
container_name: windows
devices:
- /dev/kvm
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
stop_grace_period: 2m
restart: on-failure
environment:
VERSION: "win11"
RAM_SIZE: "4G"
CPU_CORES: "4"
DISK_SIZE: "64G"
volumes:
- /var/win:/storage
Version 2
Version 2 extends version 1 with some settings for the automatic installation.
I have added the following values under Enviroment:
LANGUAGE: "German"
REGION: "de-DE"
KEYBOARD: "de-DE"
USERNAME: "tux"
PASSWORD: "tux"
I think the values are self-explanatory but are explained in more detail in the appendix.
services:
windows:
image: dockurr/windows
container_name: windows
devices:
- /dev/kvm
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
stop_grace_period: 2m
restart: on-failure
environment:
VERSION: "win11"
RAM_SIZE: "4G"
CPU_CORES: "4"
DISK_SIZE: "64G"
LANGUAGE: "German"
REGION: "de-DE"
KEYBOARD: "de-DE"
USERNAME: "tux"
PASSWORD: "tux"
volumes:
- /var/win:/storage
Step 2
- start terminal and change to the created directory
- start container with
docker compose up
# or with output
docker compose up -d
The new container can be accessed directly via VNC using the URL http://localhost:8006/.
Now wait until the ISO has been downloaded and the automatic installation has been completed.
Step 3
Once the container is ready or the installation is complete, the “fresh” Windows can be used.
Alternatively, you can also use an RDP connection via localhost:3389. My recommendation is clearly RDP. It simply feels smoother.
Practice part 2 - Creating space
In the second practical part, we add another virtual hard disk to our container and connect the container to a USB stick.
Step 1 - USB stick
The assignment is made close to the hardware - i.e. specifically for each individual device.
In the Enviroment section, we need a new entry to assign a USB stick to the container.
ARGUMENTS: "-device usb-host,vendorid=0x090c,productid=0x1000"
The vendor and product ID of the device is required. To get these two values, we need the command lsusb.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0bda:5420 Realtek Semiconductor Corp. 4-Port USB 2.0 Hub
Bus 001 Device 003: ID 05e3:0610 Genesys Logic, Inc. Hub
Bus 001 Device 004: ID 046d:0843 Logitech, Inc. Webcam C930e
Bus 001 Device 005: ID 08bb:2902 Texas Instruments PCM2902 Audio Codec
Bus 001 Device 006: ID 090c:1000 Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.) Flash Drive
Bus 001 Device 007: ID 046a:0115 CHERRY CHERRY Wireless Device
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 002: ID 0bda:0420 Realtek Semiconductor Corp. 4-Port USB 3.0 Hub
Bus 002 Device 003: ID 05e3:0626 Genesys Logic, Inc. Hub
Bus 002 Device 004: ID 0bda:8153 Realtek Semiconductor Corp. RTL8153 Gigabit Ethernet Adapter
In my case, the USB stick is Device 006 - recognizable by the name Flash Drive.
The ID section contains the vendor and product ID in the order (separated by a :).
We place a 0x in front of each of these values >> vendorid=0x090c,productid=0x1000.
Finally, the following parameter must be added in the Devices section:
- /dev/bus/usb
The container can be started and the USB stick can be used normally.
Step 2 - Additional partitions
Again we start in the Enviroment section and expand it as follows:
DISK2_SIZE: "10G"
DISK3_SIZE: "2G"
We add the following to the Volumes section:
volumes:
- /var/win:/storage
- /var/win:/storage2
- /var/win:/storage3
The size and storage location of the new virtual hard disks can of course be freely adjusted.
After the container has started up, the new virtual hard disks still need to be formatted.
Practice Part 3 - Special Operations
Part 1 - Manual Windows installation
If you do not want an automatic installation, you can also trigger a manual installation with a single parameter.
environment:
MANUAL: "Y"
Part 2 - Sharing files with the host system
For me, one of the most important points is exchanging files between the container and the host system.
In the Volumes section, only one additional parameter is required: - /home/toadie/share:/shared
volumes:
- /var/win:/storage
- /home/toadie/share:/shared
The host.lan device appears under Network - the “Exchange” directory can be found here.
Part 3 - Pass-Through
WARNING:
I can’t say what will happen if you use a Linux partition that already contains data!
My recommendation: Shrink a partition and create a NTFS or FATx partition.
Pass-through** is a technique for using devices from the host system directly in a VM or Contrainer. In other words, devices are not emulated but the existing hardware is addressed directly as by the host system. Of course, this offers significantly better performance.
Only one parameter needs to be added to the Devices section:
- /dev/sdb2:/disk2
In this example, the container would have direct access to the 2nd hard disk and its 2nd partition.
Alternatively, the entire hard disk can of course be used.
Part 4 - Own ISO for the installation
To use your own Windows ISO, the Volumes section is changed as follows:
volumes:
- /var/win/win.iso:/win.iso
- /var/win:/storage
Conclusion and final words
Performance
I doubt that it is possible to play games that are newer than 1999 with such a system - if at all.
Docker is not worthwhile for gamers.
For smaller services or programs, however, a Windows Docker is definitely an alternative to a virtual machine.
I was amazed at the performance when converting audio files. Here, the Docker variant is clearly ahead of Virtual Box and QEMU.
Especially when using Pass-Through there is nothing to complain about.
Furthermore, I have the, perhaps subjective, impression that the Docker Windows containers put less strain on the host system overall than conventional virtual machines.
Recommendations
For small requirements, the Tiny version should be sufficient. This requires significantly less hard disk capacity than full Windows versions. I myself have opted for the Tiny version. So far, it has been completely sufficient for my few usage scenarios.
Outlook
I cannot say whether all images offer the same features and work equally well.
For my tests I used win11, win10, win7 and tiny10. All without any problems. However, tiny10 did not accept any changes to the language - but this is probably due to the concept of a Tiny Windows.
Appendix
Available Windows versions
Conclusion and final words
Performance
I doubt that it is possible to play games that are newer than 1999 with such a system - if at all.
Docker is not worthwhile for gamers.
For smaller services or programs, however, a Windows Docker is definitely an alternative to a virtual machine.
I was amazed at the performance when converting audio files. Here, the Docker variant is clearly ahead of Virtual Box and QEMU.
Especially when using Pass-Through there is nothing to complain about.
Furthermore, I have the, perhaps subjective, impression that the Docker Windows containers put less strain on the host system overall than conventional virtual machines.
Recommendations
For small requirements, the Tiny version should be sufficient. This requires significantly less hard disk capacity than full Windows versions. I myself have opted for the Tiny version. So far, it has been completely sufficient for my few usage scenarios.
Outlook
I cannot say whether all images offer the same features and work equally well.
For my tests I used win11, win10, win7 and tiny10. All without any problems. However, tiny10 did not accept any changes to the language - but this is probably due to the concept of a Tiny Windows.
Appendix
Available Windows versions
Value for Docker | Version | Download size |
---|---|---|
win11 | Windows 11 Pro | 6.4 GB |
win11e | Windows 11 Enterprise | 5.8 GB |
win10 | Windows 10 Pro | 5.7 GB |
ltsc10 | Windows 10 LTSC | 4.6 GB |
win10e | Windows 10 Enterprise | 5.2 GB |
win8 | Windows 8.1 Pro | 4.0 GB |
win8e | Windows 8.1 Enterprise | 3.7 GB |
win7 | Windows 7 Enterprise | 3.0 GB |
vista | Windows Vista Enterprise | 3.0 GB |
winxp | Windows XP Professional | 0.6 GB |
2022 | Windows Server 2022 | 4.7 GB |
2019 | Windows Server 2019 | 5.3 GB |
2016 | Windows Server 2016 | 6.5 GB |
2012 | Windows Server 2012 | 4.3 GB |
2008 | Windows Server 2008 | 3.0 GB |
core11 | Tiny 11 Core | 2.1 GB |
tiny11 | Tiny 11 | 3.8 GB |
tiny10 | Tiny 10 | 3.6 GB |
Parameters
Devices
Parameters | Description |
/dev/kvm | |
/dev/bus/usb | |
/dev/sdb:/disk2 |
Volumes
Parameters | Description |
- /home/tux/docker/win10:/storage | Path for the virtual Docker disk |
- /home/tux/docker/share:/shared | Path for a share directory to exchange files with between host and container |
Enviroment
Parameters | Description |
VERSION | Windows version - see table Available Windows versions |
RAM_SIZE | Size of the available physical memory |
CPU_CORES | Number of CPU cores provided |
DISK_SIZE | Size of the virtual hard disk |
LANGUAGE | Desired language, e.g. German |
REGION | Time zone etc., e.g. de-DE |
KEYBOARD | Keyboard layout, e.g. de-DE for the German keyboard layout |
USERNAME | User name for the Windows user, e.g. Tux |
PASSWORD | Password for the Windows user |
ARGUMENTS | e.g. for USB devices |
MANUAL | A manual installation is triggered (MANUAL: “Y”) |