From df548a65ebaf417a69b402d9d366cb0f023cff71 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sun, 18 Feb 2018 01:40:55 +0100 Subject: [PATCH] Allow Dockerfile from outside build-context Historically, the Dockerfile had to be insde the build-context, because it was sent as part of the build-context. https://github.com/moby/moby/pull/31236/commits/3f6dc81e10b8b813fffaa9b4167a60c5a507fa38 added support for passing the Dockerfile through stdin, in which case the contents of the Dockerfile is injected into the build-context. This patch uses the same mechanism for situations where the location of the Dockerfile is passed, and its path is outside of the build-context. Before this change: $ mkdir -p myproject/context myproject/dockerfiles && cd myproject $ echo "hello" > context/hello $ echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > dockerfiles/Dockerfile $ docker build --no-cache -f $PWD/dockerfiles/Dockerfile $PWD/context unable to prepare context: the Dockerfile (/Users/sebastiaan/projects/test/dockerfile-outside/myproject/dockerfiles/Dockerfile) must be within the build context After this change: $ mkdir -p myproject/context myproject/dockerfiles && cd myproject $ echo "hello" > context/hello $ echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > dockerfiles/Dockerfile $ docker build --no-cache -f $PWD/dockerfiles/Dockerfile $PWD/context Sending build context to Docker daemon 2.607kB Step 1/3 : FROM busybox ---> 6ad733544a63 Step 2/3 : COPY /hello / ---> 9a5ae1c7be9e Step 3/3 : RUN cat /hello ---> Running in 20dfef2d180f hello Removing intermediate container 20dfef2d180f ---> ce1748f91bb2 Successfully built ce1748f91bb2 Signed-off-by: Sebastiaan van Stijn --- cli/command/image/build.go | 14 ++++++++++++-- cli/command/image/build/context.go | 8 ++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/cli/command/image/build.go b/cli/command/image/build.go index 637068a80f4b..470888f884a8 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -9,8 +9,10 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "regexp" "runtime" + "strings" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" @@ -206,6 +208,14 @@ func runBuild(dockerCli command.Cli, options buildOptions) error { buildCtx, relDockerfile, err = build.GetContextFromReader(dockerCli.In(), options.dockerfileName) case isLocalDir(specifiedContext): contextDir, relDockerfile, err = build.GetContextFromLocalDir(specifiedContext, options.dockerfileName) + if err == nil && strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) { + // Dockerfile is outside of build-context; read the Dockerfile and pass it as dockerfileCtx + dockerfileCtx, err = os.Open(relDockerfile) + if err != nil { + return errors.Errorf("unable to open Dockerfile: %v", err) + } + defer dockerfileCtx.Close() + } case urlutil.IsGitURL(specifiedContext): tempDir, relDockerfile, err = build.GetContextFromGitURL(specifiedContext, options.dockerfileName) case urlutil.IsURL(specifiedContext): @@ -253,7 +263,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error { } } - // replace Dockerfile if it was added from stdin and there is archive context + // replace Dockerfile if it was added from stdin or a file outside the build-context, and there is archive context if dockerfileCtx != nil && buildCtx != nil { buildCtx, relDockerfile, err = build.AddDockerfileToBuildContext(dockerfileCtx, buildCtx) if err != nil { @@ -261,7 +271,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error { } } - // if streaming and dockerfile was not from stdin then read from file + // if streaming and Dockerfile was not from stdin then read from file // to the same reader that is usually stdin if options.stream && dockerfileCtx == nil { dockerfileCtx, err = os.Open(relDockerfile) diff --git a/cli/command/image/build/context.go b/cli/command/image/build/context.go index a98cd7b237e1..1d3011aff6bc 100644 --- a/cli/command/image/build/context.go +++ b/cli/command/image/build/context.go @@ -167,6 +167,10 @@ func GetContextFromGitURL(gitURL, dockerfileName string) (string, string, error) return "", "", err } relDockerfile, err := getDockerfileRelPath(absContextDir, dockerfileName) + if err == nil && strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) { + return "", "", errors.Errorf("the Dockerfile (%s) must be within the build context", dockerfileName) + } + return absContextDir, relDockerfile, err } @@ -318,10 +322,6 @@ func getDockerfileRelPath(absContextDir, givenDockerfile string) (string, error) return "", errors.Errorf("unable to get relative Dockerfile path: %v", err) } - if strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) { - return "", errors.Errorf("the Dockerfile (%s) must be within the build context", givenDockerfile) - } - return relDockerfile, nil }