Docker-compose and file volume mounts


Can’t quite believe I’m the first to ask this, but I can’t find anything relevant on a search of the history.

I’m having some difficulties with a fairly straightforward node app. I’m trying to build it in a docker executor. Because docker volume mounts don’t play nicely with node_modules at the best of times, I’m mounting a file as a volume in my docker-compose.yaml. The relevant bit looks like this:

version: "3"
      - "./src:/app/src"
      - "./spec:/app/spec"
      - "./npm-package:/app/npm-package"
      - "./jest.config.js:/app/jest.config.js"

Note that the final volume listed is a file, not a directory.

When I run my build step, I get this error:

ERROR: for my-shiny-koa-test  Cannot start service web: oci runtime error: container_linux.go:265: starting container process caused "process_linux.go:368: container init caused \"rootfs_linux.go:57: mounting \\\"/home/circleci/project/jest.config.js\\\" to rootfs \\\"/var/lib/docker/overlay2/b3e1d109078ef7679cac836dae1d60f90f3b508914ede873db91ee5e023720bf/merged\\\" at \\\"/var/lib/docker/overlay2/b3e1d109078ef7679cac836dae1d60f90f3b508914ede873db91ee5e023720bf/merged/app/jest.config.js\\\" caused \\\"not a directory\\\"\""
: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

Now, I know that I’m not trying to mount a directory onto a file or vice versa. The file jest.config.js definitely exists, and is a file, not a directory, in both host and post-build container. So, I rerun the failing step with SSH to have a poke around. If I ssh remote-docker from the runner, and ls -l project, I see this:

circleci@default-139481f6-11da-427e-abbc-2e587bc031b3:~$ ls -l project
total 16
drwxr-xr-x 2 root root 4096 Nov  1 16:09 jest.config.js
drwxr-xr-x 2 root root 4096 Nov  1 16:09 npm-package
drwxr-xr-x 2 root root 4096 Nov  1 16:09 spec
drwxr-xr-x 2 root root 4096 Nov  1 16:09 src

For some reason, jest.config.js has been created in the remote-docker environment as a directory. That would explain why docker-compose won’t mount it over a file, but why is it doing that? And, more importantly, how do I make it stop? I can’t rmdir jest.config.js in the remote-docker because it’s owned by root.

For my purposes I don’t care about the contents of the file on the host, so if there was a way to avoid doing the volume mounts at all, I’d do that. I’m trying not to alter the docker-compose.yaml file though so there’s a single source of truth for how to bring up the application.

Hi @regularfry

We’ve also come up against this recently and found in the CircleCI docs that mounting volumes is not possible (I guess because everything is mounted as a dir).

Those docs do suggest a way around it by creating an intermediate container with your configs and then use --from-volumes when running a container. I’m trying to get that to work when using a docker-compose file, but no luck so far.

I’ve seen those docs, but that’s not quite what I’m trying to do. I don’t care about mounting from the job space into remote docker. I think the reason that doesn’t work isn’t because things are mounted as a dir, it’s because the job space doesn’t export a filesystem that the remote docker can see.

What it looks like to me is that the remote docker setup is cludging enough of the filesystem into place from a naive reading of the docker-compose.yaml that most of the time docker-compose can get away with it, but (and this is a total guess) they’re acting at a point in the process where they don’t have access to the checkout so they can’t tell what’s file and what’s directory from the paths given.

I suspect the only way to get this to properly work will be to move the config into a directory and mount that. Not ideal, but workable.