By default, Windows 11 Pro will be installed. But you can add the `VERSION` environment variable to your compose file, in order to specify an alternative Windows version to be downloaded:
> This can also be used to resize the existing disk to a larger capacity without any data loss. However you will need to [manually extend the disk partition](https://learn.microsoft.com/en-us/windows-server/storage/disk-management/extend-a-basic-volume?tabs=disk-management) since the added disk space will appear as unallocated.
By default, the VM is allocated the full amount of RAM configured via `RAM_SIZE` for its entire lifetime.
If you want the container to dynamically reclaim unused guest RAM based on host memory pressure, you can enable memory ballooning:
```yaml
environment:
BALLOONING: "Y"
```
This requires the VirtIO Balloon service to be installed in the guest. For all supported Windows versions, this happens automatically during unattended installation. If you are using a manual installation or an existing guest that was installed before this feature was added, you need to install it manually by running the following command inside the VM:
```bat
C:\Windows\Drivers\Balloon\blnsvr.exe -i
```
The following optional variables allow you to tune the ballooning behaviour:
| **Variable** | **Default** | **Description** |
|---|---|---|
| `BALLOONING` | _(off)_ | Set to `Y` to enable dynamic memory ballooning |
| `BALLOONING_MIN_MEM` | `33%` | Minimum balloon target, as a percentage of guest max memory (e.g. `33%`) or absolute size (e.g. `2G`) |
| `BALLOONING_RAM_THRESHOLD`| `80.0` | Target host RAM usage percentage; the PI controller aims to keep host usage at or below this value |
| `BALLOONING_RAM_THRESHOLD_HARD`| `90.0` | Host RAM usage percentage above which the balloon target may drop below guest RAM usage, inducing guest memory pressure |
| `BALLOONING_PSI_PRESSURE` | `10.0` | Host PSI `avg10` stall percentage at which the PSI ceiling begins to lower the balloon target |
| `BALLOONING_PSI_PRESSURE_MAX` | `50.0` | Host PSI `avg10` stall percentage at which the PSI ceiling reaches the configured minimum balloon target |
| `BALLOONING_HYSTERESIS` | `128M` | Minimum balloon target change required before a resize is applied, as a percentage (e.g. `2%`) or absolute size (e.g. `256M`) |
| `BALLOONING_KP` | `0.5` | PI controller proportional gain; higher values react faster but may oscillate |
| `BALLOONING_KI` | `0.05` | PI controller integral gain; higher values correct steady-state error faster but risk overshoot |
| `BALLOONING_INTERVAL` | `5` | Polling interval in seconds |
> [!NOTE]
> Memory ballooning uses Linux PSI (`/proc/pressure/memory`) for progressive pressure detection. Between `BALLOONING_PSI_PRESSURE` and `BALLOONING_PSI_PRESSURE_MAX` the PSI ceiling linearly lowers the maximum balloon target from guest max memory down to the configured minimum. If PSI is unavailable (kernel lacks `CONFIG_PSI`), both thresholds are silently skipped and ballooning continues using host memory usage alone.
If you want to use a keyboard layout or locale that is not the default for your selected language, you can add `KEYBOARD` and `REGION` variables like this:
Replace the example path `./example.iso` with the filename of your desired ISO file. The value of `VERSION` will be ignored in this case.
### How do I run a script after installation?
To run your own script after installation, you can create a file called `install.bat` and place it in a folder together with any additional files it needs (software to be installed for example).
Then bind that folder in your compose file like this:
```yaml
volumes:
- ./example:/oem
```
The example folder `./example` will be copied to `C:\OEM` and the containing `install.bat` will be executed during the last step of the automatic installation.
### How do I perform a manual installation?
It's recommended to stick to the automatic installation, as it adjusts various settings to prevent common issues when running Windows inside a virtual environment.
So for a better experience you can connect using any Microsoft Remote Desktop client to the IP of the container, using the username `Docker` and password `admin`.
There is a RDP client for [Android](https://play.google.com/store/apps/details?id=com.microsoft.rdc.androidx) available from the Play Store and one for [iOS](https://apps.apple.com/nl/app/microsoft-remote-desktop/id714464092?l=en-GB) in the Apple Store. For Linux you can use [FreeRDP](https://www.freerdp.com/) and on Windows just type `mstsc` in the search box.
> This IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
After configuring the container for [macvlan](#how-do-i-assign-an-individual-ip-address-to-the-container), it is possible for Windows to become part of your home network by requesting an IP from your router, just like a real PC.
Use `/disk1` if you want it to become your main drive (which will be formatted during installation), and use `/disk2` and higher to add them as secondary drives (which will stay untouched).
If the device is a USB disk drive, please wait until after the installation is fully completed before connecting it. Otherwise the installation may fail, as the order of the disks can get rearranged.
If you did not receive any error from `kvm-ok` but the container still complains about a missing KVM device, it could help to add `privileged: true` to your compose file (or `sudo` to your `docker` command) to rule out any permission issue.
Yes, this project contains only open-source code and does not distribute any copyrighted material. Any product keys found in the code are just generic placeholders provided by Microsoft for trial purposes. So under all applicable laws, this project will be considered legal.
*The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Microsoft Corporation.*