Following from post last week about obuilder and Windows Host Compute Services, I am pleased to report that this is now running on OCaml-CI. In this early phase, I have enabled testing only on Windows 2025 with OCaml 5.4 and opam 2.5 using the MinGW toolchain.
Since my earlier post, I have achieved reliable operation and pushed the workarounds I had in obuilder into LWT. Furthermore, I have switched from a JSON configuration file per layer to an S-expression format, as this better matches the existing style, and the PPX deriving was already installed. There have also been numerous other small clean-ups.
Containerd uses the Windows Host Network Service, as does Docker. Docker creates a new network at boot with a random subnet. In the extract below, the network is 172.17.32.0/20.
PS C:\Users\Administrator> Get-HnsNetwork
ActivityId : 0F32EF26-00D8-4B04-BB0A-57F18075F9EA
AdditionalParams :
CurrentEndpointCount : 1
Extensions : {@{Id=E7C3B2F0-F3C5-48DF-AF2B-10FED6D72E7A; IsEnabled=False;
Name=Microsoft Windows Filtering Platform},
@{Id=F74F241B-440F-4433-BB28-00F89EAD20D8; IsEnabled=False;
Name=Microsoft Azure VFP Switch Extension},
@{Id=430BDADD-BAB0-41AB-A369-94B67FA5BE0A; IsEnabled=True; Name=Microsoft
NDIS Capture}}
Flags : 8
Health : @{LastErrorCode=0; LastUpdateTime=134170237512475197}
ID : 4EE1C263-FD69-45F9-8F4D-1D7137222B79
IPv6 : False
LayeredOn : FBA38879-AA6A-48AF-AD6D-35127F74313A
MacPools : {@{EndMacAddress=00-15-5D-D2-1F-FF; StartMacAddress=00-15-5D-D2-10-00}}
MaxConcurrentEndpoints : 3
Name : nat
NatName : NAT9A2D26A3-7226-46EE-9D96-5CDA0BF27595
Policies : {@{Type=VLAN; VLAN=1}}
State : 1
Subnets : {@{AdditionalParams=; AddressPrefix=172.17.32.0/20; Flags=0;
GatewayAddress=172.17.32.1; Health=;
ID=FD5E1DC1-71A1-4669-94D1-AD980E405535; IpSubnets=System.Object[];
ObjectType=5; Policies=System.Object[]; State=0}}
SwitchGuid : 4EE1C263-FD69-45F9-8F4D-1D7137222B79
TotalEndpoints : 13
Type : nat
Version : 68719476736
Resources : @{AdditionalParams=; AllocationOrder=2; Allocators=System.Object[];
CompartmentOperationTime=0; Flags=0; Health=;
ID=0F32EF26-00D8-4B04-BB0A-57F18075F9EA; PortOperationTime=0; State=1;
SwitchOperationTime=0; VfpOperationTime=0;
parentId=95C9A579-958E-4991-A38A-A15BA23F39D9}
I had been running these commands on startup:
Get-HnsNetwork | Where-Object { $_.Name -eq 'nat' } | Remove-HnsNetwork
New-HnsNetwork -Type nat -Name nat -AddressPrefix '172.20.0.0/16' -Gateway '172.20.0.1'
And setting the network configuration to 172.20.0.0/16 in C:\Program Files\containerd\cni\conf\0-containerd-nat.conf. However, this broke docker build as it could not find the network it was expecting:
failed to create endpoint vibrant_tu on network nat: failed during hnsCallRawResponse: hnsCall failed in Win32: Element not found. (0x490)
Changing direction, I have instead used fix-nat.ps1 as a scheduled task at reboot to align containerd’s configuration with Docker’s.
# Read Docker's existing NAT network configuration and write it into the
# containerd CNI config so both runtimes share the same subnet.
Import-Module c:\windows\hns.psm1
$net = Get-HnsNetwork | Where-Object { $_.Name -eq 'nat' }
if (-not $net) {
Write-Error "No NAT network found"
exit 1
}
$subnet = $net.Subnets[0].AddressPrefix
$gateway = $net.Subnets[0].GatewayAddress
$json = @{
cniVersion = "0.3.0"
name = "nat"
type = "nat"
master = "Ethernet"
ipam = @{
subnet = $subnet
routes = @(@{ gateway = $gateway })
}
capabilities = @{
portMappings = $true
dns = $true
}
} | ConvertTo-Json -Depth 3
$json | Set-Content 'C:\Program Files\containerd\cni\conf\0-containerd-nat.conf' -Encoding ASCII
Write-Host "CNI config updated: subnet=$subnet gateway=$gateway"
Here is the log of a successful run from OCaml-CI: mtelvers/mandelbrot/commit/14e08f30f087994a19822546a55405d078acd0d3/variant/windows-server-mingw-ltsc2025-5.4_opam-2.5
PRs