为了账号安全,请及时绑定邮箱和手机立即绑定

Dockerize 用于生产的 PHP 应用程序

Dockerize 用于生产的 PHP 应用程序

PHP
杨__羊羊 2022-06-17 16:26:17
我们有一个 PHP(特别是 Laravel)应用程序,应该针对生产环境进行 docker 化。但是与 Web Server 和 PHP-FPM 容器共享应用程序源代码存在问题。Nginx 和 PHP-FPM 都应该可以访问应用程序源代码,所以这里是网络上建议的解决方法:为 Nginx 和 PHP-FPM 提供两个独立的容器,并将源代码安装在主机上并创建一个卷。然后,将此卷分配给这些容器。这个解决方案是不需要的,因为每次应用程序代码更改时,都应该重新构建整个堆栈并且应该刷新创建的卷。此外,这些任务应该在我们所有的服务器上执行,这可能会浪费很多时间。将 PHP-FPM 和 Nginx 放在同一个容器上,并保持它们的进程使用supervisor脚本entrypoint运行。在这个解决方案中,当源代码发生变化时,我们构建一次镜像,希望没有共享卷被刷新,所以这似乎是一个很好的解决方法。但是,这个解决方案的主要问题是它违反了容器化背后的理念。Docker在其文档中说:每个容器应该有一个关注点(或正在运行的进程)。但是在这里,我们有两个正在运行的进程!是否有其他可能适用于生产环境的解决方案?不得不提一下,我们将在不久的将来使用Swarm或Kubernetes 。
查看完整描述

2 回答

?
手掌心

TA贡献1942条经验 获得超3个赞

一般来说,这两种方法在生产中都应该避免,但是如果我比较卷挂载和每个容器两个进程,我会选择每个容器两个进程,而不是将主机代码挂载到容器,


在某些情况下,第一种方法会失败,例如Fargate的情况,其中没有一种无服务器的主机,那么在这种情况下,您肯定会为每个容器运行两个进程。


每个容器运行多个进程的主要问题是“如果 php-fpm 关闭并且 Nginx 进程正在运行怎么办”。但是您可以使用多种方法处理这种情况,您可以通过 docker 文档查看建议的方法。


docker-multi-service_container


docker 文档使用自定义脚本或 supervisord 覆盖了这个场景。


如果你需要在一个容器中运行多个服务,你可以通过几种不同的方式来完成。


将所有命令放在一个包装脚本中,并附上测试和调试信息。将包装脚本作为您的 CMD 运行。这是一个非常幼稚的例子。首先,包装脚本:

#!/bin/bash


# Start the first process

./my_first_process -D

status=$?

if [ $status -ne 0 ]; then

  echo "Failed to start my_first_process: $status"

  exit $status

fi


# Start the second process

./my_second_process -D

status=$?

if [ $status -ne 0 ]; then

  echo "Failed to start my_second_process: $status"

  exit $status

fi


# Naive check runs checks once a minute to see if either of the processes exited.

# This illustrates part of the heavy lifting you need to do if you want to run

# more than one service in a container. The container exits with an error

# if it detects that either of the processes has exited.

# Otherwise it loops forever, waking up every 60 seconds


while sleep 60; do

  ps aux |grep my_first_process |grep -q -v grep

  PROCESS_1_STATUS=$?

  ps aux |grep my_second_process |grep -q -v grep

  PROCESS_2_STATUS=$?

  # If the greps above find anything, they exit with 0 status

  # If they are not both 0, then something is wrong

  if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then

    echo "One of the processes has already exited."

    exit 1

  fi

done

使用像 supervisord 这样的流程管理器。这是一种中等重量的方法,需要您将 supervisord 及其配置打包到您的镜像中(或基于包含 supervisord 的镜像)以及它管理的不同应用程序。然后你启动 supervisord,它会为你管理你的流程。这是一个使用这种方法的 Dockerfile 示例,假设预先编写的 supervisord.conf、my_first_process 和 my_second_process 文件都与 Dockerfile 存在于同一目录中。

但是,如果您正在寻找主管,则可以在其中一个程序被杀死后检查关闭主管以及其他类似的方法来监视该过程。


查看完整回答
反对 回复 2022-06-17
?
森栏

TA贡献1810条经验 获得超5个赞

您可以创建两个单独的 Docker 映像,一个仅包含您的静态资产,另一个包含可运行的后端代码。静态资产图像可以最小为


# Dockerfile.nginx

FROM nginx:latest

COPY . /usr/share/nginx/html

不要在任何地方绑定安装任何东西。让你的 CI 系统构建两个镜像


TAG=20191214

docker build -t myname/myapp-php:$TAG .

docker build -t myname/myapp-nginx:$TAG -f Dockerfile.nginx .

现在您可以运行两个单独的容器(不违反每个容器一个进程的准则),独立扩展它们(3 个 nginx 但 30 个 PHP),而不必手动复制您的源代码。


另一种有用的技术是将您的静态资产发布到一些外部托管系统;如果您无论如何都在 AWS 中运行,那么 S3 在这里运行良好。您仍然需要某种代理来将请求转发到资产商店或后端服务,但现在可以只是带有自定义配置文件的 Nginx;它不需要您的任何应用程序代码。(在 Kubernetes 中,您可以使用指向带有nginx.conf文件的配置映射的 Nginx 部署来运行它。)


当你设置你的 CI 系统时,你绝对不应该在构建或集成测试时将挂载代码绑定到你的容器中。测试您正在构建的容器中的实际内容,而不是源代码的其他副本。您可以创建两个单独的 Docker 映像,一个仅包含您的静态资产,另一个包含可运行的后端代码。静态资产图像可以最小为


# Dockerfile.nginx

FROM nginx:latest

COPY . /usr/share/nginx/html

不要在任何地方绑定安装任何东西。让你的 CI 系统构建两个镜像


TAG=20191214

docker build -t myname/myapp-php:$TAG .

docker build -t myname/myapp-nginx:$TAG -f Dockerfile.nginx .

现在您可以运行两个单独的容器(不违反每个容器一个进程的准则),独立扩展它们(3 个 nginx 但 30 个 PHP),而不必手动复制您的源代码。


另一种有用的技术是将您的静态资产发布到一些外部托管系统;如果您无论如何都在 AWS 中运行,那么 S3 在这里运行良好。您仍然需要某种代理来将请求转发到资产商店或后端服务,但现在可以只是带有自定义配置文件的 Nginx;它不需要您的任何应用程序代码。(在 Kubernetes 中,您可以使用指向带有nginx.conf文件的配置映射的 Nginx 部署来运行它。)


当你设置你的 CI 系统时,你绝对不应该在构建或集成测试时将挂载代码绑定到你的容器中。测试您正在构建的容器中的实际内容,而不是源代码的其他副本。


查看完整回答
反对 回复 2022-06-17
  • 2 回答
  • 0 关注
  • 140 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号