Anthony O.
Anthony O.

Reputation: 24477

Docker: adding a file from a parent directory

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?

Upvotes: 573

Views: 545503

Answers (16)

Irfanullah Jan
Irfanullah Jan

Reputation: 3902

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
...

Upvotes: 19

ruloweb
ruloweb

Reputation: 764

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

Upvotes: 1

Andre Haverdings
Andre Haverdings

Reputation: 917

--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/

Upvotes: 6

mbarthelemy
mbarthelemy

Reputation: 12913

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.

Upvotes: 204

teastburn
teastburn

Reputation: 3508

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/

Upvotes: 22

Ronnie Smith
Ronnie Smith

Reputation: 18585

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

Upvotes: 2

lfarroco
lfarroco

Reputation: 624

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

Upvotes: 13

Trong Nguyen
Trong Nguyen

Reputation: 109

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

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

Upvotes: 10

Boedy
Boedy

Reputation: 7783

  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

Upvotes: 658

Nikita Kuznetsov
Nikita Kuznetsov

Reputation: 2987

With docker-compose, you could set context folder:

# docker-compose.yml

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

Upvotes: 290

Affes Salem
Affes Salem

Reputation: 1649

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

Upvotes: 4

Yordan Georgiev
Yordan Georgiev

Reputation: 5460

  • 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
    

Upvotes: 1

Sukhminder Sandhu
Sukhminder Sandhu

Reputation: 915

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

Upvotes: 2

wikier
wikier

Reputation: 2576

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.

Upvotes: 0

Binita Bharati
Binita Bharati

Reputation: 5918

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 .

Upvotes: 50

guneysus
guneysus

Reputation: 6502

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

Upvotes: 18

Related Questions