有条件地在docker-compose中有条件地挂载卷

时间:2019-07-11 20:03:19

标签: docker configuration docker-compose dockerfile volumes

我使用docker和docker compose将科学工具打包到易于/普遍执行的模块中。一个示例是一个Docker,它将一个相当复杂的python库打包到一个运行jupyter笔记本服务器的容器中。这个想法是,其他不是非常精通技术的科学家可以克隆github存储库,运行docker-compose up然后进行分析,而不必安装库,配置各种插件和其他依赖项等。

我一切正常,除了我在使卷挂架以连贯的方式工作时遇到问题。原因是docker容器中的库处理多种数据集,用户将这些数据集存储在通常通过shell环境变量进行跟踪的几个单独目录中。 (请不要告诉我这样做是一种不好的方法-这是在现场完成工作的方式,而不是我选择执行的方式。)例如,如果用户存储了FreeSurfer数据,它们将具有一个名为SUBJECTS_DIR的环境变量,该变量指向包含数据的目录;如果它们存储HCP数据,则将具有环境变量HCP_SUBJECTS_DIR。但是,它们可能既有这两个,也可能没有,或者也没有。

我希望能够在docker-compose.yml文件中放入类似内容,以便处理以下情况:

version: '3'
services:
   my_fancy_library:
      build: .
      ports:
         - "8080:8888"
      environment:
         - HCP_SUBJECTS_DIR="/hcp_subjects"
         - SUBJECTS_DIR="/freesurfer_subjects"
      volumes:
         - "$SUBJECTS_DIR:/freesurfer_subjects"
         - "$HCP_SUBJECTS_DIR:/hcp_subjects"

在对此进行测试时,如果用户同时设置了两个环境变量,那么一切都会顺利进行。但是,如果它们没有其中之一,则会收到有关不装入长度少于2个字符的目录的错误消息(我将其解释为有关装入“:/ hcp_subjects”指定的卷的投诉)。 / p>

This question提出的基本要求相同,答案指向here,如果我理解正确的话,则基本上说明了如何拥有多个在某些情况下可以解决的docker-compose文件时尚。就我的情况而言,这并不是一个切实可行的解决方案,原因如下:

  • 该工具旨在供那些不一定了解docker,docker-compose或相关实用程序的人使用,因此希望他们编写/编辑自己的docker-compose.yml文件是一个问题
  • 这些目录中不止两个(我以两个示例为例),我无法为这些已声明或未声明的路径的每种可能组合制作一个docker-compose文件
  • 老实说,鉴于所需的信息就在docker-compose已经读取的变量中,因此该解决方案似乎很笨拙。

我唯一能想到的解决方案是要求用户运行脚本./run.sh而不是docker-compose up;脚本检查环境变量,写出其自己的docker-compose.yml文件和相应的卷,然后运行docker-compose up本身。这似乎也有些笨拙,但是可以。

有人知道在运行docker-compose up时根据环境变量的状态有条件地装入一组卷的方法吗?

谢谢。

2 个答案:

答案 0 :(得分:2)

您可以在.env [1] 随附的docker-compose.yml文件中为环境变量设置默认值。

通过默认将环境变量设置为/dev/null,然后在容器化应用程序中处理这种情况,您应该能够实现所需的条件。

示例

$ tree -a
.
├── docker-compose.yml
├── Dockerfile
├── .env
└── run.sh

docker-compose.yml

version: "3"

services:
  test:
    build: .
    environment:
      - VOL_DST=${VOL_DST}
    volumes:
      - "${VOL_SRC}:${VOL_DST}"

Dockerfile

FROM alpine
COPY run.sh /run.sh
ENTRYPOINT ["/run.sh"]

.env

VOL_SRC=/dev/null
VOL_DST=/volume

run.sh

#!/usr/bin/env sh
set -euo pipefail

if [ ! -d ${VOL_DST} ]; then
  echo "${VOL_DST} not mounted"
else
  echo "${VOL_DST} mounted"
fi

测试

未定义环境变量VOL_SRC

$ docker-compose up
Starting test_test_1 ... done
Attaching to test_test_1
test_1  | /volume not mounted
test_test_1 exited with code 0

定义的环境变量VOL_SRC

$ VOL_SRC="./" docker-compose up
Recreating test_test_1 ... done
Attaching to test_test_1
test_1  | /volume mounted

[1] https://docs.docker.com/compose/environment-variables/#the-env-file

答案 1 :(得分:1)

虽然@Ente的答案可以解决问题,但是当环境之间的差异更为复杂时,这是另一种解决方案。

Docker compose支持multiple docker-compose files用于在不同环境中进行配置覆盖

这很有用,例如,如果您有不同的命名卷,则可能需要根据环境将其挂载在同一路径上。

您可以修改现有服务,甚至添加新服务,例如:

# docker-compose.yml
version: '3.3'
services:
  service-a:
    image: "image-name"
    volumes:
        - type: volume
          source: vprod
          target: /data
    ports:
     - "80:8080"

volumes:
  vprod:
  vdev:

然后您具有替代文件来更改卷映射:

# docker-compose.override.yml
services:
  service-a:
    volumes:
        - type: volume
          source: vdev
          target: /data

运行docker-compose up -d时,两种配置都将与优先文件合并。

默认情况下,Docker compose会拾取docker-compose.ymldocker-compose.override.yml,如果您有更多文件或具有不同名称的文件,则需要按顺序指定它们:

docker-compose -f docker-compose.yml -f docker-compose.custon.yml -f docker-compose.dev.yml up -d