I’m learning Docker and I’m facing the following issue, mainly related to sharing files between services. I’ve prepared an illustration:
I have 3 stages in my Dockerfile
: builder, php and caddy. My docker-compose.yml
defines 2 services: php and caddy (the target is the correspoding stage in the Dockerfile
). Requirements:
- builder stage produces some files needed by php service at runtime (i.e.
public/build/metatada.json
) - builder stage produces some files needed by caddy service at runtime (i.e.
public/js/foo.js
) - php stage produces some files that should be available to caddy service at runtime (i.e.
public/bundles/foo.js
) - caddy service must share
public/
folder with php service, because new files can be created (i.e. userpublic/uploads/newfile.pdf
) - New static files in source code must be taken into account (i.e.
public/img/newimage.png
)
Solution 1: my first naive solution won’t work because point 4: caddy service can’t access resources created by the php services at runtime (i.e. public/uploads/new.png
):
FROM node:current-alpine as builder
WORKDIR /app
COPY . .
RUN npm run build
FROM php:fpm-latest as php
COPY . .
COPY --from=builder /app/public/ public/
FROM caddy:latest as caddy
WORKDIR /srv
COPY --from=builder /app/public/ public/
Solution 2: bind mount source code public
folder to caddy /srv/public
and php /var/www/html/public
folder. This solves 4 and 5, but completely wipes the builder output so points 1, 2, 3 are not respected.
Which other option I have? I already tried to share a volume (see my other SO question) but it won’t work either.
2
Answers
Forgive me if I’m also being naive with this approach, I have read your other question as well. Just a suggestion to try.
Could you not keep both public folder’s contents elsewhere in the container, use solution 2 and load the container’s public folder contents after boot using the entrypoint script in each container, if a certain file can’t be found? That way nothing is obscured by the bind and you still have all the files.
Something like:
entrypoint.sh
Where
/apptmp/public
contains the files generated during the build process and/app/public
is the mounted directory.(I used
while
butif
is fine too).EDIT: If the files are needed at runtime you can script a wait into the entrypoints as well.
I am not sure if it will work but you could try the following.
The main idea is try using some kind of initialization container in your docker compose setup.
I mean, in addition to the php and caddy containers, you will use a third one.
This third container will be responsible for initializing the different resources required by the rest of containers in your setup,
php
andcaddy
.The following
docker-compose
file definition try illustrating the concept:I am not used to work with
php
and I based this compose file in this related SO question: please, forgive me for any inaccuracy.It is very important to note that in order to make the final application work properly the same volume is used. Please, review the different mounts points in the different containers and make it point to the right locations.
The build for the
init-assets
container can be performed with a Dockerfile very similar to the one you proposed in your first solution: just be sure to change the final caddy container entry point to something that exists the container.This approach is typically used for performing the initial setup of databases as in the case of airflow and as described here in SO too, but I think it could be of help in your use case as well.
As I said, they are just ideas but I hope that with minor tweaks they will make your application work properly.