Reputation: 2866
I've been attempting to solve this problem for what seems like an eternity, but it seems as though Docker for Windows has only recently been able to successfully bind volumes from the Windows host to its Docker containers. However, I'm unable to get the same functionality working via docker-compose
. Does anyone have any definitive information surrounding this, or thoughts on how I might go about getting this to work?
I have read a painful amount of GitHub issues about Windows volume mounting, but it seems as though most of the answers are related to getting Docker to mount the volume. I'm having no issues there, just docker-compose
.
To illustrate my issue, the following command gives me the following output, which is the correct contents of my local directory, mounted in Docker:
$ docker run --rm -v c:/Users/synta/go/src/github.com/syntaqx/example:/go/src/github.com/syntaqx/example alpine ls /go/src/github.com/syntaqx/example
LICENSE
README.md
cmd
docker-compose.yml
docs
go.mod
go.sum
example.go
However, given the same implementation within a docker-compose.yml
:
version: '3.6'
services:
example:
build:
context: .
dockerfile: Dockerfile
volumes:
- /c/Users/syntaqx/go/src/github.com/syntaqx/example:/go/src/github.com/syntaqx/example
And the following Dockerfile
:
ARG GO_VERSION=1.11
ARG ALPINE_VERSION=3.8
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder
WORKDIR /go/src/github.com/syntaqx/example
RUN ls -alh
ENTRYPOINT ["go"]
I'm given literally no output (ls -alh
gives .
and ..
, letting me know the directory is definitely there via WORKDIR
, but not populated from the binding):
$ docker-compose up -d --build
Building example
Step 1/6 : ARG GO_VERSION=1.11
Step 2/6 : ARG ALPINE_VERSION=3.8
Step 3/6 : FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder
---> be1230a1b343
Step 4/6 : WORKDIR /go/src/github.com/syntaqx/example
---> Using cache
---> a0ccb401a86a
Step 5/6 : RUN ls /go/src/github.com/syntaqx/example
---> Running in 0cd52d44a637
Removing intermediate container 0cd52d44a637
---> 4f362f738e49
Step 6/6 : ENTRYPOINT ["go"]
---> Running in 5d7a1e841bfe
Removing intermediate container 5d7a1e841bfe
---> 9da9cfcf372a
...
Perhaps I'm missing something obvious here, but I've tried a dozen ways of expressing the volume PATH (.
, C:\
, /c/
, ///c
), with relative paths apparently being very broken in Docker Windows, and the other paths not changing the result.
Also very sorry if this is a duplicate, but from what I've seen, most other questions are very specifically trying to mount host volumes in Docker, period. Or, the issue with relative paths, which I'm happy to side step for the time being. To repeat, all of that is working fine for me as shown in my example, just docker-compose
seems broken.
Hope one of you guys can help me! Feeling very out of my depth here.
Upvotes: 2
Views: 1900
Reputation: 2866
But, I learned something: I actually had a fundamental misunderstanding of how volume mounts work within Docker. To my surprise, everything, including relative volume paths are working as expected.
The fundamental misunderstanding I had for volume mounts is that they are not available during build steps, but the mount is attached to the final container. Docker imposes this requirement, as without it, builds would not be repeatable.
So, in the usecase I provided above, the only difference (albeit not obvious until I understood this) between the Dockerfile
and the docker run
command, is that my Dockerfile
is actively building a container, and attempting to execute commands, where the docker run
is only running the command on the prebuilt alpine
.
So, is it possible to do what I was doing? Sort of
I ran into a couple of cheese solutions that utilize a decorator-ish entrypoint.sh
chaining pattern, allowing you to chain multiple Dockerfile
build outputs into their final container, and when it's run, executes chained commands before the given CMD
. Simply put, you have a bunch of dockerfiles that all end with ENTRYPOINT ["entrypoint.sh"]
, and then outline the steps you would previously leverage RUN
for:
#!/bin/sh
set -eu
until /go/src/github.com/syntaqx/example && go mod download
do
echo "Waiting for mount..."
done
sh -c "go $*"
Then, you can have each dockerfile shove commands on top of the last one.
Note: I did not end up using this once, as I describe below, so this shell may not work, but I thought it was a cool implementation thought, so I wanted to nod to it.
However, for my use case, all of this was very unnecessary. Knowing why the commands are failing, I'm I'm able to simply defer the RUN
commands until the final ENTRYPOINT
, create a singular entrypoint.sh
, and then run them in the order I wanted during the build. I don't benefit from dependency caching this way, but I also don't need it for this particular use case.
Thanks for reading, and I hope you learned something too!
Upvotes: 4