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/dirname
或
ADD 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:
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)
- 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
中没有任何其他上下文文件
还有一个 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/dirname
或
ADD 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:
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 underparent_dir/my-app/HardLinked/common_files
, the files underparent_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)- 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 offile-syncer
enables it to be used in alocal(...)
invokation in the project'sTiltfile
)
使用一个小包装脚本将所需的目录复制到 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
中没有任何其他上下文文件