指定共享卷的数据来源

Specify origin of data for a shared volume

我有一个任务已经解决,但我对解决方案不满意。基本上,我有一个网络服务器容器 (Nginx) 和一个快速 CGI 容器 (PHP-FPM)。 Web 服务器容器构建在现成的镜像上,FCGI 容器基于自定义镜像并包含应用程序文件。现在,由于并非所有内容都是源代码并在 FCGI 容器上进行处理,我还需要使应用程序文件在 Web 服务器容器内可用。

这是执行此任务的 docker-compose.yml

version: '3.3'

services:
  nginx:
    image: nginx:1-alpine
    volumes:
      - # customize just the Nginx configuration file
        type: bind
        source: ./nginx.conf
        target: /etc/nginx/nginx.conf
      - # mount application files from PHP-FPM container
        type: volume
        source: www-data
        target: /var/www/my-service
        read_only: true
        volume:
          nocopy: true
    ports:
      - "80:80"
    depends_on:
      - php-fpm

  php-fpm:
    image: my-service:latest
    command: ["/usr/sbin/php-fpm7.3", "--nodaemonize", "--force-stderr"]
    volumes:
      - # create volume from application files
        # This one populates the content of the volume.
        type: volume
        source: www-data
        target: /var/www/my-service

volumes:
  # volume with application files shared between nginx and php-fpm
  www-data:

我不喜欢这里的地方主要反映在有关卷的评论中。谁创建和存储数据应该从代码而不是评论中显而易见。另外,我真正不喜欢的是 docker 实际上创建了一个地方来存储该卷的数据。这不仅会耗尽磁盘 space 并增加启动时间,还要求我永远不要忘记使用 docker-compose down --volumes 以便在下次启动时刷新内容。想象一下当我发现 down 没有拆除 up 创造的东西并且我正在寻找以前运行的幽灵时我的愤怒。

我的问题是:

您可以使用带选项 type=tmpfslocal 驱动程序,例如:

volumes:
  www-data:
    driver: local
    driver_opts:
      type: tmpfs
      device: tmpfs

哪个将符合您的要求:

  • 数据将在运行时在容器之间共享
  • 数据不应持久化,即当容器停止、重新启动或销毁时卷将被清空

这是 CLI 等效于

docker volume create --driver local --opt type=tmpfs --opt device=tmpfs www-data

重要说明:这不是 Docker tmpfs 坐骑,而是 Docker volume 使用 tmpfs 选项 。正如 local volume driver documentation it uses the Linux mount 选项中所述,在我们的例子中 --types 指定一个 tmpfs 文件系统。与简单的 tmpfs 挂载相反,它将允许您在容器之间共享卷,同时保留临时文件系统的经典行为

I can't find documentation for available volume drivers or even explore which volume drivers exist

Can I express in code that one container contains data that should be made available to other containers more clearly? The above code works, but it fails utterly to express the intent.

我不这么认为,关于本卷的意图,您的代码已经很清楚了:

  • 这就是卷的用途:在容器之间共享数据。正如文档中所述 卷可以更安全地在多个容器 之间共享,而且只有容器应该写入卷。
  • nocopyread_only 明确表示 nginx 依赖于另一个容器写入的数据,因为它只能从该卷中读取
  • 鉴于您的卷不是 external,可以安全地假设只有同一堆栈中的另一个容器可以使用它
  • 一些关于 Docker 的逻辑和经验可以让我们快速回到前一点,但即使对于经验不足的 Docker 用户,您的评论也给出了明确的指示,您的注释是代码的一部分 ;)

您还可以使用 php 图像

中的静态副本制作自定义 nginx 图像

这里是 nginx 的 Dockerfile

FROM my-service:latest AS src-files

FROM nginx
COPY --from=src-files /path-to-static-in-my-service-image /path-to-static-in-nginx

这将允许您不使用带有源代码的卷

也可以在 Dockerfile 中使用环境变量中的 TAG

FROM my-service:${TAG} AS src-files
...

这取决于您设置的用例。如果它仅适用于本地开发人员,或者如果您想要在生产环境中使用同样的东西。在开发人员中,手动填充卷或由一个容器为其他容器填充卷可能没问题。

但如果您想要在生产中以相同方式 运行 的东西,您可能需要其他东西。例如,在生产中,我不想将我的代码放在卷中,而是以不可变的方式放在我的映像中,我只需要重新部署它。

对我来说,卷不是用于存储应用程序代码,而是用于存储缓存、用户上传内容等数据。我们希望在部署之间保留一些东西。

所以,如果我们想要 2 个具有相同文件的图像而不在一个卷中,我将使用应用程序代码和静态内容构建 2 个图像,一个用于 php,一个用于 nginx。

但是这两个图像的部署通常是不同步的。我们通过先部署 PHP 应用程序然后部署 nginx 应用程序来解决这个问题。在 nginx 上,我们添加了一个配置,它首先尝试从中提供静态内容,如果该文件不存在,则向 PHP.

询问

对于开发环境,我们将重用相同的图像,但使用卷将当前代码挂载到容器内(主机绑定挂载)。

但在某些情况下,绑定挂载可能会出现一些问题: - 在 Mac 上,文件共享速度很慢,但在 Edge 频道 (2.3.1.0) 中使用最新版本的 Docker 桌面应该会更好 - 在 Windows 上,文件共享也很慢 - 在 Linux 上,我们需要注意容器内使用的文件权限和用户

如果您尝试使用卷解决方案解决 one/many 个问题,我们可以找到一些解决方案。例如,在 Mac 上,我将首先尝试 docker 的 Edge 版本,在 Windows 上,如果可能,我将使用 WSL2 并且 Docker 设置为使用 WSL2 后端。