595

In my Dockerfile I've got :

ADD ../../myapp.war /opt/tomcat7/webapps/

That file exists as ls ../../myapp.war returns me the correct file but when I execute sudo docker build -t myapp . I've got :

Step 1 : ADD ../../myapp.war /opt/tomcat7/webapps/
2014/07/02 19:18:09 ../../myapp.war: no such file or directory

Does somebody know why and how to do it correctly?

2

16 Answers 16

676
  1. cd to your parent directory instead
  2. build the image from the parent directory, specifying the path to your Dockerfile
docker build -t <some tag> -f <dir/dir/Dockerfile> .

In this case, the context of the docker will be switched to the parent directory and accessible for ADD and COPY

Sign up to request clarification or add additional context in comments.

11 Comments

Thank you! This works fine on a local box, but Docker Hub fails to build the image since it tries to do it from its same directory (tbh, just what one would normally expect). Is there any way to do the same trick in Docker Hub?
-f doesn't appear to be deprecated per the docs -> Specify a Dockerfile (-f): docs.docker.com/engine/reference/commandline/build/…
As I read this bulletin, the '-f' flag has only been deprecated on the 'tag' command - docs.docker.com/engine/deprecated/…
but why doesn't COPY ../../.. . work for me - I keep seing the contents of the current directory where I ran docker build?
from the Docker documentation: "When copying source files from the build context, their paths are interpreted as relative to the root of the context. If you specify a relative path leading outside of the build context, such as COPY ../something /something, parent directory paths are stripped out automatically. The effective source path in this example becomes COPY something /something." docs.docker.com/reference/dockerfile/…
|
300

With docker-compose, you could set context folder:

# docker-compose.yml

version: '3.3'    
services:
  yourservice:
    build:
      context: ./
      dockerfile: ./docker/yourservice/Dockerfile

5 Comments

Be careful where you set your context to because large files/folders will make the process hang. You'll want to ignore them with .dockerignore and more appropriately set your context to the point where you really need it.
Using docker-compose as a shortcut to solve this problem of context build is not bad at the moment anyway.
Should dockerfile path be relative to the new context or to docker compose file?
"When the value supplied is a relative path, it is interpreted as relative to the location of the Compose file. " docs.docker.com/compose/compose-file/compose-file-v3
Note that the default context is the project directory, which is the the path of the first specified Compose file.
208

Unfortunately, (for practical and security reasons I guess), if you want to add/copy local content, it must be located at the same level in the directory tree as the Dockerfile.

From the documentation:

The <src> path must be inside the context of the build; you cannot ADD ../something/something, because the first step of a docker build is to send the context directory (and subdirectories) to the docker daemon.

EDIT: There's now an option (-f) to set the path of your Dockerfile ; it can be used to achieve what you want, see @Boedy 's response.

8 Comments

Is there a "clean" workaround for this? I'd rather not restructure my whole project directory just to accommodate this.
As said by @Günter, there is a workaround here superuser.com/a/842690/136024 ... is it really "clean"? Well at least it's a "workaround" :)
See better answer from @Boedy stackoverflow.com/a/34300129/2950621
I'd like to hear any "security reason" for this, really
The documentation link is now docs.docker.com/engine/reference/builder/#add
|
50

Adding some code snippets to support the accepted answer.

Directory structure :

setup/
 |__docker/DockerFile
 |__target/scripts/<myscripts.sh>
src/
 |__<my source files>

Docker file entry:

RUN mkdir -p /home/vagrant/dockerws/chatServerInstaller/scripts/
RUN mkdir -p /home/vagrant/dockerws/chatServerInstaller/src/
WORKDIR /home/vagrant/dockerws/chatServerInstaller

#Copy all the required files from host's file system to the container file system.
COPY setup/target/scripts/install_x.sh scripts/
COPY setup/target/scripts/install_y.sh scripts/
COPY src/ src/

Command used to build the docker image

docker build -t test:latest -f setup/docker/Dockerfile .

5 Comments

great approach. Is it possible to share the code of install_x.sh as well?
I don't understand what -f setup/docker/Dockerfile flag is doing. What is it doing in your example?
also why does the docker command need the final dot if you are already specifying the path to the build context and Dockerfile?
also from where did you run that docker build command? what is the pwd?
@CharlieParker - -f option specifies the relative path of the Dockerfile wrt current working directory. The dot at the end specifies the current working directory. My answer already depicts how the current working directory looks like. Hope that clarifies it for you.
26

In May 2022, Docker announced it added the --build-context flag to the docker build command.

For your example, you can run your build command like this:

docker build --build-context myapp=../.. .

And your Dockerfile can reference that context with any commands that support the --from option

# Dockerfile
COPY --from=myapp myapp.war /opt/tomcat7/webapps/

5 Comments

This feature is broken for podman on Windows: github.com/containers/podman/issues/18840
If I am understanding the OP's question correctly - this is the best answer. Using build-context you can "add a file from a parent directory" in your Dockerfile build. Great feature - I was unaware of it.
Should be the new designated answer.
The best solution.
This is the correct way of doing it. Changing the main context is probably not something easily achievable.
20

If using docker-compose.yml, there is additional_contexts in the API that we can use to take resources from a parent folder outside the main context.

https://docs.docker.com/compose/compose-file/build/#additional_contexts

Here is how it works:

# docker-compose.yml

version: '3.3'    
services:
  my_service:
    build:
      context: ./
      additional_contexts:
         assets: ../../assets
      dockerfile: ./docker/my_service/Dockerfile
# Dockerfile
...
COPY --from=assets . /app/assets
...

1 Comment

correction on code COPY --from=assets . /app/assets use = in place of :
18

Since -f caused another problem, I developed another solution.

  • Create a base image in the parent folder
  • Added the required files.
  • Used this image as a base image for the project which in a descendant folder.

The -f flag does not solved my problem because my onbuild image looks for a file in a folder and had to call like this:

-f foo/bar/Dockerfile foo/bar

instead of

-f foo/bar/Dockerfile .

Also note that this is only solution for some cases as -f flag

2 Comments

Clever idea! multi-stage build to carry over files you need! Thanks for sharing that!
Do we need two Dockerfiles then? One in the parent directory and another in the current (child) directory?
13

Given the following setup:

+ parent
    + service1
        - some_file.json
    + service2
        - Dockerfile

If you have a Dockerfile in service2 and want to copy some_file.json from service1, you can run this inside the service2 directory:

docker build -t my_image ../ --file Dockerfile

This will set the target context one level above. The tricky part here is that the target Dockerfile is set explicitly (as it is not in the target context).

In service2/Dockerfile, you must issue the COPY command as if the file were one level above:

COPY service1/some_file.json /target/location/some_file.json

instead of

COPY ../service1/some_file.json /target/location/some_file.json # will not work

Comments

11

Let setting context: ../../ in parent folder in docker-compose.yml
Ex:

app:
    build:
      context: ../../
      dockerfile: ./source/docker/dockerfile/Dockerfile

1 Comment

this is real answer to original question.
9

--if this is still relevant--

As alternative:

You can now use --build-context with Dockerfile 1.4. This allows you to reference directories outside of the Dockerfile location.

docker build -t myapp --build-context root=../../ . and then COPY --from=root myapp.war /opt/tomcat7/webapps/

1 Comment

This answer should be higher and should be the de-facto way of doing what's asked in the question. Asking to change the build context screws up everything in the Dockerfile, and you have to rewrite it again, relative to the parent directory. This brings even more problems down the road.
4

Let's say you have your directories tree like this:

dir0
├───dir1
│   └───dir11
|   |   └───dockerfile
|   └───dir12 (current)
└───dir2 (content to be copied)

and your dockerfile look like this:

FROM baseImage
COPY / /content

Let's say you want to copy dir2 content into a new docker image using COPY or ADD of dockerfile that is in dir11 and your current directory is dir12

You will have to run this command in order to build your image properly:

docker build -t image-name:tag -f ../dir11/dockerfile ../../dir2
  • -t your-image-name Name and optionally a tag in the 'name:tag' format
  • -f ../dir11/dockerfile Name of the Dockerfile (Default is 'PATH/Dockerfile')
  • ../../dir2 path to be current for COPY or ADD commands

Update

Let's say you run this by mistake:

docker build -t image-name:tag -f ../dir11/dockerfile ../../

This will not solve your problem because in this case the COPY / /content will look like it's copying dir0 content (dir1 & dir2) so in order to fix that you can either change the command using the right path or you can also change the COPY source path in the dockerfile like this:

COPY /dir2 /content

Comments

2

If you are using skaffold, use 'context:' to specify context location for each image dockerfile - context: ../../../

            apiVersion: skaffold/v2beta4
            kind: Config
            metadata:
                name: frontend
            build:
                artifacts:
                    - image: nginx-angular-ui
                      context: ../../../
                      sync:
                          # A local build will update dist and sync it to the container
                          manual:
                              - src: './dist/apps'
                                dest: '/usr/share/nginx/html'
                      docker:
                          dockerfile: ./tools/pipelines/dockerfile/nginx.dev.dockerfile
                    - image: webapi/image
                      context: ../../../../api/
                      docker:
                          dockerfile: ./dockerfile
            deploy:
                kubectl:
                    manifests:
                        - ./.k8s/*.yml

skaffold run -f ./skaffold.yaml

Comments

2

You should not do this bcs the idea is for the build to be portable but if you must:

Instruct Docker to set context: to the parent folder. For example if you have a Documents parent folder with /ssl and /my-proj subfolders you could instruct Docker to copy ssl files to the container like this:

This Docker compose file would be at Documents/my-proj/compose.yaml.

  nginx:
    build:
      context: ../
      dockerfile_inline: |
        FROM nginx:latest
        WORKDIR /etc/nginx
        COPY /ssl/example.com/certificate.crt ssl/
        COPY /ssl/example.com/private.key ssl/
    container_name: nginx
    restart: unless-stopped
    ports: [80:80,443:443,59840:59840]
    volumes:
      - $NGINX_CONF_FILEPATH:/etc/nginx/conf.d/default.conf

Comments

2

As some others have pointed out, you could use context: ../, here is a full example:

Directory structure

.
├── docker
│   ├── Dockerfile
│   └── docker-compose.yaml
└── go.mod

docker-compose.yaml

version: '3.1'

services:
  golang:
    build:
      context: ../
      dockerfile: docker/Dockerfile
    ports:
      - '80:80'

Dockerfile

FROM golang:1.18.3

WORKDIR /app
COPY . .

# RUN some-stuff

And then from the root directory run:

docker-compose -f docker/docker-compose.yaml up --build

Comments

1
  • build the img from an upper dir

  • name the img

  • enable proper volume sharing

  • check the Makefile in the link above on how-to start the container ...

    docker build . -t proj-devops-img --no-cache --build-arg UID=$(shell id -u) --build-arg GID=$(shell id -g) -f src/docker/devops/Dockerfile
    

Comments

0

The solution for those who use composer is to use a volume pointing to the parent folder:

#docker-composer.yml

foo:
  build: foo
  volumes:
    - ./:/src/:ro

But I'm pretty sure the can be done playing with volumes in Dockerfile.

1 Comment

It can't. Note: The host directory is, by its nature, host-dependent. For this reason, you can’t mount a host directory from Dockerfile because built images should be portable. A host directory wouldn’t be available on all potential hosts. docs.docker.com/engine/tutorials/dockervolumes/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.