So you’ve heard about this thing called Docker and you want to give it a go on your Mac. You’ve installed Docker Toolkit and you’ve created yourself a docker machine:
$ docker-machine create -d virtualbox mymachine Running pre-create checks... Creating machine... (docker) OUT | Creating VirtualBox VM... (docker) OUT | Creating SSH key... (docker) OUT | Starting VirtualBox VM... (docker) OUT | Starting VM... Waiting for machine to be running, this may take a few minutes... Machine is running, waiting for SSH to be available... Detecting operating system of created instance... Detecting the provisioner... Provisioning created instance... Copying certs to the local machine directory... Copying certs to the remote machine... Setting Docker configuration on the remote daemon... To see how to connect Docker to this machine, run: docker-machine env mymachine $ docker-machine env mymachine export DOCKER_TLS_VERIFY="1" export DOCKER_HOST="tcp://192.168.99.100:2376" export DOCKER_CERT_PATH="/Users/ian/.docker/machine/machines/mymachine" export DOCKER_MACHINE_NAME="mymachine" # Run this command to configure your shell: # eval "$(docker-machine env mymachine)" $ eval "$(docker-machine env mymachine)" $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Working nicely there. You’ve probably spent some time creating containers and getting things just so. Then you connect to your work VPN using Cisco AnyConnect and bang, it errors!
$ docker ps Cannot connect to the Docker daemon. Is the docker daemon running on this host?
At this point you may think that the environment variables are incorrect and pointing at the incorrect docker machine so you check:
$ docker-machine env mymachine Error running connection boilerplate: Error checking and/or regenerating the certs: There was an error validating certificates for host "192.168.99.100:2376": dial tcp 192.168.99.100:2376: i/o timeout You can attempt to regenerate them using 'docker-machine regenerate-certs name'. Be advised that this will trigger a Docker daemon restart which will stop running containers.
Certificates!? What’s going on here?
When AnyConnect connects you to your VPN it changes the network routing such that all traffic is redirected to the remote network. For Docker, this means that the Docker client cannot connect to the Docker server running inside the VirtualBox VM because the traffic cannot be routed to it.
Fortunately, this can be resolved by using the loopback address 127.0.0.1 and some port forwarding.
To tell the Docker client where to connect we need to override the
DOCKER_HOST environment variable:
$ export DOCKER_HOST="tcp://127.0.0.1:2376"
We then need to setup port forwarding on the VirtualBox VM for the Docker client to be able to communicate with the Docker server inside the VM.
$ docker-machine stop mymachine $ VBoxManage modifyvm "mymachine" --natpf1 "docker,tcp,,2376,,2376" $ docker-machine start mymachine $ docker ps An error occurred trying to connect: Get https://127.0.0.1:2376/v1.21/containers/json: x509: certificate is valid for 192.168.99.100, not 127.0.0.1
Oh dear. That hasn’t worked because the certificates have not been generated for the loopback address. This verification check can be switched off using the
tlsverify command line option:
$ docker --tlsverify=false ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
That’s fixed it! It isn’t ideal but for a developer wanting to run Docker locally for development only purposes it’s a quick way of getting things working without attempting to manually regenerate the certificates.
To save typing I would recommend setting up an alias so the option does not have to be specified every time.
alias docker='docker --tlsverify=false'
Whilst this port forwarding works, it does, unfortunately, mean that every service you want to run in a container will require a port forwarding configuration to be set on the VirtualBox VM. This can be done at the command line pretty easily as follows:
VBoxManage modifyvm "mymachine" --natpf1 "Apache,tcp,,8080,,8080"
For the above example when running Apache in a container you would just point your browser at http://localhost:8080/.