Windows Docker Machine
This Vagrant environment creates a "Docker Machine" to work on your MacBook with Windows containers. You can easily switch between Docker Desktop Linux containers and the Windows containers.
Many flavors
There are several versions of Windows Server. This is where you decide which Vagrant VM should be started.
2022-box
- Windows Server 2022 (10.0.20348) LTS Channel, prebuilt from Vagrant Cloud2022
- Windows Server 2022 (10.0.20348) LTS Channel2019-box
- Windows Server 2019 (10.0.17763) LTS Channel, prebuilt from Vagrant Cloud2019
- Windows Server 2019 (10.0.17763) LTS Channel1903
- Windows Server, version 1903 (10.0.18362) Semi-Annual Channel1809
- Windows Server, version 1809 (10.0.17763) Semi-Annual Channel1803
- Windows Server, version 1803 (10.0.17134) Semi-Annual Channel2016-box
- Windows Server 2016 (10.0.14393) LTS channel, *prebuilt from Vagrant Cloud2016
- Windows Server 2016 (10.0.14393) LTS channelinsider
- Windows Server Insider buildslcow
- Windows Server, version 1809 with LCOW enabled
So with a vagrant up 2019
you spin up the LTS version, with vagrant up 1903
the 1903 semi-annual version and with vagrant up insider
the Insider build.
If you don't want to run the packer step, you can run vagrant up 2019-box
or vagrant up 2022-box
to get your box image downloaded directly from Vagrant
Cloud. That uses the box images windows_2019_docker, respectively
windows_2022_docker.
Tested environments
- macOS with Vagrant 2.2.19
- VMware Fusion Pro 11.0.3
- VirtualBox 5.2.26 and 6.1.34
- Windows with Vagrant 2.2.4
Getting started
First you need a Windows Server VM for your hypervisor. I prefer "Infrastructure as Code", so every build step is available on GitHub.
- (optional) packer build to build a Vagrant base box, it's like a Docker image, but for Vagrant VM's.
- vagrant up to create a running VM instance of Windows Server, either using the
packer build
or by using one of the pre-built Vagrant Cloud binaries2022-box
,2019-box
, or2016-box
. - docker run to run Windows containers in that Windows VM
Step 1 (building the headless Vagrant box) can be done with these steps:
$ git clone https://github.com/StefanScherer/packer-windows
$ cd packer-windows
$ packer build --only=vmware-iso windows_2022_docker.json
$ vagrant box add windows_2022_docker windows_2022_docker_vmware.box
- or -
$ packer build --only=vmware-iso windows_2019_docker.json
$ vagrant box add windows_2019_docker windows_2019_docker_vmware.box
- or -
$ packer build --only=vmware-iso --var iso_url=~/path-to-1903.iso windows_server_1903_docker.json
$ vagrant box add windows_server_1903_docker windows_server_1903_docker_vmware.box
- or -
$ packer build --only=vmware-iso --var iso_url=~/path-to-1809.iso windows_server_1809_docker.json
$ vagrant box add windows_server_1809_docker windows_server_1809_docker_vmware.box
- or -
$ packer build --only=vmware-iso --var iso_url=~/path-to-1803.iso windows_server_1803_docker.json
$ vagrant box add windows_server_1803_docker windows_server_1803_docker_vmware.box
- or -
$ packer build --only=vmware-iso --var iso_url=~/path-to-insider.iso windows_server_insider_docker.json
$ vagrant box add windows_server_insider_docker windows_server_insider_vmware_docker.box
- or -
$ packer build --only=vmware-iso --var iso_url=~/path-to-2016.iso windows_2016_docker.json
$ vagrant box add windows_2016_docker windows_2016_docker_vmware.box
Of course you can build only the box version you need. If you are using VirtualBox instead of VMware,
swap vmware
for virtualbox
in the vagrant commands above.
Working on macOS & Linux
Create the Docker Machine
Spin up the headless Vagrant box you created earlier. It will create the TLS
certificates and a corresponding Docker context called 2022-box
or 2019-box
.
$ git clone https://github.com/StefanScherer/windows-docker-machine
$ cd windows-docker-machine
$ vagrant up --provider vmware_desktop 2019-box
- or -
$ vagrant up --provider virtualbox 2019-box
If you want to use Windows Server 2022, type 2022-box
here instead.
List your new Docker machine
$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
2019-box 2019-box windows-docker-machine tcp://192.168.65.130:2376
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock https://localhost:6443 (default) swarm
dummy tcp://1.2.3.4:2375
Switch to Windows containers
$ docker context use 2019-box
Now your Mac Docker client talks to the Windows Docker engine:
$ docker version
Client: Docker Engine - Community
Version: 19.03.0-beta1
API version: 1.39 (downgraded from 1.40)
Go version: go1.12.1
Git commit: 62240a9
Built: Thu Apr 4 19:15:32 2019
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Enterprise
Engine:
Version: 18.09.5
API version: 1.39 (minimum version 1.24)
Go version: go1.10.8
Git commit: be4553c277
Built: 04/11/2019 06:43:04
OS/Arch: windows/amd64
Experimental: false
Switch back to Docker Desktop
$ docker context use default
This removes all DOCKER environment variables and you can use your Docker for Mac installation.
$ docker version
Client: Docker Engine - Community
Version: 19.03.0-beta1
API version: 1.39 (downgraded from 1.40)
Go version: go1.12.1
Git commit: 62240a9
Built: Thu Apr 4 19:15:32 2019
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.2
API version: 1.39 (minimum version 1.12)
Go version: go1.10.6
Git commit: 6247962
Built: Sun Feb 10 04:13:06 2019
OS/Arch: linux/amd64
Experimental: false
Mounting volumes from your Mac machine
Just use C:$(pwd)
to prepend a drive letter.
$ docker run -it -v C:$(pwd):C:$(pwd) mcr.microsoft.com/windows/servercore:1809 powershell
This mounts the current working directory through the Windows VM into the Windows Container.
Accessing published ports of Windows containers
When you run Windows containers with publish ports then you can use the IP
address of the Windows Docker host to access it. The docker context
command in combination with jq
can give your the IP address with a command. Alternatively docker-machine ip
also gives you the IP address.
Example: Run the whoami Windows container and open it in the default macOS browser.
$ docker run -d -p 8080:8080 stefanscherer/whoami
$ open http://$(docker context inspect 2019-box | jq -r '.[0].Endpoints.docker.Host | .[6:] | .[:-5]'):8080
- or -
$ open http://$(docker-machine ip 2019-box):8080
Working on Windows
Spin up the headless Vagrant box you created earlier. It will create the TLS
certificates and a corresponding Docker context called 2022-box
or 2019-box
.
If you haven't worked with docker context
yet, create the .docker
directory
in your user profile manually.
PS C:\> mkdir $env:USERPROFILE\.docker
Create the Docker Machine
Choose your hypervisor and start the VM
PS C:\> git clone https://github.com/StefanScherer/windows-docker-machine
PS C:\> cd windows-docker-machine
PS C:\> vagrant up --provider vmware_desktop 2019-box
- or -
PS C:\> vagrant up --provider virtualbox 2019-box
- or -
PS C:\> vagrant up --provider hyperv 2019-box
If you want to use Windows Server 2022, type 2022-box
here instead.
Notice: The provider hyperv
does mount the volumes with SMB into the Windows Server
VM. It seems that there is a problem mounting that further into a Windows
container. The provisioning (creating the TLS certs and copying them back to the
Windows host) will fail.
List your new Docker machine
PS C:\> docker context ls
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
2019-box 2019-box windows-docker-machine tcp://192.168.65.130:2376
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock https://localhost:6443 (default) swarm
Switch to Windows containers
PS C:\> docker context use 2019-box
Now your Windows Docker client talks to the Windows Docker engine:
PS C:\> docker version
Client: Docker Engine - Community
Version: 19.03.0-beta1
API version: 1.39 (downgraded from 1.40)
Go version: go1.12.1
Git commit: 62240a9
Built: Thu Apr 4 19:15:32 2019
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Enterprise
Engine:
Version: 18.09.5
API version: 1.39 (minimum version 1.24)
Go version: go1.10.8
Git commit: be4553c277
Built: 04/11/2019 06:43:04
OS/Arch: windows/amd64
Experimental: false
Switch to back to Docker for Windows
PS C:\> docker context use default
This removes all DOCKER environment variables and you can use your Docker for Windows installation.
PS C:\> docker version
Client: Docker Engine - Community
Version: 19.03.0-beta1
API version: 1.39 (downgraded from 1.40)
Go version: go1.12.1
Git commit: 62240a9
Built: Thu Apr 4 19:15:32 2019
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.2
API version: 1.39 (minimum version 1.12)
Go version: go1.10.6
Git commit: 6247962
Built: Sun Feb 10 04:13:06 2019
OS/Arch: linux/amd64
Experimental: false
Mounting volumes from your Windows machine
Just use $(pwd)
in PowerShell.
PS C:\> docker run -it -v "$(pwd):$(pwd)" mcr.microsoft.com/windows/servercore:1809 powershell
This mounts the current working directory through the Windows VM into the Windows Container.
Accessing published ports of Windows containers
When you run Windows containers with publish ports then you can use the IP
address of the Windows Docker host to access it. The docker context inspect
command can
give your the IP address with a command.
Example: Run the whoami Windows container and open it in the default browser.
PS C:\> docker run -d -p 8080:8080 stefanscherer/whoami
PS C:\> start http://$(docker-machine ip 2019-box):8080
Further commands
Here is a list of vagrant
and docker
commands for typical actions.
I use a bash
function
dm
in my dotfiles repo
to simplify all the tasks without switching to the Vagrant folder each time.
The dm
started as a shortcut for docker-machine
commands. I have updated the function to work with docker context
, but rolled back for now as I prefer the environment variables to have different "contexts" per terminal tab.
dm shortcut | Vagrant / Docker command |
---|---|
dm start 2019-box |
vagrant up --provider xxx 2019-box |
dm regenerate-certs 2019-box |
vagrant provision 2019-box |
dm stop 2019-box |
vagrant halt 2019-box |
dm start 2019-box |
vagrant up 2019-box |
dm rdp 2019-box |
vagrant rdp 2019-box |
dm rm [-f] 2019-box |
vagrant destroy [-f] 2019-box |
dm 2019-box |
docker context use 2019-box or eval $(docker-machine env 2019-box) |
dm ip 2019-box |
docker context inspect 2019-box | jq -r '.[0].Endpoints.docker.Host | .[6:] | .[:-5]' or docker-machine ip 2019-box |
Insider builds
If you want to follow the Windows Server Insider builds then this is for you. It is tested on a Mac with the following steps.
-
Register at Windows Insider program https://insider.windows.com
-
Download the Windows Server ISO from https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewserver?wa=wsignin1.0
-
Build the Vagrant basebox with Packer
git clone https://github.com/StefanScherer/packer-windows
cd packer-windows
packer build --only=vmware-iso --var iso_url=~/Downloads/Windows_InsiderPreview_Server_en-us_18356.iso windows_server_insider_docker.json
vagrant box add windows_server_insider_docker windows_server_insider_docker_vmware.box
Then spin up your Insider machine with
vagrant up insider
This Vagrant box has Docker installed and the following base images are already pulled from Docker Hub:
- mcr.microsoft.com/windows/servercore/insider
- mcr.microsoft.com/windows/nanoserver/insider
LCOW
You can try the Linux Container on Windows feature in a separate machine lcow
.
It is preconfigured to use the Windows Server, version 1903. But you can
also use Windows Insider Server Preview as base box.
vagrant up lcow
docker context use lcow
docker run alpine uname -a
Cleanup
If you want to cleanup your machine again after playing with Windows Containers, use the following commands
vagrant destroy -f
vagrant box remove StefanScherer/windows_2019_docker
docker context rm 2019-box