If you bind-mount a non-existent file (on the host), docker will happily create a directory in its place and share it with the container. Upon "fixing" the mistake, (ie, stopping the container, replacing the directory with the file and starting the container), you'll get the following error:
docker: Error response from daemon: oci runtime error: container_linux.go:262: starting container process caused "process_linux.go:339: container init caused "rootfs_linux.go:57: mounting "[snip]" to [snip]" at "[snip]" 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.
Here are some steps to reproduce from a console:
# ensure test file does not exist
$ rm -f /test.txt
# run hello-world container with test.txt bind mount
$ docker run --name testctr -v /test.txt:/test.txt hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
<snip>
# let's say what's in /
$ ls -l /
<snip>
dr-xr-xr-x 13 root root 0 Jul 17 01:08 sys
drwxr-xr-x 2 root root 4096 Jul 22 20:54 test.txt
drwxrwxrwt 1 root root 4096 Jul 17 09:01 tmp
<snip>
# let's correct the mistake and run the container again
$ rm -rf /test.txt
$ touch /test.txt
$ docker start testctr
Error response from daemon: OCI runtime create failed: container_linux.go:348: starting
container process caused "process_linux.go:402: container init caused \"rootfs_linux.go:58:
mounting \\\"/test.txt\\\" to rootfs \\\"/var/lib/docker/overlay2/
26fd6981e919e5915c31098fc74551314c4f05ce6c5e175a8be6191e54b7f807/merged\\\" at \\\"/var/lib/
docker/overlay2/26fd6981e919e5915c31098fc74551314c4f05ce6c5e175a8be6191e54b7f807/merged/
test.txt\\\" caused \\\"not a directory\\\"\"": unknown: 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
Error: failed to start containers: testctr
Note that even though we get this error when starting the existing container, creating a new one actually works.
So my question is, how do I fix this? I can see two different possibilities:
docker run ...
) into a variable (?)PS: This question is also supposed to fix this one.
Two options for generating docker run ...
for existing containers:
assaflavie/runlike - I went with this since the other seemed to have some issues with labels (but this one doesn't support bulk inspection)
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike <container>
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock nexdrew/rekcod <container>
The final script would look like (untested):
# get names of running containers (names persist recreation)
running_containers=$(docker ps --format "{{.Names}}")
# stop running containers
docker stop $running_containers
# generate recreate script
containers=$(docker ps --all --format "{{.Names}}")
echo '#!/bin/sh' > ./recreate.sh
while read -r cname; do
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock assaflavie/runlike "$cname" >> ./recreate.sh
done <<< "$containers"
chmod +x ./recreate.sh
# ... do some action now (maybe also manually check recreate script) ...
# recreate containers
docker rm --force $containers
./recreate.sh
# restart containers that were previously running
docker start $running_containers
This seems to tackle my needs, but a few people noted that these tools might miss a docker feature or might even contain bugs (I noticed this already with rekcod, for example), so use with caution.