Skip to content

Instantly share code, notes, and snippets.

@dpfoose
Last active October 10, 2023 09:22
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dpfoose/f96d4e4b76c2e01265619d545b77987a to your computer and use it in GitHub Desktop.
Save dpfoose/f96d4e4b76c2e01265619d545b77987a to your computer and use it in GitHub Desktop.
Get the path on a Docker host from a path in a Docker container if the path is in a bind-mounted volume
'''
Copyright (C) 2018 by Daniel Foose
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
'''
import re
import docker
import socket
def in_docker():
"""
Check if running in Docker
:return: Whether or not this is running in Docker container
"""
try:
with open('/proc/1/cgroup', 'rt') as cgroup_file:
return 'docker' in cgroup_file.read()
except FileNotFoundError as e:
return False
def translate_path(path):
"""
:param path: A string representing a path within the container
:return: A string representing a path on the host (or the original path if the path is not in a bound volume)
"""
binds = get_binds()
if path in binds.keys():
return binds[path]
exps = ['(%s)/(.*)' % key for key in binds.keys()]
print('path: %s' % path)
for exp in exps:
result = re.search(exp, path)
if result:
print('%s/%s' % (binds[result.group(1)], result.group(2)))
return '%s/%s' % (binds[result.group(1)], result.group(2))
raise ValueError('Path %s not present in a bind mount. Volume mount will fail when running this in Docker.' % path)
def get_current_container():
"""
Will raise ValueError if there is no container with the same hostname as the environment this is running in
Which indicates that this is not a docker container, or that /var/run/docker.sock is not bind mounted to
/var/run/docker.sock on the host (i.e. this is a container which is also a docker host).
:return: A dictionary containing information about the container this is running in obtained using docker api
"""
hostname = socket.gethostname()
client = docker.from_env()
for container in client.containers.list():
if container.attrs['Config']['Hostname'] == hostname:
return container
raise ValueError('Not running in Docker container')
def get_binds():
"""
:return: A dictionary with paths in the container as keys and paths on the host as values
"""
container = get_current_container()
return {bind.split(':')[1]: bind.split(':')[0] for bind in container.attrs['HostConfig']['Binds']}
@dpfoose
Copy link
Author

dpfoose commented Jan 29, 2018

/var/run/docker.sock on the host must be bound to /var/run/docker.sock in the container.
This is mostly useful when you need to spawn another container with bind mounts.

@okainov
Copy link

okainov commented Apr 21, 2021

@dpfoose would you be able please to mention the license of these snippets?

@dpfoose
Copy link
Author

dpfoose commented Apr 21, 2021

@dpfoose would you be able please to mention the license of these snippets?

@okainov
Sure, I added a license statement. It's the zero-clause BSD, so you can treat it as public domain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment