Description
I am using Docker version 1.12.5 on Windows 10 via Hyper-V and want to use container executables as commands in the current path. I built a Docker image that is running fine, but I have a problem to mount the current path. The idea is to create an alias and do a docker run --rm [...] command so that it could be used system-wide in the current directory.
Setup
I have a drive E with a folder "test" and in there a folder called "folder on windows host" to show that the command is working. The Dockerfile create the directory /data, defines it as VOLUME and WORKDIR.
Having E:\test as the current directory in PowerShell and executing the Docker command with an absolute path, I can see the content of E:\test:
PS E:\test> docker run --rm -it -v E:\test:/data mirkohaaser/docker-clitools ls -la
total 0
drwxr-xr-x 2 root root 0 Jan 4 11:45 .
drwxr-xr-x 2 root root 0 Jan 5 12:17 folder on windows host
Problem
I want to use the current directory and not an absolute notation. I could not use pwd in the volume because of different error messages:
Trying with ($pwd)
PS E:\test> docker run --rm -it -v ($pwd):/data mirkohaaser/docker-clitools ls -la
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error parsing reference: ":/data" is not a valid repository/tag.
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
Trying with /($pwd)
PS E:\test> docker run --rm -it -v /($pwd):/data mirkohaaser/docker-clitools ls -la
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error parsing reference: "E:\\test" is not a valid repository/tag.
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
Trying with \´pwd\´
PS E:\test> docker run --rm -it -v ´$pwd´:/data mirkohaaser/docker-clitools ls -la
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: Invalid bind mount spec "´E:\\test´:/data": invalid mode: /data.
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
Trying with `pwd`
PS E:\test> docker run --rm -it -v `$pwd`:/data mirkohaaser/docker-clitools ls -la
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: create $pwd: "$pwd" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed.
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
What is the correct syntax of mounting the current directory as a volume in Docker on Windows 10?
In Windows Command Line (cmd), you can mount the current directory like so:
docker run --rm -it -v %cd%:/usr/src/project gcc:4.9
In PowerShell, you use ${PWD}, which gives you the current directory:
docker run --rm -it -v ${PWD}:/usr/src/project gcc:4.9
On Linux:
docker run --rm -it -v $(pwd):/usr/src/project gcc:4.9
Cross Platform
The following options will work on both PowerShell and on Linux (at least Ubuntu):
docker run --rm -it -v ${PWD}:/usr/src/project gcc:4.9
docker run --rm -it -v $(pwd):/usr/src/project gcc:4.9
This works for me in PowerShell:
docker run --rm -v ${PWD}:/data alpine ls /data
Command prompt (Cmd.exe)
When the Docker CLI is used from the Windows Cmd.exe, use %cd% to mount the current directory:
echo test > test.txt
docker run --rm -v %cd%:/data busybox ls -ls /data/test.txt
Git Bash (MinGW)
When the Docker CLI is used from the Git Bash (MinGW), mounting the current directory may fail due to a POSIX path conversion: Docker mounted volume adds ;C to end of windows path when translating from linux style path.
Escape the POSIX paths by prefixing with /
To skip the path conversion, POSIX paths have to be prefixed with the slash (/) to have leading double slash (//), including /$(pwd)
touch test.txt
docker run --rm -v /$(pwd):/data busybox ls -la //data/test.txt
Disable the path conversion
Disable the POSIX path conversion in Git Bash (MinGW) by setting MSYS_NO_PATHCONV=1 environment variable at the command level
touch test.txt
MSYS_NO_PATHCONV=1 docker run --rm -v $(pwd):/data busybox ls -la /data/test.txt
or shell (system) level
export MSYS_NO_PATHCONV=1
touch test.txt
docker run --rm -v $(pwd):/data busybox ls -la /data/test.txt
Open Settings on Docker Desktop (Docker for Windows).
Select Shared Drives.
Select the drive that you want to use inside your containers (e.g., C).
Click Apply. You may be asked to provide user credentials.
The command below should now work on PowerShell (command prompt does not support ${PWD}):
docker run --rm -v ${PWD}:/data alpine ls /data
IMPORTANT: if/when you change your Windows domain password, the mount will stop working silently, that is, -v will work but the container will not see your host folders and files. Solution: go back to Settings, uncheck the shared drives, Apply, check them again, Apply, and enter the new password when prompted.
For Git Bash for Windows (in ConEmu), the following works for me (for Docker Windows containers):
docker run --rm -it -v `pwd -W`:c:/api microsoft/dotnet:2-runtime
Note the backticks/backquotes around pwd -W!
With all other variations of PWD I've tried I've received: "Error response from daemon: invalid volume specification: ..."
Update:
The above was for Docker Windows containers, for Linux containers use:
docker run --rm -it -v `pwd -W`:/api -p 8080:80 microsoft/aspnetcore:2
Here is mine which is compatible for both Win10 docker-ce & Win7 docker-toolbox. At las at the time I'm writing this :).
You can notice I prefer use /host_mnt/c instead of c:/ because I sometimes encountered trouble on docker-ce Win 10 with c:/
$WIN_PATH=Convert-Path .
#Convert for docker mount to be OK on Windows10 and Windows 7 Powershell
#Exact conversion is : remove the ":" symbol, replace all "\" by "/", remove last "/" and minor case only the disk letter
#Then for Windows10, add a /host_mnt/" at the begin of string => this way : c:\Users is translated to /host_mnt/c/Users
#For Windows7, add "//" => c:\Users is translated to //c/Users
$MOUNT_PATH=(($WIN_PATH -replace "\\","/") -replace ":","").Trim("/")
[regex]$regex='^[a-zA-Z]/'
$MOUNT_PATH=$regex.Replace($MOUNT_PATH, {$args[0].Value.ToLower()})
#Win 10
if ([Environment]::OSVersion.Version -ge (new-object 'Version' 10,0)) {
$MOUNT_PATH="/host_mnt/$MOUNT_PATH"
}
elseif ([Environment]::OSVersion.Version -ge (new-object 'Version' 6,1)) {
$MOUNT_PATH="//$MOUNT_PATH"
}
docker run -it -v "${MOUNT_PATH}:/tmp/test" busybox ls /tmp/test
Other solutions for Git Bash provided by others didn't work for me. Apparently there is currently a bug/limitation in Git for Windows. See this and this.
I finally managed to get it working after finding this GitHub thread (which provides some additional solutions if you're interested, which might work for you, but didn't for me).
I ended up using the following syntax:
MSYS_NO_PATHCONV=1 docker run --rm -it -v $(pwd):/usr/src/project gcc:4.9
Note the MSYS_NO_PATHCONV=1 in front of the docker command and $(pwd) - round brackets, lower-case pwd, no quotes, no backslashes.
Also, I'm using Linux containers on Windows if that matters..
I tested this in the new Windows Terminal, ConEmu and GitBash, and all of them worked for me.
This command should fix it.
docker run --rm -it -v ${PWD}:c:\data mirkohaaser/docker-clitools
{PWD} is the host current folder. after the : is the container folder.
If the mounting is correct then files will be listed in the director c:\data in the container.
You need to swap all the back slashes to forward slashes
so change
docker -v C:\my\folder:/mountlocation ...
to
docker -v C:/my/folder:/mountlocation ...
I normally call docker from a cmd script where I want the folder to mount to be relative to the script i'm calling so in that script I do this...
SETLOCAL
REM capture the path to this file so we can call on relative scrips
REM without having to be in this dir to do it.
REM capture the path to $0 ie this script
set mypath=%~dp0
REM strip last char
set PREFIXPATH=%mypath:~0,-1%
echo "PREFIXPATH=%PREFIXPATH%"
mkdir -p %PREFIXPATH%\my\folder\to\mount
REM swap \ for / in the path
REM because docker likes it that way in volume mounting
set PPATH=%PREFIXPATH:\=/%
echo "PPATH=%PPATH%"
REM pass all args to this script to the docker command line with %*
docker run --name mycontainername --rm -v %PPATH%/my/folder/to/mount:/some/mountpoint myimage %*
ENDLOCAL
If you are still having this issue in 2022, you can install docker in windows with WSL(Windows Subsystem for Linux). Then you can go on Microsoft Store and install one of the Linux project like Ubuntu, Debian or Kali Linux.
On Docker Desktop go to setting -> WSL integration
and enable your version of Linux.
On VS Code open new WSL terminal and execute the Linux command there.
If you want to pass your project directory with the DockerfileRunArguments property to your debug container, then pwd won't work.
<PropertyGroup>
<!-- Will result in `` -->
<DockerfileRunArguments>-v "$(pwd):/data:ro"</DockerfileRunArguments>
</PropertyGroup>
Use $(MSBuildProjectDirectory) instead of $(pwd)
<PropertyGroup>
<!-- Will result in the full path to your project directory -->
<DockerfileRunArguments>-v "$(MSBuildProjectDirectory):/data:ro"</DockerfileRunArguments>
</PropertyGroup>
Reference: MSDocs - Visual Studio Container Tools
PowerShell on Windows 10 Pro
The above solutions did not work for me as plain pwd gives a description in the response:
Path
----
C:\Users\barnaby
It needs outputting as a variable in the script $(pwd) but then docker complains invalid reference format
The solution is to wrap the whole switch parameters in double quotes and this works for me:
docker run --rm -v "$(pwd):/app" php:7.4-cli php /app/hello.php
docker run --rm -v /c/Users/Christian/manager/bin:/app --workdir=/app php:7.2-cli php app.php
Git bash
cd /c/Users/Christian/manager
docker run --rm -v ${PWD}:/app --workdir=/app php:7.2-cli php bin/app.php
echo ${PWD}
result:
/c/Users/Christian/manager
cmd or PowerShell
cd C:\Users\Christian\manager
echo ${PWD}
result:
Path
---- C:\Users\Christian\manager
as we see in cmd or PowerShell $ {PWD} will not work
Normally, when finding a bind-mount path for the overlay2 driver with Docker-in-Docker, I can do it via the following:
$ docker run --rm -it --entrypoint bash \
-v /var/run/docker.sock:/var/run/docker.sock \
gcr.io/cloud-builders/docker
$ apt-get install jq -y
$ mount_point=$(docker inspect $HOSTNAME | jq -r '.[0].GraphDriver.Data.MergedDir')
$ echo "$mount_point"
/var/lib/docker/overlay2/c68a6fc53a27d6347e691a52bdd792094a7a4fdc65041b387d1ea38607ba999d/merged
$ mkdir hello && cd hello
$ echo "sample contents" > file
$ docker run --rm -it --entrypoint bash \
-v "$mount_point/hello":/hello \
-w /hello \
gcr.io/cloud-builders/docker
$ ls
# nothing
For everything besides WSL2, this will properly mount my files. However, for WSL2, it seems the bind mounts are present under a different location. If my attached WSL2 distro name is Ubuntu-22.04, I can find a list of unique IDS under /mnt/wsl/docker-desktop-bind-mounts/Ubuntu-22.04/:
$ ls /mnt/wsl/docker-desktop-bind-mounts/Ubuntu-22.04/
13a7bc88b63d361f5752d7ef3f5c96cd262ef580e6f435cced6bd10ec82842b0 692b88d87549cc6cb71d70e56b24d64d46c6e4f3b54611d635e407941a34d5da
21241f82d3c1e170eae05d87ed4fe9493165603a5f20f4decc5da0695296a22b 71329c4cc6e32171553fa81d044eb31d1a3aac52ba9376c4a99f4505c494cf5b
2af2028475f25893cbe6ae56fd41a5060323a05cf2de361ca5cd788882ab124e 9f9cdad793414edd07516ebe0fef99bea77a67d7033bcce9e6e2636fc52d206f
40072ee5313e41a68b132298796cbec4d044881a473056704dbaf45732b96709 e9b0d5f175dde593817759ef48c2ea4be074dd6fd7dde1e5ee0051f1cbbb36e7
449de67da5b95f36f74bf415852073e587a6f2f5acffecd8470687a065aa9a24 fd27f4eaa94fe2d4e43106f3751004bf816189bf06237c658a0c8e7aec6e54c8
67aa8dec46ea42423b4090c10503d733f4ff4c1eb43cb8e31f040c84cafba60c
Now, if I use a bindmount for the initial load, I can find the file as the mount point in the container, so at least I can get files relative to a mount point (but not very reliably). Run on the WSL2 host:
$ find /mnt/wsl/docker-desktop-bind-mounts/Ubuntu-22.04 -name clippy.toml
/mnt/wsl/docker-desktop-bind-mounts/Ubuntu-22.04/b7371a7ca29bc7acbea2f7cebdf0d5b452a4fadd8af16a733896e7dccbd49e3a/clippy.toml
/mnt/wsl/docker-desktop-bind-mounts/Ubuntu-22.04/0157aea7f7f54b90e62c5810422a2535f5513005a8db7001cf10c7753d3dc6fb/clippy.toml
This isn't straightforward if more than 1 container or bind mount exists with that file, however. Also, none of the hashes for the container match the Docker inspect or the hostname. Now, run on the container:
$ correct_id=b7371a7ca29bc7acbea2f7cebdf0d5b452a4fadd8af16a733896e7dccbd49e3a
$ echo $HOSTNAME
dadd6ab5f853
$ docker inspect $HOSTNAME| grep b737
# nothing
So there doesn't seem to be a reliable way to find that file. Also, for any files outside a bind mount, there doesn't seem to be a way to find their path. At least, however, the correct WSL2 bind mount location does work if passed into the container:
$ docker run --rm -it --entrypoint bash \
-v /mnt/wsl/docker-desktop-bind-mounts/Ubuntu-22.04/b7371a7ca29bc7acbea2f7cebdf0d5b452a4fadd8af16a733896e7dccbd49e3a/:"$PWD" \
-w "$PWD" gcr.io/cloud-builders/docker
$ ls
CHANGELOG.md Cargo.lock LICENSE-APACHE README.md ci crosstool-ng docker rustfmt.yml target
CODE_OF_CONDUCT.md Cargo.toml LICENSE-MIT assets clippy.toml deny.toml docs src xtask
But how do I find say, a file in the container at /hello/file, which was created inside the container run within WSL2?
I should also mention this is Docker Desktop for Windows being shared into the WSL Ubuntu distro. Docker was not installed inside the distro and then used without iptables.
So recently came across this weird case where I am trying to access file in my local dir into my container.
When I run the following command on terminal it runs fine and shows the expected list of file
docker run -it --rm -v $(pwd):/mnt/data -w /mnt/data-sink artprod.dev.abc.com/org/cli ls
But when I try to run this via makefile it shows nothing,(I run make in the same path where I run the docker cmd in the previous step)
docker-publish: build
echo "Publishing $(APP_NAME) snapshot $(VERSION)"
docker run -it --rm -v $(pwd):/mnt/data -w /mnt/data-sink artprod.dev.abc.com/org/cli ls
$(shell pwd) worked simply $(pwd) in make didnt do the shell interpolation.
I have the latest centos image for docker and the host machine is ubuntu.
i'm having some script at my host machine, with the path:
/home/username/untitled1/preReq.sh
i'm trying to execute this script, inside my centos docker.
while i'm mounting the directory of the script, i can't see anything and it appears that i'm mounting the root directory.
i'm using this command (from ~)
docker run --rm -it -v ${PWD}:/untitled1 centos
someone know how to fix it?
either use the pwd command (without caps) if you're in the directory:
docker run --rm -it -v ${pwd}:/untitled1 centos
or use $HOME environment variable if you're running with that user:
docker run --rm -it -v ${HOME}:/untitled1 centos
I would suggest
docker run --rm -it -v `pwd`:/untitled1 centos
At least that works for me.
${X}
evaluates the environment variable X. PWD is typically set by your shell:
$ export
[...]
declare -x PWD="/home/user"
[...]
pwd on the other hand is a program producing the current working directory to STDOUT:
$ whereis pwd
pwd: /bin/pwd /usr/include/pwd.h /usr/share/man/man1/pwd.1.gz
$ pwd
/home/user
With the previous docker command the program is executed and its STDOUT is inserted producing:
docker run --rm -it -v /home/user:/untitled1 centos
While going through the docker docs, I came across volumes-from (https://docs.docker.com/engine/reference/commandline/run/) option for docker run command.
I didn't understand the differences between ro, rw, and z option provided as-
$ docker run --volumes-from ba8c0c54f0f2:ro -i -t ubuntu pwd
In the above command the ro option is replaced with z. I will be thankful if anyone explores on differences of using these options.
Two suffixes :z or :Z can be added to the volume mount. These suffixes tell Docker to relabel file objects on the shared volumes. The 'z' option tells Docker that the volume content will be shared between containers. Docker will label the content with a shared content label. Shared volumes labels allow all containers to read/write content. The 'Z' option tells Docker to label the content with a private unshared label.
https://github.com/rhatdan/docker/blob/e6473011583967df4aa5a62f173fb421cae2bb1e/docs/sources/reference/commandline/cli.md
If you use selinux you can add the z or Z options to modify the selinux label of the host file or directory being mounted into the container. This affects the file or directory on the host machine itself and can have consequences outside of the scope of Docker.
The z option indicates that the bind mount content is shared among multiple containers.
The Z option indicates that the bind mount content is private and unshared.
Use extreme caution with these options. Bind-mounting a system directory such as /home or /usr with the Z option renders your host machine inoperable and you may need to relabel the host machine files by hand.
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app:z \
nginx:latest
https://docs.docker.com/storage/bind-mounts/#configure-bind-propagation
From tests here in my machine, -z lets you share content from one container with another. Suppose this image:
FROM alpine
RUN mkdir -p /var/www/html \
&& echo "foo" > /var/www/html/index.html
Let's build it and tag as test-z:
$ docker build . -t test-z
Now create and run test-z container with the name testing-z, mapping the volume test-vol to /var/www/html and adding the z modifier
$ docker run \
--name testing-z \
--volume test-vol:/var/www/html:z \
-d test-z tail -f /dev/null
The contents of /var/www/html from testing-z can be accessed from others containers by using the --volumes-from flag, like below:
$ docker run --rm --volumes-from testing-z -it nginx sh
# cat /var/www/html/index.html
foo
Obs.: I'm running Docker version 19.03.5-ce, build 633a0ea838
docker run --volumes-from a64f10cd5f0e:z -i -t rhel6 bin/bash
I have tested it, i have mounted in one container and from that container to another newly container. IT goes with rw option
I've done the following observation:
# docker run --rm -ti -v /host/path/to/flyway/scripts:/flyway/sql:z --entrypoint '' flyway/flyway ls -l /flyway/sql
total 0
# docker run --rm -ti -v /host/path/to/flyway/scripts:/flyway/sql --entrypoint '' flyway/flyway ls -l /flyway/sql
ls: cannot open directory '/flyway/sql': Permission denied
So, in this case, the container works only if :z is set. On this host, SELinux is installed. If this is not the case, the :z doesn't have a recognizable effect to me.
Alternatively to :z, one could use chcon on the host folder to change this permission:
# chcon -t svirt_sandbox_file_t /host/path/to/flyway/scripts
# docker run --rm -ti -v /host/path/to/flyway/scripts:/flyway/sql:z --entrypoint '' flyway/flyway ls -l /flyway/sql
total 0
# docker run --rm -ti -v /host/path/to/flyway/scripts:/flyway/sql --entrypoint '' flyway/flyway ls -l /flyway/sql
total 0