Docker 在上下文之外跟随符号链接

Docker follow symlink outside context

还有一个 Docker 符号链接问题。我有一堆文件要复制到我所有的 Docker 构建中。我的目录结构是:

parent_dir
    - common_files
        - file.txt
    - dir1
        - Dockerfile  
        - symlink -> ../common_files

在上面的例子中,当我在 dir1 中构建 docker 时,我希望 file.txt 被复制过来。但我不想维护 file.txt 的多个副本。 每 this link, as of docker version 0.10、docker 构建必须

Follow symlinks inside container's root for ADD build instructions.

但是当我在 Docker 文件中使用以下任一行构建时,我得到 没有这样的文件或目录

ADD symlink /path/dirnameADD symlink/file.txt /path/file.txt

挂载选项不会为我解决这个问题(跨平台...)。 我尝试了 tar -czh . | docker build -t 但没有成功。

有没有办法让 Docker 遵循符号链接并将 common_files/file.txt 复制到构建的容器中?

这是不可能的,也不会实施。请查看 discussion on github issue #1676:

We do not allow this because it's not repeatable. A symlink on your machine is the not the same as my machine and the same Dockerfile would produce two different results. Also having symlinks to /etc/paasswd would cause issues because it would link the host files and not your local files.

一种可能是 运行 在父目录中构建,其中:

$ docker build [tags...] -f dir1/Dockerfile .

(或等效地,在子目录中,)

$ docker build  [tags...] -f Dockerfile ..

必须将 Dockerfile 配置为 copy/add 使用适当的路径。根据您的设置,您可能希望父级中的 .dockerignore 省略 您不想放入上下文中的事情。

而不是使用 simlinks 可以通过将文件从 sites_available 移动到 sites_enabled 而不是复制或制作 simlinks

来管理地解决问题

所以你的站点配置将只在 site_available 文件夹中的一个副本中,如果它停止或什么,或者在 sites_enabled 如果它应该被使用

我知道它破坏了 docker 构建的可移植性,但您可以使用硬链接而不是符号链接:

ln /some/file ./hardlink

如果有人仍然遇到这个问题,我在 superuser.com 上找到了一个非常好的解决方案:

https://superuser.com/questions/842642/how-to-make-a-symlinked-folder-appear-as-a-normal-folder

它基本上建议使用 tar 取消引用符号链接并将结果提供给 docker build:

$ tar -czh . | docker build -

我只需要在相同的上下文中解决这个问题。我的解决方案是使用分层 Docker 构建。换句话说:

parent_dir
  - common_files
    - Dockerfile
    - file.txt

- dir1
    - Dockerfile (FROM common_files:latest)

缺点是要记得在dir1之前建common_files。优点是,如果你有很多依赖图像,那么由于使用了公共层,它们都会变小一些。

我非常沮丧,所以我制作了一个小的 NodeJS 实用程序来帮助解决这个问题:file-syncer

给定现有目录结构:

parent_dir
    - common_files
        - file.txt
    - my-app
        - Dockerfile
        - common_files -> symlink to ../common_files

基本用法:

cd parent_dir

// starts live-sync of files under "common_files" to "my-app/HardLinked/common_files"
npx file-syncer --from common_files --to my-app/HardLinked

然后在你的 Dockerfile:

[regular commands here...]

# have docker copy/overlay the HardLinked folder's contents (common_files) into my-app itself
COPY HardLinked /

Q/A

  • 这比在 Docker 运行之前将 parent_dir/common_files 复制到 parent_dir/my-app/common_files 有何优势?

That would mean giving up the regular symlink, which would be a loss, since symlinks are helpful and work fine with most tools. For example, it would mean you can't see/edit the source files of common_files from the in-my-app copy, which has some drawbacks. (see below)

  • 这比在 Docker 运行之前将 parent_dir/common-files 复制到 parent_dir/my-app/common_files_Copy,然后在构建时让 Docker 将其复制到 parent_dir/my-app/common_files 更好吗?

There are two advantages:

  1. file-syncer does not "copy" the files in the regular sense. Rather, it creates hard links from the source folder's files. This means that if you edit the files under parent_dir/my-app/HardLinked/common_files, the files under parent_dir/common_files are instantly updated, and vice-versa, because they reference the same file/inode. (this can be helpful for debugging purposes and cross-project editing [especially if the folders you are syncing are symlinked node-modules that you're actively editing], and ensures that your version of the files is always in-sync/identical-to the source files)
  2. Because file-syncer only updates the hard-link files for the exact files that get changed, file-watcher tools like Tilt or Skaffold detect changes for the minimal set of files, which can mean faster live-update-push times than you'd get with a basic "copy whole folder on file change" tool would.
  • 这与 Syncthing 等常规文件同步工具相比有何优势?

Some of those tools may be usable, but most have issues of one kind or another. The most common one is that the tool either cannot produce hard-links of existing files, or it's unable to "push an update" for a file that is already hard-linked (since hard-linked files do not notify file-watchers of their changes automatically, if the edited-at and watched-at paths differ). Another is that many of these sync tools are not designed for instant responding, and/or do not have run flags that make them easy to use in restricted build tools. (eg. for Tilt, the --async flag of file-syncer enables it to be used in a local(...) invokation in the project's Tiltfile)

使用一个小包装脚本将所需的目录复制到 Dockerfile 的位置;

  • build.sh;

.

#!/bin/bash
[ -e bin ] && rm -rf bin
cp -r ../../bin .
docker build -t "sometag" .

如果你在 mac,记得做 brew install gnu-tar 并使用 gtar 而不是 tar。两者似乎有些不同。

gtar 至少对我有用。

通常我将构建指令隔离到子文件夹中,因此应用程序和逻辑级别位于更高位置:

.
├── app
│   ├── package.json
│   ├── modules
│   └── logic
├── deploy
│   ├── back
│   │   ├── nginx
│   │   │   └── Chart.yaml
│   │   ├── Containerfile
│   │   ├── skaffold.yaml
│   │   └── .applift -> ../../app
│   ├── front
│   │   ├── Containerfile
│   │   ├── skaffold.yaml
│   │   └── .applift -> ../../app
│   └── skaffold.yaml
└── .......

我为这些符号链接使用名称“.applift” .applift -> ../../app

现在通过真实路径跟随符号链接而不关心路径深度

dir/deploy/front$ docker build -f Containerfile --tag="build" `realpath .applift`

或打包在 func

dir/deploy$ docker_build () { docker build -f ""/Containerfile --tag="" `realpath "/.applift"`; }
dir/deploy$ docker_build ./back "front_builder"

所以

COPY app/logic/ ./app/

Containerfile 中可以工作

是的,在这种情况下,您将失去其他层的上下文。但通常 build-directory

中没有任何其他上下文文件