Docker、docker-compose以及在项目之间复制文件

3

我有以下设置。

文件夹结构

solution-root
    ├── docker-compose.yml
    ├── project1
    │   ├── Dockerfile
    │   ├── sub1
    │   │   ├── ...loads of stuff...
    │   ├── sub2
    │   │   ├── ...more stuff...
    ├── project2
    │   ├── Dockerfile
    │   ├── sub1
    │   │   ├── ...more stuff...
    │   ├── sub2
    │   │   ├── ...even more stuff...
    ├── project-db
    │   ├── Dockerfile

docker-compose.yml

version: '3'

services:
  project1:
    build:
      context: ./project1
      dockerfile: Dockerfile
    ...
  project2:
    build:
      context: ./project2
      dockerfile: Dockerfile
    ...
  project-db:
    build:
      context: ./project-db
      dockerfile: Dockerfile
    ...
...

项目-db/Dockerfile
FROM mysql:5.7

COPY ../project1/app/seeders /seeders/
COPY ../project2/app/seeders /seeders/

显然,我想要从另一个兄弟文件夹复制文件,因为这个project-db需要它们。

当我运行docker-compose build时,出现以下错误:

Service 'project-db' failed to build: COPY failed: Forbidden path outside the build context: ../project1/app/seeders

好的,我明白了,环境不允许我升级。

那么我们就将环境移动到根目录,然后从那里运行项目/Dockerfile。

docker-compose.yml

  project-db:
    build:
      context: .
      dockerfile: ./project-db/Dockerfile
    ...

现在我们可以复制所需的文件。 project-db/Dockerfile
COPY project1/app/seeders /seeders/
COPY project2/app/seeders /seeders/

现在,使用 docker-compose build 一切看起来还好(有点问题)。但是存在一个问题 - 构建项目数据库需要相当长的时间。这意味着每次运行时都会花费很长时间。我认为这是因为现在 project-db 的上下文是整个文件夹结构。
因此,我尝试使用 .dockerignore 过滤掉不需要的文件夹: .dockerignore
project3
project3/**
project4
project4/**
project5
project5/**
...

但是没有什么可以消除这种滞后。

我无法正确地使此工作。 此外 - 我不能干涉现有项目的内部结构。

这里出了什么问题?


哪一步花费了很长时间:是“发送上下文”步骤,还是实际在您的Dockerfile中的某些步骤? - David Maze
你为什么不使用卷共享,有特殊原因吗? - agentsmith
@DavidMaze:我认为自己是一个Docker初学者,所以无法百分之百地回答那个问题;从我所读的内容来看,这种滞后通常是由于发送上下文引起的,但我该如何判断呢? - OzrenTkalcecKrznaric
@agentsmith 没什么特别的,我只是不知道卷是用来做那个目的的。我以为卷是为了持久化状态,例如在多个docker调用之间。 - OzrenTkalcecKrznaric
1
是的,它们是为此目的而设计的,没错。但根据docker-docs的说明,也可以用于在多个容器之间共享数据。我想到了这样的方法:为每个容器分配一个卷,在Dockerfile中将文件COPY到该卷中,然后与数据库共享卷。如果您需要,我可以提供更具体的答案。 - agentsmith
@agentsmith 如果您这样做,您可能也会帮助其他人,因为这似乎是其他人也面临的问题。请随意添加答案 :) - OzrenTkalcecKrznaric
1个回答

1
正如作者正确指出的那样,卷用于持久化数据。在这里,我想展示两种解决方案,以说明如何将它们用于在容器之间共享数据。这个解决方案远非完美!

解决方案1

缺点

首先,我想指出这种解决方案的缺点。

  • 您需要清理卷。 卷只在第一次创建时填充容器的内容。 有关说明,请参见此处。 因此,如果项目目录中的某些文件已更改,则必须执行docker-compose down -v
  • 另一种docker-compose down -v`` 的方法是使用docker volume rm``手动删除命名卷。
  • 如果您不想这样做,可以将文件暂时COPY到一个文件夹中(这不是已挂载的卷,例如/tmp)。 使用入口脚本,然后可以将文件复制到其预定位置(例如/home/developer/)。 有关此内容,请参见解决方案2

我的设置:文件夹结构

我的文件夹结构与您的类似:

├── docker-compose.yaml
├── project1
│   ├── Dockerfile
│   ├── entrypoint.sh
│   ├── sub1
│   │   ├── testfile_project_1_1.txt
│   │   └── testfile_project_1_2.txt
│   └── sub2
│       └── testfile_project_1_3.txt
├── project2
│   ├── Dockerfile
│   ├── entrypoint.sh
│   ├── sub1
│   │   └── testfile_project_2_1.txt
│   └── sub2
│       ├── testfile_project_2_2.txt
│       ├── testfile_project_2_3.txt
│       ├── testfile_project_2_4.txt
│       └── testfile_project_2_5.txt
└── project-db
    ├── Dockerfile
    └── entrypoint.sh

来源

docker-compose.yaml

version: "3.8"
services:
  first-service:
    build: 
      context: ./project1
      dockerfile: Dockerfile
    volumes:       
      - data-first-service:/home/developer/

  second-service:
    build: 
      context: ./project2
      dockerfile: Dockerfile
    volumes:       
      - data-second-service:/home/developer/

  databse-service:
    build: 
      context: ./project-db
      dockerfile: Dockerfile
    volumes:       
      - data-first-service:/home/developer/project1/
      - data-second-service:/home/developer/project2/
    depends_on: 
      - first-service
      - second-service
 
volumes: 
  data-first-service:  
  data-second-service:

Dockerfile(s)

它们基本上是相同的。*db-service* 的dockerfile只复制了它的入口脚本。有关sudoers的部分在这里,因为这是我的默认测试镜像。我只是包含它以明确我的用户具有哪些权限,并使常规用户可以无密码使用sudo。这不是强制性的。

FROM ubuntu:latest
# We need some tools
RUN apt-get update && apt-get install -y sudo
# We want to have another user than `root`
## USER SETUP 
RUN adduser developer
# We want to have passwordless sudo access
RUN \
    sed -i /etc/sudoers -re 's/^%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
    sed -i /etc/sudoers -re 's/^root.*/root ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
    sed -i /etc/sudoers -re 's/^#includedir.*/## **Removed the include directive** ##"/g' && \
    echo "developer ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers;  su - developer -c id

# Run now with user developer
USER developer
COPY sub1 /home/developer/sub1
COPY sub2 /home/developer/sub2
RUN ls -l

ADD ./entrypoint.sh /entrypoint.sh
RUN sudo chmod +x /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]

entrypoint.sh

这两个项目的入口点并没有什么特别之处,它们只包含一个简单的ls -l命令,用于查看/home/developer目录。*db-service*的入口点只显示了一个tree输出(见Results):
#!/bin/bash
cd ~
echo "db service - You are here: ${PWD} "
tree --du -shaC | grep -Ev '(  *[^ ]* ){5}\['

结果

正如您所看到的,project-db 容器现在包含了另外两个项目的文件。

databse-service_1  | .
databse-service_1  | |-- [ 220]  .bash_logout
databse-service_1  | |-- [3.7K]  .bashrc
databse-service_1  | |-- [ 807]  .profile
databse-service_1  | |-- [ 17K]  project1
databse-service_1  | |   |-- [ 220]  .bash_logout
databse-service_1  | |   |-- [3.7K]  .bashrc
databse-service_1  | |   |-- [ 807]  .profile
databse-service_1  | |   |-- [4.0K]  sub1
databse-service_1  | |   |   |-- [   0]  testfile_project_1_1.txt
databse-service_1  | |   |   `-- [   0]  testfile_project_1_2.txt
databse-service_1  | |   `-- [4.0K]  sub2
databse-service_1  | |       `-- [   0]  testfile_project_1_3.txt
databse-service_1  | `-- [ 17K]  project2
databse-service_1  |     |-- [ 220]  .bash_logout
databse-service_1  |     |-- [3.7K]  .bashrc
databse-service_1  |     |-- [ 807]  .profile
databse-service_1  |     |-- [4.0K]  sub1
databse-service_1  |     |   `-- [   0]  testfile_project_2_1.txt
databse-service_1  |     `-- [4.0K]  sub2
databse-service_1  |         |-- [   0]  testfile_project_2_2.txt
databse-service_1  |         |-- [   0]  testfile_project_2_3.txt
databse-service_1  |         |-- [   0]  testfile_project_2_4.txt
databse-service_1  |         `-- [   0]  testfile_project_2_5.txt
databse-service_1  | 
databse-service_1  |   42K used in 6 directories, 17 files

使用方法

正如所说的,这种方法有一些缺点。为了使这个解决方案生效,您需要运行 docker-compose down 命令。 因此,工作流程看起来类似于这样: docker-compose build && docker-compose up。 如果您更改了项目目录中的文件或者想要更新内容,必须调用 docker-compose down -v 命令,否则它仍将重复使用旧卷中预填充的内容。


解决方案2

基本上,它与解决方案1相同。不同之处在于,“项目容器”首先将源代码复制到临时位置,然后在容器启动(并挂载卷)后将其复制到卷挂载的路径。

Dockerfile

对于这个解决方案只有小的更改。

[...]
# Run now with user developer
USER developer
COPY sub1 /tmp/sub1
COPY sub2 /tmp/sub2
RUN ls -l

ADD ./entrypoint.sh /entrypoint.sh
RUN sudo chmod +x /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]

并且入口点看起来像这样

#!/bin/bash
mv /tmp/sub1 /home/developer/sub1
mv /tmp/sub2 /home/developer/sub1

# Then do your stuff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接