Docker on Windows Subsystem for Linux with Windows 10 Creators Update

Wow, that's a long blog title... lucky for you, it could have been longer... Docker for Windows with Windows Subsystem for Linux on Windows 10 Creators Update

The Windows Subsystem for Linux (WSL), a.k.a Bash on Windows, was first introduced with the Windows 10 Anniversary update back in 2016. Since then a whole bunch of work has gone into improving it, including support for tonnes more developer tools, networking and better integration with the underlying Windows OS. Most of these improvements were bundled into the Windows 10 Creators Update, which was released this spring. If you don't have the Creators Update and want to get your hands on it, go grab it from here. For more information about the updates to the WSL in the Creators Update, please refer to this blog.

One of the features that was released in the Creators Update that I'm particular excited about, is the massively improved interoperability between the Windows OS and the Linux OS. Meaning that you can now launch Windows binaries from Bash on Windows and similarly, Linux binaries from Windows. Now this has the potential to change the way that you work with the Docker tooling on Windows.

Currently, on Windows 10 Anniversary update, you have to install Docker for Windows and a separate Docker client binary in your bash environment. The bash client then works by connecting to the Docker engine running on the Docker for Windows Linux virtual machine by setting the following environment variable:

export DOCKER_HOST="tcp://127.0.0.1:2375"  

You will also need to enable the docker engine to expose itself over TCP without TLS by checking this box in the Docker for Windows settings.

This method works reasonably well, except you have 2 separate clients (Linux and Windows) that you have to reconcile configuration between and you have to open a security vulnerability in your system by exposing the daemon over TCP without TLS.

With the Creators Update, we can now setup our bash environment to call our Windows Docker binary so that we don't have to manage the 2 distinct clients.

Setup Docker in bash with the Creators Update
  1. Go and install Docker for Windows from the Docker store. Use the default installation directories.

  2. Ensure the Windows installation is working as expected:

    docker run hello-world
    Hello from Docker!
    This message shows that your installation appears to be working correctly.
    ...
    
  3. Open a new Bash on Windows terminal.

  4. Open your .bashrc file:

    vim ~/.bashrc
    
  5. Jump to the bottom of the file using the shortcut SHIFT + G

  6. Add a new section to the file with the following commands:

    ...
    # Configure Docker with Docker for Windows
    PATH="$HOME/bin:$HOME/.local/bin:$PATH"
    PATH="$PATH:/mnt/c/Program\ Files/Docker/Docker/resources/bin"
    alias docker="docker.exe"
    

    These commands are going to add the Windows docker.exe binary folder to your bash $PATH variable. You then create a simple alias from docker -> docker.exe to save you writing docker.exe every time.

  7. Save and close the .bashrc file using: :wq.

  8. Source your updated bashrc to update your bash environment:

     source ~/.bashrc
    
  9. In bash, change to a directory under /mnt/c/* .i.e. /mnt/c/Users/username/

  10. Test that you can call docker correctly from your bash terminal:

    docker run hello-world
    Hello from Docker!
    ...
    

NOTE: The reason in step 9, I suggested you moved to a directory under /mnt/c/ is because the Docker client needs to be able to set the working directory. This is usually set to the directory in which you execute the docker command. However, if you happen to be inside a virtual volume in the Linux file system, such as /home/username/, then the Window's based Docker client won't have access and thus won't be able to set this folder as the working directory. Therefore, it is important that you ONLY execute docker commands in bash from folders that are shared between both the Windows file system and the Linux file system .i.e. /mnt/c/User/username and C:\Users\username.

If you do not follow this advice, you will hit the following warning:

docker run hello-world  
Unable to translate current working directory. Using C:\Windows\system32\  
...

The Docker command will throw this warning but continue to successfully run the container. This is not an issue for pre-built docker images. However, if you are building your own Docker images which use files from the current working directory then you might find yourself in a bit of a mess. With errors such as:

unable to prepare context: unable to evaluate symlinks in Dockerfile path: GetFileAttributesEx C:\Windows\System32\Dockerfile: The system cannot find the file specified.  

As you can see from the first warning, docker will attempt to default the working directory to the working directory of the terminal in which you ran the command. This is can be dangerous and inconvenient, hence I strongly advice you follow the method mentioned above.

Now you should have a single Docker client (Windows binary) which can be invoked seamlessly from your bash environment.

Remember: Docker for Windows can be configured to run both Windows and Linux based containers, make sure you have it set to environment in which you intend your container to run.