Docker,docker撰写和在项目之间复制文件

时间:2020-09-02 11:07:35

标签: docker docker-compose dockerfile

我有以下设置。

文件夹结构

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
    ...
...

project-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

好的,我明白了,上下文不允许我升级。 然后将上下文移至根,然后从那里运行project / 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会持续相当长的时间。这意味着每次运行时。我猜这是由于现在project-db的上下文是整个文件夹结构。

因此,我尝试使用.dockerignore过滤掉不需要的文件夹:

.dockerignore

project3
project3/**
project4
project4/**
project5
project5/**
...

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

我无法使其正常工作。 另外-我无法摆弄现有项目的内部结构。

这是怎么了?

1 个答案:

答案 0 :(得分:1)

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


解决方案1 ​​

缺点

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

  • 您需要清理卷。卷在首次创建时仅填充有容器的内容。有关说明,请参见here。 因此,如果项目目录中的某些文件已更改,docker-compose down -v 必须完成
  • 一种docker-compose down -v`` is to manually delete the named volumes using 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

它们几乎相同。 * 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输出(请参见结果):

#!/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