54

Now that I found a way to expose host files to the container (-v option) I would like to do kind of the opposite:

How can I edit files from a running container with a host editor?

sshfs could probably do the job but since a running container is already some kind of host directory I wonder if there is a portable (between aufs, btrfs and device mapper) way to do that?

ascobol
  • 7,554
  • 7
  • 49
  • 70

10 Answers10

46

The best way is:

  $ docker cp CONTAINER:FILEPATH LOCALFILEPATH
  $ vi LOCALFILEPATH
  $ docker cp LOCALFILEPATH CONTAINER:FILEPATH

Limitations with $ docker exec: it can only attach to a running container.

Limitations with $ docker run: it will create a new container.

zhigang
  • 6,597
  • 4
  • 30
  • 24
28

Whilst it is possible, and the other answers explain how, you should avoid editing files in the Union File System if you can.

Your definition of volumes isn't quite right - it's more about bypassing the Union File System than exposing files on the host. For example, if I do:

$ docker run --name="test" -v /volume-test debian echo "test"

The directory /volume-test inside the container will not be part of the Union File System and instead will exist somewhere on the host. I haven't specified where on the host, as I may not care - I'm not exposing host files, just creating a directory that is shareable between containers and the host. You can find out exactly where it is on the host with:

$ docker inspect -f "{{.Volumes}}" test
map[/volume_test:/var/lib/docker/vfs/dir/b7fff1922e25f0df949e650dfa885dbc304d9d213f703250cf5857446d104895]

If you really need to just make a quick edit to a file to test something, either use docker exec to get a shell in the container and edit directly, or use docker cp to copy the file out, edit on the host and copy back in.

Adrian Mouat
  • 44,585
  • 16
  • 110
  • 102
  • The `docker inspect` command seems to be correct only up to docker 1.7. For how to inspect the mapping on newer versions see https://www.adelton.com/docs/docker/docker-inspect-volumes-mounts – Dirk Vollmar Dec 09 '16 at 10:47
  • can you generalize this answer to other containers? is this possible on osx? – smatthewenglish Sep 06 '17 at 16:27
  • 2
    @s.matthew.english there's no such thing as a MacOS container.On MacOS, Docker runs an xhyve Linux VM internally to host the Docker containers. The volume path only exists in this VM (which is pretty much hidden from you). – Adrian Mouat Sep 07 '17 at 11:08
  • The `-v /volume-test` syntax acheives a [volume mount](https://docs.docker.com/storage/volumes/) but I think the asker is better served with a [bind mount](https://docs.docker.com/storage/bind-mounts/). – MatrixManAtYrService Feb 01 '21 at 05:26
5

We can use another way to edit files inside working containers (this won't work if container is stoped).

Logic is to:
-)copy file from container to host
-)edit file on host using its host editor
-)copy file back to container

We can do all this steps manualy, but i have written simple bash script to make this easy by one call.

/bin/dmcedit:

#!/bin/sh
set -e

CONTAINER=$1
FILEPATH=$2
BASE=$(basename $FILEPATH)
DIR=$(dirname $FILEPATH)
TMPDIR=/tmp/m_docker_$(date +%s)/

mkdir $TMPDIR
cd $TMPDIR
docker cp $CONTAINER:$FILEPATH ./$DIR
mcedit ./$FILEPATH
docker cp ./$FILEPATH $CONTAINER:$FILEPATH
rm -rf $TMPDIR

echo 'END'
exit 1;

Usage example:

dmcedit CONTAINERNAME /path/to/file/in/container

The script is very easy, but it's working fine for me.

Any suggestions are appreciated.

Mikl
  • 673
  • 9
  • 19
  • @JensKohl, can you give more detailed info? – Mikl Jul 09 '15 at 16:02
  • 1
    You should try copying the file back using `docker cp $FILEPATH $CONTAINER: .... etc` – Joaquín M Apr 28 '16 at 04:55
  • @JoaquínM Thx! I've edited my answer. Glad docker improved it's functions, and gives us this new feature. – Mikl May 18 '16 at 15:45
  • On Windows I ended up using `docker cp` in MINGW64 console. This worked for me. So first copying from container to host, edit and then copy same file back to container. – Mustafa Temiz May 30 '16 at 13:13
3

There are two ways to mount files into your container. It looks like you want a bind mount.

Bind Mounts

This mounts local files directly into the container's filesystem. The containerside path and the hostside path both point to the same file. Edits made from either side will show up on both sides.

  • mount the file:
❯ echo foo > ./foo
❯ docker run --mount type=bind,source=$(pwd)/foo,target=/foo -it debian:latest
# cat /foo
foo # local file shows up in container
  • in a separate shell, edit the file:
❯ echo 'bar' > ./foo # make a hostside change
  • back in the container:
# cat /foo
bar # the hostside change shows up
# echo baz > /foo # make a containerside change
# exit
 
❯ cat foo
baz # the containerside change shows up

Volume Mounts

  • mount the volume
❯ docker run --mount type=volume,source=foovolume,target=/foo  -it debian:latest
root@containerB# echo 'this is in a volume' > /foo/data
  • the local filesystem is unchanged
  • docker sees a new volume:
❯ docker volume ls
DRIVER    VOLUME NAME
local     foovolume
  • create a new container with the same volume
❯ docker run --mount type=volume,source=foovolume,target=/foo  -it debian:latest
root@containerC:/# cat /foo/data
this is in a volume # data is still available

syntax: -v vs --mount

These do the same thing. -v is more concise, --mount is more explicit.

bind mounts

-v /hostside/path:/containerside/path
--mount type=bind,source=/hostside/path,target=/containerside/path

volume mounts

-v /containerside/path
-v volumename:/containerside/path
--mount type=volume,source=volumename,target=/containerside/path

(If a volume name is not specified, a random one is chosen.)

The documentaion tries to convince you to use one thing in favor of another instead of just telling you how it works, which is confusing.

MatrixManAtYrService
  • 8,023
  • 1
  • 50
  • 61
1

Here's the script I use:

#!/bin/bash
IFS=$'\n\t'
set -euox pipefail


CNAME="$1"
FILE_PATH="$2"

TMPFILE="$(mktemp)"
docker exec "$CNAME" cat "$FILE_PATH" > "$TMPFILE"
$EDITOR "$TMPFILE"
cat "$TMPFILE" | docker exec -i "$CNAME" sh -c 'cat > '"$FILE_PATH"
rm "$TMPFILE"

and the gist for when I fix it but forget to update this answer: https://gist.github.com/dmohs/b50ea4302b62ebfc4f308a20d3de4213

DavidM
  • 1,417
  • 1
  • 13
  • 16
  • I just improved the script by preserving file extension to let editor highlight the file content. https://gist.github.com/mostafar/116a0cb79005955476b24c0960b72d5a – MostafaR May 27 '16 at 15:35
1

If you think your volume is a "network drive", it will be easier. To edit the file located in this drive, you just need to turn on another machine and connect to this network drive, then edit the file like normal.

How to do that purely with docker (without FTP/SSH ...)?

  1. Run a container that has an editor (VI, Emacs). Search Docker hub for "alpine vim"

Example:

docker run -d --name shared_vim_editor \
 -v <your_volume>:/home/developer/workspace \
jare/vim-bundle:latest
  1. Run the interactive command:

docker exec -it -u root shared_vim_editor /bin/bash

Hope this helps.

Brian Ng
  • 1,005
  • 12
  • 13
0

I use sftp plugin from my IDE.

  1. Install ssh server for your container and allow root access.
  2. Run your docker container with -p localport:22
  3. Install from your IDE a sftp plugin

Example using sublime sftp plugin: https://www.youtube.com/watch?v=HMfjt_YMru0

moylop260
  • 1,288
  • 2
  • 13
  • 20
  • Can you provide a full set of instructions on doing this? Please include the commands necessary to install the SSH server (e.g., apt-get or similar) and the commands necessary to properly setup the SSH server for running an SFTP server. Would also be nice to see instructions on how to setup at least one editor for sync (e.g., sublime). Answers should avoid being dependent on external links, especially to YouTube. – Micah Zoltu Apr 04 '17 at 17:51
0

The way I am doing is using Emacs with docker package installed. I would recommend Spacemacs version of Emacs. I would follow the following steps:

1) Install Emacs (Instruction) and install Spacemacs (Instruction)

2) Add docker in your .spacemacs file

3) Start Emacs

4) Find file (SPC+f+f) and type /docker:<container-id>:/<path of dir/file in the container>

5) Now your emacs will use the container environment to edit the files

TheRimalaya
  • 4,232
  • 2
  • 31
  • 37
  • Seems worse than just running emacs in that container... But emacs is old for me and docker is new. Can this run shells in the container too? – nroose Jul 22 '19 at 22:17
-3
docker run -it -name YOUR_NAME IMAGE_ID /bin/bash

$>vi path_to_file
animuson
  • 53,861
  • 28
  • 137
  • 147
Yousef Irman
  • 109
  • 4
  • 8
    This will work on some containers, but lots of containers will only include a minimal environment, thus won't include vi. – mkirk Jul 06 '15 at 20:54
-4

The following worked for me

docker run -it IMAGE_NAME /bin/bash

eg. my image was called ipython/notebook

docker run -it ipython/notebook /bin/bash