I have the following file structure:
my-app
├── docker-compose.dev.yml
├── ui (React)
│ ├── src
│ ├── .dockerignore
│ ├── Dockerfile.dev
│ ├── package.json
│ ├── package-lock.json
├── api (Node)
│ ├── src
│ ├── .dockerignore
│ ├── Dockerfile.dev
│ ├── package.json
│ ├── package-lock.json
├── server (Nginx)
│ ├── Dockerfile.dev
│ ├── nginx.dev.conf
ui/Dockerfile.dev
FROM node:lts
WORKDIR /ui
COPY package.json .
COPY package-lock.json .
RUN npm install
EXPOSE 3000
CMD ["npm", "start"]
api/Dockerfile.dev
FROM node:lts
WORKDIR /api
COPY package.json .
COPY package-lock.json .
RUN npm install
EXPOSE 8080
CMD ["npm", "run", "dev"]
.dockerignore (It’s the same for ui and api)
node_modules
build
.dockerignore
Dockerfile
Dockerfile.prod
docker-compose.dev.yml
version: "3.8"
services:
ui:
build:
context: ./ui
dockerfile: Dockerfile.dev
image: my-app-ui
volumes:
- ./ui:/ui
- ./ui/node_modules
ports:
- "3000:3000"
tty: true
api:
build:
context: ./api
dockerfile: Dockerfile.dev
image: my-app-api
env_file:
- ./api.env
ports:
- "8080"
server:
build:
context: ./server
dockerfile: Dockerfile.dev
image: my-app-server
ports:
- "80:80"
links:
- api:api
- ui:ui
When I run this with docker-compose -f docker-compose.dev.yml up
the ui has live-reloads although an empty node_modules folder is generated at my-app/ui/
that gets populated with another .cache folder whenever the development server restarts. The order of the volumes at the ui service is the only way it works and if I don’t add ./ui/node_modules
I get an error saying that the package react-scripts was not found. I don’t know why this works the way it does or even at all. As far as I understand it the short syntax for volume declaration uses the colon to separate between the source, which can be either a host path or a name for the volume, and the target, which is the container path where the volume is mounted. This makes me think that the first volume is mounting the contents of my-app/ui/
on the container’s /ui/
path. Shouldn’t this be enough to abilitate live-reloads? Why do I need to add ./ui/node_modules
after that for the container to be able to run scripts dependant on packages? I don’t have a node_modules folder on my-app/ui/
, I’m installing the dependencies from that Dockerfile. What is it even doing? Is it just specifying a path and letting the Engine create a volume, like the docs suggest?
There’s more: when I declare volumes for the api service like I did with ui:
api:
build:
context: ./api
dockerfile: Dockerfile.dev
image: snake-api
env_file:
- ./api.env
volumes:
- ./api:/api
- ./api/node_modules
ports:
- "8080"
Both containers fail to start and these errors are thrown:
ERROR: for ui Cannot start service ui: OCI runtime create failed: container_linux.go:349: starting container process caused “process_linux.go:449: container init caused “rootfs_linux.go:58: mounting \”/var/lib/docker/volumes/1cbe57d474e441fc67073878f45647a08db5c2b774d9b93c7fa4c583ea4ab229/_data\” to rootfs \"/var/lib/docker/overlay2/0c864fb070cec3c96ed46d16219047aa5875e84fbde77415d4f1dd6590e160dd/merged\" at \"/var/lib/docker/overlay2/0c864fb070cec3c96ed46d16219047aa5875e84fbde77415d4f1dd6590e160dd/merged/ui/node_modules\" caused \“mkdir /var/lib/docker/overlay2/0c864fb070cec3c96ed46d16219047aa5875e84fbde77415d4f1dd6590e160dd/merged/ui/node_modules: file exists\”"": unknown
ERROR: for api Cannot start service api: OCI runtime create failed: container_linux.go:349: starting container process caused “process_linux.go:449: container init caused “rootfs_linux.go:58: mounting \”/var/lib/docker/volumes/9257238f321f1fc9705e3a194f99c8bd15846978645548ec7d887dd8c90f90d7/_data\” to rootfs \"/var/lib/docker/overlay2/4f48404c5f6134d8e3592576ccccd2404306b1ac1dada65691686950049beb06/merged\" at \"/var/lib/docker/overlay2/4f48404c5f6134d8e3592576ccccd2404306b1ac1dada65691686950049beb06/merged/api/node_modules\" caused \“mkdir /var/lib/docker/overlay2/4f48404c5f6134d8e3592576ccccd2404306b1ac1dada65691686950049beb06/merged/api/node_modules:
file exists\”"": unknown
UNLESS I first create an empty node_modules folder on each directory (my-app/ui/
and my-app/api/
) or, at least, on the api. Doing this makes both services start and allows live-reloading. Forgetting to create that folder on the ui causes it to crash and throw the error above but forgetting to create it on the api will make it print that nodemon was not found, an error similar to the one I experience on the ui when I don’t add ./ui/node_modules
. What is happening?