How to set docker-machine env for fabric local() commands

I’m trying to run commands against a docker-machine cloud provider, and so I need to take the contents of the command docker-machine env digitalocean which is typically as follows:

export DOCKER_HOST="tcp://"
export DOCKER_CERT_PATH="/Users/danh/.docker/machine/machines/digitalocean"
export DOCKER_MACHINE_NAME="digitalocean"
# Run this command to configure your shell:
# eval "$(docker-machine env digitalocean)"

and use the above as a shell prefix, such as:

  • Docker - MySQL container does not keep running
  • Travis ci in docker failing
  • Proxying http requests to another docker container
  • Docker wont build anymore after accedently trying to delete windowsfilter folder
  • How to list images in docker registry being on registry server?
  • docker-machine osx port forwarding
  • print 'outside with:' + local('echo $DOCKER_HOST')
    with prefix(local('docker-machine env digitalocean', capture=True)):
        print 'inside with:' + local('echo $DOCKER_HOST')
    with prefix('DOCKER_HOST="tcp://"'):
        print 'inside with (manual):' + local('echo $DOCKER_HOST')

    However this instead returns:

    outside with:tcp://
    inside with:
    inside with (manual):tcp://

    The only way I can see to get past this is to rip apart the result of local('docker-machine env digitalocean') manually. Surely there is a more fabric-esque way however?

  • Docker mount happens before or after entrypoint execution
  • Why can't redis access the disk in docker-compose?
  • Slow DNS resolution inside docker container
  • Why are my AWS CodeBuild commands not running?
  • How to build an Image using Docker API?
  • Run docker without “sudo” in Fedora 24
  • 2 Solutions collect form web for “How to set docker-machine env for fabric local() commands”

    Well, here’s the solution I’ve gone with so far, feels a bit hacky though:

    def dm_env(machine):
        Sets the environment to use a given docker machine.
        _env = local('docker-machine env {}'.format(machine), capture=True)
        # Reorganize into a string that could be used with prefix().
        _env = re.sub(r'^#.*$', '', _env, flags=re.MULTILINE)  # Remove comments
        _env = re.sub(r'^export ', '', _env, flags=re.MULTILINE)  # Remove `export `
        _env = re.sub(r'\n', ' ', _env, flags=re.MULTILINE)  # Merge to a single line
        return _env
    def blah():
        print 'outside with: ' + local('echo $DOCKER_HOST')
        with prefix(dm_env('digitalocean')):
            print 'inside with: ' + local('echo $DOCKER_HOST')


    outside with: tcp://
    inside with: tcp://

    Another way to get the required information is to use formatting templates for the output of the docker-machine inspect command, as also shown in the documentation.

    Note that curly brackets in Python strings need to be escaped by doubling them, so you end up having four opening and closing brackets each time.

    machine_name = dev
    machine_ip = local("docker-machine inspect --format='{{{{.Driver.IPAddress}}}}' {0}".format(machine_name), capture=True)
    machine_port = local("docker-machine inspect --format='{{{{.Driver.EnginePort}}}}' {0}".format(machine_name), capture=True)
    machine_cert_path = local("docker-machine inspect --format='{{{{.HostOptions.AuthOptions.StorePath}}}}' {0}".format(machine), capture=True)

    Now, you can use the shell_env context manager in order to temporarily point your Docker daemon to a remote machine by setting the according environment variables:

    from fabric.api import shell_env
    with shell_env(DOCKER_TLS_VERIFY='1',
                   DOCKER_HOST='tcp://{0}:{1}'.format(machine_ip, machine_port),
        # will print containers on the remote machine
        local('docker ps -a')
    # will print containers on your local machine 
    # since environment switch is only valid within the context manager
    local('docker ps -a') 
    Docker will be the best open platform for developers and sysadmins to build, ship, and run distributed applications.