Docker和符号链接

Docker and symlinks

我有一个这样的回购协议:

1
2
3
4
5
6
7
8
9
10
/config
   config.json
/worker-a
   Dockerfile
   <symlink to config.json>
   /code
/worker-b
   Dockerfile
   <symlink to config.json>
   /code

但是,构建图像失败,因为Docker无法处理符号链接。我应该提到我的项目远比这复杂得多,所以重组目录不是一个很好的选择。我该如何处理这种情况?


Docker不支持构建上下文之外的符号链接文件。

在容器中使用共享文件的一些不同方法。

共享基础图像

为包含共享配置/文件的基本worker-config映像创建Dockerfile

1
COPY config.json /config.json

创建图像并标记为worker-config

1
docker build -t worker-config:latest .

为您的所有员工提供基础worker-config图像Dockerfile

1
FROM worker-config:latest

构建脚本

使用脚本将公共配置推送到每个工作容器中。

./build worker-n

1
2
3
4
5
6
7
#!/bin/sh
set -uex
rundir=$(readlink -f"${0%/*}")
container=$(shift)
cd"$rundir/$container"
cp ../config/config.json ./config-docker.json
docker build"$@" .

从URL构建

从所有worker-n构建的公共URL中提取配置。

1
ADD http://somehost/config.json /

增加图像生成上下文的范围

通过从包含共享文件和特定容器文件的父目录构建,在构建上下文中包含symlink目标文件。

1
2
cd ..
docker build -f worker-a/Dockerfile .

您在Dockerfile中引用的所有源路径也必须更改以匹配新的构建上下文:

1
COPY workerathing /app

变成

1
COPY worker-a/workerathing /app

如果您有一个大的构建上下文,那么使用此方法可以使所有的构建上下文变大,因为它们都成为共享的。它可以降低构建速度,特别是对于远程Docker构建服务器。

从命名卷装入配置目录

像这样的卷只能作为目录工作,因此您不能像在将文件从主机装载到容器时那样指定文件。

1
2
3
4
docker volume create --name=worker-cfg-vol
docker run -v worker-cfg-vol:/config worker-config cp config.json /config

docker run -v worker-cfg-vol:/config:/config worker-a

从数据容器装载配置目录

同样,目录只是基本上和上面一样。但是,这会自动将文件从目标目录复制到新创建的共享卷中。

1
2
docker create --name wcc -v /config worker-config /bin/true
docker run --volumes-from wcc worker-a

从主机装载配置文件

1
docker run -v /app/config/config.json:/config.json worker-a

docker buildcli命令将指定的目录(通常是.作为"构建上下文")发送到docker引擎(守护进程)。不要将构建上下文指定为/worker-a,而是将构建上下文指定为根目录,并使用-f参数指定一个子目录中Dockerfile的路径。

1
2
docker build -f worker-a/Dockerfile .
docker build -f worker-b/Dockerfile .

你需要稍微修改一下你的dockerfiles,把它们指向../config/config.json,但这是很容易修复的。

另外,请查看这个问题/答案,我认为它可以解决与您所遇到的问题完全相同的问题。

如何包括Docker构建上下文之外的文件?

希望这有帮助!干杯


我也遇到了这个问题,我想分享另一个方法,上面没有提到。我没有在我的Dockerfile中使用npm link,而是使用了yalc。

  • 在容器中安装yalc,例如RUN npm i -g yalc
  • 在Docker中构建库,并运行yalc publish(如果共享的lib是私有的,则添加--private标志)。这将在本地"发布"您的库。
  • 在每次回购中运行yalc add my-lib,通常在运行npm install之前使用npm link。它将在Docker容器中创建一个本地的.yalc文件夹,在node_modules中创建一个在Docker内部工作的符号链接到这个文件夹,并重写package.json以引用这个文件夹,这样您就可以安全地运行安装程序。
  • 或者,如果您进行两阶段构建,请确保还将.yalc文件夹复制到最终图像。
  • 下面是一个示例Dockerfile,假设您有一个包含三个包的Mono存储库:模型、GUI和服务器,并且模型存储库必须共享并命名为my-models

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    # You can access the container using:
    #   docker run -it my-name sh
    # To start it stand-alone:
    #   docker run -it -p 8888:3000 my-name

    FROM node:alpine AS builder
    # Install yalc globally (the apk add... line is only needed if your installation requires it)
    RUN apk add --no-cache --virtual .gyp python make g++ && \
      npm i -g yalc
    RUN mkdir /packages && \
      mkdir /packages/models && \
      mkdir /packages/gui && \
      mkdir /packages/server
    COPY ./packages/models /packages/models
    WORKDIR /packages/models
    RUN npm install && \
      npm run build && \
      yalc publish --private
    COPY ./packages/gui /packages/gui
    WORKDIR /packages/gui
    RUN yalc add my-models && \
      npm install && \
      npm run build
    COPY ./packages/server /packages/server
    WORKDIR /packages/server
    RUN yalc add my-models && \
      npm install && \
      npm run build

    FROM node:alpine
    RUN mkdir -p /app
    COPY --from=builder /packages/server/package.json /app/package.json
    COPY --from=builder /packages/server/dist /app/dist
    # Make sure you copy the yalc registry too.
    COPY --from=builder /packages/server/.yalc /app/.yalc
    COPY --from=builder /packages/server/node_modules /app/node_modules
    COPY --from=builder /packages/gui/dist /app/dist/public
    WORKDIR /app
    EXPOSE 3000
    CMD ["node","./dist/index.js"]

    希望有帮助…


    另一种解决方案是将所有软链接升级为硬链接。