Reputation: 5646
I have the following setup.
Folder structure
solution-root
├── docker-compose.yml
├── project1
│ ├── Dockerfile
│ ├── sub1
│ │ ├── ...loads of stuff...
│ ├── sub2
│ │ ├── ...more stuff...
├── project2
│ ├── Dockerfile
│ ├── sub1
│ │ ├── ...more stuff...
│ ├── sub2
│ │ ├── ...even more stuff...
├── project-db
│ ├── Dockerfile
docker-compose.yml
version: '3'
services:
project1:
build:
context: ./project1
dockerfile: Dockerfile
...
project2:
build:
context: ./project2
dockerfile: Dockerfile
...
project-db:
build:
context: ./project-db
dockerfile: Dockerfile
...
...
project-db/Dockerfile
FROM mysql:5.7
COPY ../project1/app/seeders /seeders/
COPY ../project2/app/seeders /seeders/
Obviously, I want to copy files from another sibling folder because this project-db
needs them.
So, when I run docker-compose build I am presented with this error:
Service 'project-db' failed to build: COPY failed: Forbidden path outside the build context: ../project1/app/seeders
Ok, I get it, context does not allow me to level up. Let's move context to root then and then run project/Dockerfile from there.
docker-compose.yml
project-db:
build:
context: .
dockerfile: ./project-db/Dockerfile
...
Now we can copy files that we need.
project-db/Dockerfile
COPY project1/app/seeders /seeders/
COPY project2/app/seeders /seeders/
And now all is well(ish) with docker-compose build
.
BUT there is a problem - building project-db lasts quite some time. And that means every time it's being run. I guess that it's due to the fact that now the context of the project-db
is the entire folder structure.
So, I tried with .dockerignore
to filter out unneeded folders:
.dockerignore
project3
project3/**
project4
project4/**
project5
project5/**
...
But nothing removes that lag.
I can't get this to work properly. Also - I can't fiddle with the internal structures of the existing projects.
What is wrong here?
Upvotes: 3
Views: 4317
Reputation: 1326
As the author correctly pointed out, volumes are used for persisting data. Here I want to show two solutions, on how to use them for sharing data between container. This solution is far from being perfect!
First, I want to point out the downsides of this solution.
docker-compose down -v
must be done, if some files in the project-directories have changed.docker-compose down -v`` is to manually delete the named volumes using
docker volume rm ``.COPY
the files to a folder (which is not a mounted volume, e. g. /tmp
). Using an entrypoint script you can than copy the files to its intended position (e. g. /home/developer/
). See Solution 2 for this.My folder structure looks similar to yours:
├── docker-compose.yaml
├── project1
│ ├── Dockerfile
│ ├── entrypoint.sh
│ ├── sub1
│ │ ├── testfile_project_1_1.txt
│ │ └── testfile_project_1_2.txt
│ └── sub2
│ └── testfile_project_1_3.txt
├── project2
│ ├── Dockerfile
│ ├── entrypoint.sh
│ ├── sub1
│ │ └── testfile_project_2_1.txt
│ └── sub2
│ ├── testfile_project_2_2.txt
│ ├── testfile_project_2_3.txt
│ ├── testfile_project_2_4.txt
│ └── testfile_project_2_5.txt
└── project-db
├── Dockerfile
└── entrypoint.sh
version: "3.8"
services:
first-service:
build:
context: ./project1
dockerfile: Dockerfile
volumes:
- data-first-service:/home/developer/
second-service:
build:
context: ./project2
dockerfile: Dockerfile
volumes:
- data-second-service:/home/developer/
databse-service:
build:
context: ./project-db
dockerfile: Dockerfile
volumes:
- data-first-service:/home/developer/project1/
- data-second-service:/home/developer/project2/
depends_on:
- first-service
- second-service
volumes:
data-first-service:
data-second-service:
They are pretty much the same. The dockerfile for the* db-service* only copies it's entrypoint-script. The part with the sudoers
is here, because this is my default testing image. I just included it to make clear which permissions my user has and to make passwordless sudo
with regular user possible. It is not mandatory.
FROM ubuntu:latest
# We need some tools
RUN apt-get update && apt-get install -y sudo
# We want to have another user than `root`
## USER SETUP
RUN adduser developer
# We want to have passwordless sudo access
RUN \
sed -i /etc/sudoers -re 's/^%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
sed -i /etc/sudoers -re 's/^root.*/root ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
sed -i /etc/sudoers -re 's/^#includedir.*/## **Removed the include directive** ##"/g' && \
echo "developer ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers; su - developer -c id
# Run now with user developer
USER developer
COPY sub1 /home/developer/sub1
COPY sub2 /home/developer/sub2
RUN ls -l
ADD ./entrypoint.sh /entrypoint.sh
RUN sudo chmod +x /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
The entrypoints for the two projects are not special, they just contain a simple ls -l
to /home/developer
.
The entrypoint for the* db-service* just shows a tree
output (see Results):
#!/bin/bash
cd ~
echo "db service - You are here: ${PWD} "
tree --du -shaC | grep -Ev '( *[^ ]* ){5}\['
As you can see, the project-db
container now contains the files from the other two projects.
databse-service_1 | .
databse-service_1 | |-- [ 220] .bash_logout
databse-service_1 | |-- [3.7K] .bashrc
databse-service_1 | |-- [ 807] .profile
databse-service_1 | |-- [ 17K] project1
databse-service_1 | | |-- [ 220] .bash_logout
databse-service_1 | | |-- [3.7K] .bashrc
databse-service_1 | | |-- [ 807] .profile
databse-service_1 | | |-- [4.0K] sub1
databse-service_1 | | | |-- [ 0] testfile_project_1_1.txt
databse-service_1 | | | `-- [ 0] testfile_project_1_2.txt
databse-service_1 | | `-- [4.0K] sub2
databse-service_1 | | `-- [ 0] testfile_project_1_3.txt
databse-service_1 | `-- [ 17K] project2
databse-service_1 | |-- [ 220] .bash_logout
databse-service_1 | |-- [3.7K] .bashrc
databse-service_1 | |-- [ 807] .profile
databse-service_1 | |-- [4.0K] sub1
databse-service_1 | | `-- [ 0] testfile_project_2_1.txt
databse-service_1 | `-- [4.0K] sub2
databse-service_1 | |-- [ 0] testfile_project_2_2.txt
databse-service_1 | |-- [ 0] testfile_project_2_3.txt
databse-service_1 | |-- [ 0] testfile_project_2_4.txt
databse-service_1 | `-- [ 0] testfile_project_2_5.txt
databse-service_1 |
databse-service_1 | 42K used in 6 directories, 17 files
As said, this method has some downside. You need to class a docker-compose down
in order to make this solution work.
So, the workflow looks similar to this:
docker-compose build && docker-compose up
.
If you change a file in one of the project-directories or if you want to update the content ud must call docker-compose down -v
, otherwise it will still reuse the pre-populated content from the old volumes.
Basically, it’s the same as Solution 1. The difference is, that the “project-containers” first cop the sources to a temporal location and after the container has been started (and the volume is mounted) to the path where the volume is mounted.
Just minor changed for this solution
[...]
# Run now with user developer
USER developer
COPY sub1 /tmp/sub1
COPY sub2 /tmp/sub2
RUN ls -l
ADD ./entrypoint.sh /entrypoint.sh
RUN sudo chmod +x /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
and the entrypoint looks loke this
#!/bin/bash
mv /tmp/sub1 /home/developer/sub1
mv /tmp/sub2 /home/developer/sub1
# Then do your stuff
Upvotes: 1