Skip to content

Windows WCOW Docker Daemon on Cloud VM

Micah Young edited this page May 5, 2021 · 61 revisions

These instructions create a Window VM based on the Windows Server Core 1809 machine image containing Docker with Windows Container enabled (WCOW). This is useful for debugging pack and other CNB tests, specifically for Windows WCOW scenarios.

This is not a full Docker Desktop installation and the VM has only a minimal GUI and no LCOW option. However, the Docker installed uses a containerd which is very close to a Windows Kubernetes node and the default GitHub actions runner.

Total install time: ~ 5 minutes

Create your VM

This will create a from-scratch Windows development VM to which you'll add Docker and some basic development tools and settings. Choose one of the following: GCP, Azure, or Local depending on your preference.

Google Cloud Platform

Create a new instance

# Create VM with Windows Server Core for Containers + SSD
gcloud compute instances create \
  docker-windows \
  --machine-type=e2-custom-4-4096 \
  --image=windows-server-2019-dc-core-for-containers-v20201013 \
  --image-project=windows-cloud \
  --boot-disk-size=32GB \
  --boot-disk-type=pd-ssd

# Reset and print password (can be run again to securely retrieve password)
gcloud compute reset-windows-password docker-windows --user dockeruser

Microsoft Azure

Create a new instance

# Create resource group to contain VM, disks, networks, etc
az group create \
  --location eastus \
  --name docker-windows-vms

# Create VM with Windows Server Core for Containers + SSD
# You will be prompted for your desired VM password
az vm create \
  --name docker-windows \
  --admin-username dockeruser \
  --image MicrosoftWindowsServer:WindowsServer:2019-Datacenter-Core-with-Containers-smalldisk:2019.0.20190410 \
  --nsg-rule RDP \
  --storage-sku StandardSSD_LRS \
  --size Standard_B2s \
  --resource-group docker-windows-vms

# Add firewall port for SSH, append to existing rdp rule
az network nsg rule update \
  --name rdp \
  --nsg-name docker-windowsNSG \
  --destination-port-ranges 22 3389 \
  --resource-group docker-windows-vms
  • Latest image version (choose highest version):

    az vm image list --all --publisher MicrosoftWindowsServer --offer WindowsServer --sku 2019-Datacenter-Core-with-Containers-smalldisk

Local VMware Fusion VM

The use a local VM instead, follow these instructions to configure a Windows 2019 Server Evaluation VM.

https://github.com/buildpacks/pack/wiki/Windows-Docker-Daemon-on-Fusion-VM

VM Setup instructions

  1. RDP into instance using IP Address, Username and Password from create step

  2. Run the following in RDP terminal window:

    powershell
    
    # Set shutdown timer to save cost - VMs are about $100USD per month
    schtasks /create /st (Get-Date).AddHours(8).ToString("HH:mm") /sc daily /tr "shutdown -s" /tn "minimize cost"
    
    # Install SSH
    Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 ; Get-Service sshd | Set-Service -StartupType Automatic ; Start-Service sshd
    • Optional: add your ssh public key to avoid typing password. This command will prompt for your pubkey which you paste.
    Read-Host "waiting for pubkey" | Out-File -Encoding ascii -Append C:\ProgramData\ssh\administrators_authorized_keys ; $acl = Get-Acl C:\ProgramData\ssh\administrators_authorized_keys ; $acl.SetSecurityDescriptorSddlForm("O:BAG:BAD:PAI(A;;FA;;;SY)(A;;FA;;;BA)") ; $acl | Set-Acl 

    You can disconnect RDP, everything else can be done over SSH

  3. SSH into the instance using IP Address, Username and Password from create step

    ssh -t dockeruser@<ip_address> powershell
    # Password: <password>
    
    • Note: this must be an administrator account (which is the default for the Google/Azure account created in Create your VM)
  4. Run in the administrator SSH powershell session:

    powershell
    
    # Content below can be copy-pasted in bulk
    
    # Allow scripts to be run
    Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force
    
    # Set timezone to UTC
    Set-Timezone -Id UTC
    
    # Set default SSH shell to powershell
    Set-ItemProperty HKLM:\SOFTWARE\OpenSSH\ DefaultShell -Value C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe
    
    # Profile script to reload PATH on each SSH login
    mkdir $env:USERPROFILE\Documents\WindowsPowerShell
    echo '
    $env:PATH=(Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" -Name PATH).Path
    $env:PATH+=";"+(Get-ItemProperty -Path "HKCU:\Environment" -Name PATH).Path
    ' | Out-File -FilePath $env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    
    # Install chocolately dependencies
    Install-Package -Force chocolatey
    Install-ChocolateySoftware
    Install-ChocolateyPackage -Confirm:$false -Name git,golang,make,gnuwin32-coreutils.portable
    
    # Add git-* commands to PATH
    $currentPath = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" -Name PATH).Path
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" -Name PATH -Value "$currentPath;c:\Program Files\git\mingw64\bin\"
    
    # Reload path for newly installed commands
    . $env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    
    # Install richgo
    go get -u github.com/kyoh86/richgo
    echo '
    Set-Alias go -Value richgo
    $env:GOCMD="richgo"
    ' | Out-File -Append -FilePath $env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    
    # Reload path for newly installed commands
    . $env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    
    # Add/update Docker Desktop DNS helpers and config IP address on each new terminal
    echo '
    $IPAddress=(Get-NetIPAddress -InterfaceAlias ((Get-NetRoute "0.0.0.0/0").InterfaceAlias) -AddressFamily IPv4)[0].IPAddress
    
    if (!(Get-NetfirewallRule -DisplayName test-registry)) {
      New-NetfirewallRule -DisplayName test-registry -LocalAddress $IPAddress
    }
    
    $config=@{}
    if (Test-Path C:\ProgramData\docker\config\daemon.json) {
      $config=(Get-Content C:\ProgramData\docker\config\daemon.json | ConvertFrom-json)
    }
    $config."insecure-registries" = @("$IPAddress/32")
    ConvertTo-json $config | Out-File -Encoding ASCII C:\ProgramData\docker\config\daemon.json
    
    $hostsContent=(Get-Content -Path C:\Windows\System32\drivers\etc\hosts -Raw)
    $hostsContent=($hostsContent -replace ".* host.docker.internal gateway.docker.internal","")
    $hostsContent += "
    ${IPAddress} host.docker.internal gateway.docker.internal"
    $hostsContent | Out-File -Encoding ASCII -FilePath C:\Windows\System32\drivers\etc\hosts
    ' | Out-File -Append -FilePath $env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    
    # Reload path for newly installed commands
    . $env:USERPROFILE\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    
    # Restart for new settings
    Restart-Service docker
    
    # Set Git defaults to POSIX
    git config --global core.autocrlf false
    git config --global core.eol lf
    git config --global core.symlinks true

Next steps

  • Clone your repo/run your commands
    git clone https://github.com/my-fork/my-repo -b my-branch

Or