如何从主机编辑Docker容器文件?

如何从主机编辑Docker容器文件?,docker,Docker,现在,我找到了一种向容器(-v选项)公开主机文件的方法,我想做一些相反的事情: 如何使用主机编辑器编辑运行容器中的文件 sshfs可能可以完成这项工作,但由于正在运行的容器已经是某种主机目录,我想知道是否有一种可移植(在aufs、btrfs和设备映射器之间)的方法来完成这项工作?我们可以使用另一种方法来编辑工作容器中的文件(如果容器被停止,这将不起作用) 逻辑是: -)将文件从容器复制到主机 -)使用主机编辑器在主机上编辑文件 -)将文件复制回容器 我们可以手动完成所有这些步骤,但我编写了简单的

现在,我找到了一种向容器(-v选项)公开主机文件的方法,我想做一些相反的事情:

如何使用主机编辑器编辑运行容器中的文件


sshfs可能可以完成这项工作,但由于正在运行的容器已经是某种主机目录,我想知道是否有一种可移植(在aufs、btrfs和设备映射器之间)的方法来完成这项工作?

我们可以使用另一种方法来编辑工作容器中的文件(如果容器被停止,这将不起作用)

逻辑是:
-)将文件从容器复制到主机
-)使用主机编辑器在主机上编辑文件
-)将文件复制回容器

我们可以手动完成所有这些步骤,但我编写了简单的bash脚本,只需一次调用即可轻松完成

/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;
用法示例:

#!/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;
dmcedit CONTAINERNAME/path/to/file/in/container

剧本很简单,但对我来说效果很好


非常感谢您的建议。

虽然这是可能的,但其他答案说明了如何避免在Union文件系统中编辑文件(如果可以的话)

您对卷的定义不太正确-与其说是在主机上公开文件,不如说是绕过联合文件系统。例如,如果我这样做:

$ docker run --name="test" -v /volume-test debian echo "test"
容器中的目录
/volume test
将不是Union文件系统的一部分,而是存在于主机上的某个位置。我没有指定主机上的位置,因为我可能不在乎——我没有公开主机文件,只是创建了一个可在容器和主机之间共享的目录。您可以通过以下方式找到它在主机上的确切位置:

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

如果您确实需要对文件进行快速编辑以测试某些内容,可以使用
docker exec
在容器中获取一个shell并直接编辑,或者使用
docker cp
将文件复制出来,在主机上编辑并复制回来。

docker run -it -name YOUR_NAME IMAGE_ID /bin/bash

$>vi path_to_file
docker run-it IMAGE\u NAME/bin/bash

我的图像被称为ipython/notebook


docker-run-it-ipython/notebook/bin/bash
以下是我使用的脚本:

#!/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"
当我修复它但忘记更新这个答案时的要点是: 最好的方法是:

  $ docker cp CONTAINER:FILEPATH LOCALFILEPATH
  $ vi LOCALFILEPATH
  $ docker cp LOCALFILEPATH CONTAINER:FILEPATH
$docker exec的限制:它只能附加到正在运行的容器


$docker run的限制:它将创建一个新容器。

我使用IDE中的sftp插件

  • 为容器安装ssh服务器并允许root访问
  • 使用-p localport:22运行docker容器
  • 从IDE安装sftp插件
  • 使用升华sftp插件的示例:

    如果您认为您的卷是一个“网络驱动器”,这会更容易。 若要编辑此驱动器中的文件,只需打开另一台计算机并连接到此网络驱动器,然后像普通一样编辑该文件

    如何纯粹使用docker(不使用FTP/SSH…)实现这一点

  • 运行具有编辑器(VI、Emacs)的容器。搜索Docker hub查找“alpine vim”
  • 例如:

    docker run -d --name shared_vim_editor \
     -v <your_volume>:/home/developer/workspace \
    jare/vim-bundle:latest
    
    docker run-d——名称共享的_vim_编辑器\
    -v:/home/developer/workspace\
    jare/vim捆绑包:最新版本
    
  • 运行交互式命令:
  • docker exec-it-u root共享\u vim\u编辑器/bin/bash


    希望这能有所帮助。

    我现在的做法是在安装了
    docker
    软件包的情况下使用Emacs。我会推荐Emacs的版本。我将遵循以下步骤:

    1) 安装Emacs()和Spacemacs()

    2) 在
    .spacemacs
    文件中添加
    docker

    3) 启动Emacs

    4) 查找文件(
    SPC+f+f
    )并键入
    /docker::/


    5) 现在您的emacs将使用容器环境编辑文件

    有两种方法可以将文件装载到容器中。看起来您需要一个绑定挂载

    捆绑坐骑 这会将本地文件直接装载到容器的文件系统中。containerside路径和hostside路径都指向同一个文件。从任意一侧进行的编辑将显示在两侧

    • 装载文件:
    • 在单独的shell中,编辑文件:
    • 回到容器中:
    卷装载
    • 装入卷
    • 本地文件系统保持不变
    • docker看到一个新卷:
    • 创建具有相同卷的新容器
    语法:
    -v
    vs
    -mount
    它们做同样的事情
    -v
    更简洁,
    --mount
    更明确

    绑定挂载

    -v /hostside/path:/containerside/path
    --mount type=bind,source=/hostside/path,target=/containerside/path
    
    -v /containerside/path
    -v volumename:/containerside/path
    --mount type=volume,source=volumename,target=/containerside/path
    
    卷装载量

    -v /hostside/path:/containerside/path
    --mount type=bind,source=/hostside/path,target=/containerside/path
    
    -v /containerside/path
    -v volumename:/containerside/path
    --mount type=volume,source=volumename,target=/containerside/path
    
    (如果未指定卷名,则选择随机卷名。)


    试图说服你用一件事来代替另一件事,而不是仅仅告诉你它是如何工作的,这是令人困惑的。

    这将在一些容器上起作用,但许多容器只包含一个最小的环境,因此不包含vi。@JensKohl,您可以提供更详细的信息吗?您应该尝试使用
    docker cp$FILEPATH$CONTAINER:。。。。etc
    @joaqínM Thx!我已经编辑了我的答案。很高兴docker改进了它的功能,并为我们提供了这个新功能。在Windows上,我最终在MINGW64控制台中使用了
    docker cp
    。这对我有用。所以,首先从容器复制到主机,编辑相同的文件,然后再复制回容器。我只是通过保留文件扩展名来改进脚本,让编辑器突出显示文件内容。
    docker inspect
    命令似乎只有在docker 1.7之前才是正确的。有关如何检查更新版本上的映射,请参见能否将此答案推广到其他容器?这在osx上可能吗?@s.matthew.english没有MacOS容器。在MacOS上,Docker在内部运行xhyve Linux VM来托管Docker容器。卷路径只存在于这个虚拟机中(它对您几乎是隐藏的)
    ❯ 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
    
    -v /hostside/path:/containerside/path
    --mount type=bind,source=/hostside/path,target=/containerside/path
    
    -v /containerside/path
    -v volumename:/containerside/path
    --mount type=volume,source=volumename,target=/containerside/path