docker-py
docker-py copied to clipboard
Can not pass `fileobj` together with `path` context to `build`
It seems to be impossible to pass ephemeral Dockerfile to build command together with build context. Here is command line use case:
docker build -t . -f-<<EOF
Lorem ipsum docker file
EOF
According to the documentation https://docker-py.readthedocs.io/en/stable/images.htmlit should be possible to pass Dockerfile as file object, but in current implementation path param with context is ignored.
Here is path that fix part of this issue (it don't work when path.startswith(('http://', 'https://','git://', 'github.com/', 'git@')))
diff --git a/docker/api/build.py b/docker/api/build.py
index 0486dce..711def2 100644
--- a/docker/api/build.py
+++ b/docker/api/build.py
@@ -133,7 +133,7 @@ class BuildApiMixin(object):
if not fileobj:
raise TypeError("You must specify fileobj with custom_context")
context = fileobj
- elif fileobj is not None:
+ elif path is None and fileobj is not None:
context = utils.mkbuildcontext(fileobj)
elif path.startswith(('http://', 'https://',
'git://', 'github.com/', 'git@')):
@@ -149,7 +149,7 @@ class BuildApiMixin(object):
lambda x: x != '' and x[0] != '#',
[l.strip() for l in f.read().splitlines()]
))
- dockerfile = process_dockerfile(dockerfile, path)
+ dockerfile = process_dockerfile(dockerfile, path, fileobj)
context = utils.tar(
path, exclude=exclude, dockerfile=dockerfile, gzip=gzip
)
@@ -332,7 +332,13 @@ class BuildApiMixin(object):
log.debug('No auth config found')
-def process_dockerfile(dockerfile, path):
+def process_dockerfile(dockerfile, path, fileobj):
+ if fileobj is not None:
+ return (
+ '.dockerfile.{0:x}'.format(random.getrandbits(160)),
+ fileobj.read()
+ )
+
if not dockerfile:
return (None, None)
In my opinion perfect solution will be to pass context as context and Dockerfile as dockerfile then it might be distinguished if context is an directory path, URL, or tar fileobject same with dockerfile but little harder.
client.images.build(context='.', dockerfile='Dockerfile.local')
client.images.build(context='http://remote.uri', dockerfile=''' FROM ubuntu
facny docker file
''')
client.images.build(context=open('adas'), dockerfile=open('dasdasd'))
OK, here is even better fix. It handles multiline dockerfile as content of Dockerfile. It should also let us embed Dockerfile in docker-compose.yml
diff --git a/docker/api/build.py b/docker/api/build.py
index 0486dce..41649b7 100644
--- a/docker/api/build.py
+++ b/docker/api/build.py
@@ -336,6 +336,12 @@ def process_dockerfile(dockerfile, path):
if not dockerfile:
return (None, None)
+ if '\n' in dockerfile:
+ return (
+ '.dockerfile.{0:x}'.format(random.getrandbits(160)),
+ dockerfile
+ )
+
abs_dockerfile = dockerfile
if not os.path.isabs(dockerfile):
abs_dockerfile = os.path.join(path, dockerfile)
Why not include the dockerfile in the context?
If dockerfile it's not part of context for some reason, it have to be affected to be dockerized. I know that it can be passed as absolute path, but if dockerfile is ephemeral it requires saving is somewhere is filesystem which is little more complicated. Generally it py lib lacs functionality of cli, and arguments could be simplified a bit.
I experience the same problem. The API seems to assume that Dockerfile is always placed in build context which is a more restricted view than the one used by Docker itself. I can't find a way to easily implement the build command docker -f Dockerfile ${DIR} without manually copying file to build context.
Similarly I would also like to use an in-memory generated Dockerfile (mainly to dynamically pick a FROM line for tracking an upstream image.) I would like to copy static files in the build context still like test.txt. It looks like I will just need to write my dynamically generated Dockerfile out to a file and do a normal build.
fileobj = io.BytesIO(b'''FROM upstreamimage:upstreamtag
COPY test.txt /
''')
client.images.build(
fileobj=fileobj,
# no way to set context while using fileobj
)
@danieladams456 I end up with the PR that they don't want to merge and this simple polyfill that might help you:
import docker.api.build
docker.api.build.process_dockerfile = lambda dockerfile, path: ('Dockerfile', dockerfile)
And then simply:
client.images.build(path='.',dockerfile='FROM ...')
Is the project dead or what?
any update to pass the context along with fileobj????
@danieladams456 I end up with the PR that they don't want to merge and this simple polyfill that might help you:
import docker.api.build docker.api.build.process_dockerfile = lambda dockerfile, path: ('Dockerfile', dockerfile)And then simply:
client.images.build(path='.',dockerfile='FROM ...')
Hi @mcopik how to use this??
@danieladams456 I end up with the PR that they don't want to merge and this simple polyfill that might help you:
import docker.api.build docker.api.build.process_dockerfile = lambda dockerfile, path: ('Dockerfile', dockerfile)And then simply:
client.images.build(path='.',dockerfile='FROM ...')
Thank you u're the best
+1 for the ability to specify build context together with fileobj. My use-case: I'm creating a utility that is intended to be used across our org mainly by it people but not engineers. The utility gets a python code in the directory, packages it into a docker image pushes it and then call another service that will run the image in a dedicated env. The approach is to store a Docker file as a string inside the utility and pass as a fileobj. But that cannot be done, as image build process requires context for copying data from user machine.