【问题标题】:Serving new static files via nginx stored in php-fpm container after update更新后通过存储在 php-fpm 容器中的 nginx 提供新的静态文件
【发布时间】:2020-05-16 10:10:22
【问题描述】:

我有以下容器:

  • nginx:latest
  • myapp 容器(源自 php-fpm:alpine)

目前我有一个带有 CI 管道的虚拟项目,它在构建时编译资源的生产变体(图像/js/css,...)。构建文件最终位于 (/public/build) 中。在 CI 管道的最后,我将所有内容打包成 Docker 镜像并上传到 Hub。

nginxmyapp 都设置了卷(不是绑定挂载)并指向 /opt/ci-test/public/build

这是第一次。

但假设我添加了一个新文件 new.css - 我的新版本 docker 映像将包含 new.css 的构建变体。

运行具有预先存在的卷的新容器不会显示新文件我知道它不应该。。我可以创建一个新卷my_app_v2

此时nginx 看不到这个新卷,必须将其删除并重新运行(使用新卷)才能生效。

有没有简单的方法可以克服这个问题?

我的意图是为多个 PHP 应用程序使用 nginx 容器,并且每当我更新其中一个正在服务的应用程序时,我都需要避免杀死它。这是一个糟糕的决定吗?

编辑:

我设法挖掘出的一种解决方法是从附加卷中删除所有文件并启动新的myapp 容器。这会将所有最新文件镜像到卷。但这感觉很脏……

编辑2:

相关问题(案例3):https://github.com/moby/moby/issues/18670#issuecomment-165059630

EDIT3:

Dockerfile

FROM  php:7.2.30-fpm-alpine3.11

COPY . /opt/ci-test
WORKDIR /opt/ci-test

VOLUME /opt/ci-test/public/build

到目前为止,我没有docker-composer,我通过命令手动运行容器:

docker run -it -d --name php71alp -v shr_test:/opt/ci-test/public/build -p 9000:9000 <myaccount>/citest
docker run -it -d --name nginx -v shr_test:/var/www/citest -p 80:80 nginx:latest

【问题讨论】:

  • 你在使用 docker-compose 吗?你能说说你的环境怎么样?
  • 发布您的docker-composeDockerfile 详细信息
  • 大家好,很抱歉延迟回答。 @Dilson:我仍然不使用docker-compose,所以我通过docker run 命令同时运行nginx 和我的容器。 @Tarun:我为我的应用添加了Dockerfile。这真的很简单,因为它是用于 POC 目的的测试图像。谢谢!

标签: php docker nginx fpm


【解决方案1】:

不要为此使用音量。

您应该将 docker 映像视为“整体包”,其中包含您的依赖项 (nginx) 和应用程序的文件(图像、js、css...)。没有必要将您的应用程序文件与 nginx 本身区别对待,它都是单个 docker 映像的一部分。

如果没有卷,则运行 v1 映像,nginx 会看到 v1 文件。您运行映像的 v2,nginx 会看到 v2 文件。

当您真正想要在容器版本之间保存文件(例如数据库、文件上传...)时,可以使用卷。不适用于您网站的静态资产。

我的意图是为多个 PHP 应用程序使用 nginx 容器,并且每当我更新其中一个正在服务的应用程序时,我都需要避免杀死它。这是一个糟糕的决定吗?

是的,这是糟糕的设计。如果要运行多个应用程序,则应为每个应用程序运行 1 个 Docker 容器。这样,当您发布一个应用程序的新版本时,您只需要重新启动该容器。容器不应该被视为传统的虚拟机,您可以“SSH 进入”并手动配置。容器是“扔掉的”。新版本的应用程序?只需将容器替换为具有更新图像的新容器即可。

【讨论】:

  • 我明白你的意思,但我想消除不必要的 FPM 之旅并通过前端控制器传递请求,而事实上我知道那些不可能是 PHP 请求。从性能的角度来看,这是完全合理的。关于答案的第二部分:那么我应该如何托管多个应用程序(是的,单独的 FPM 容器)?我仍然需要单个 nginx(监听端口 80/443)容器,不是吗?
  • 对于托管多个应用程序,我这样做的方式是运行绑定到 localhost:8000、localhost:8001 等的容器,并在主机(不是容器)中使用单个 nginx许多虚拟服务器将 proxy_pass 传递到正确的容器端口。
  • 对于 nginx 与 fpm 的事情,我建议您从同一个容器中运行两者,因此每个应用程序有 1 个图像,而不是 2 个。这样更易于管理。您仍然可以将 nginx 配置为直接提供静态文件,并仅将 PHP 请求传递给 FPM。使用类似 supervisord 的东西在同一个容器中运行 2 个进程。通过这种方式,静态文件请求(主机 nginx)->(容器 nginx)->(文件)。 PHP 请求做 (host nginx) -> (container nginx) -> (FPM) -> (PHP files, DB..)
  • 在主机上运行 nginx 的另一个好处是您可以将其用于 TLS 终止。如果您想使用 certbot(让我们加密)来做到这一点,您只需管理主机上的一个实例,这更容易。另外,不用担心额外的主机 nginx 之旅,nginx 反向代理非常快,并且您获得的额外灵活性(例如能够轻松运行多个应用程序)非常值得。
  • 这是一个关于我如何在单个容器中执行 nginx+fpm 的示例:Dockerfileconfig files。随意复制它(BSD 许可证)。
【解决方案2】:

第一个选项:不要使用音量。如果您希望从映像构建中访问文件,并且不需要持久性,那么卷对您的工作流程没有帮助。

第二个选项:在运行之间删除之前的卷并使用命名卷,docker 将使用图像内容进行初始化。

第三个选项:修改镜像构建和容器入口点以在构建过程中将目录保存到不同的位置,并在入口点中的容器启动时将该位置恢复到卷中。我在save-volume and load-volume scripts in my base image 中有一个实现。当您想要将卷的内容与主机的内容合并时,它会变得更加复杂,您需要决定如何处理被删除的文件以及从以前的运行中保存哪些更改。

【讨论】:

  • 谢谢BMitch!我需要公开build 的唯一原因是nginx 可以直接提供这些静态文件。我不想将静态请求传递给 php 前端控制器。
  • 第三个选项似乎最接近我想要实现的目标。让我看看那个。从我的设置的外观来看,不需要合并 - 这就是为什么擦拭卷清洁确实可以完成这项工作(感觉很脏)
猜你喜欢
  • 1970-01-01
  • 2020-06-17
  • 2011-01-27
  • 1970-01-01
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多