【问题标题】:Combining PHP-fpm with nginx in one dockerfile [closed]在一个 dockerfile 中结合 PHP-fpm 和 nginx [关闭]
【发布时间】:2021-07-25 21:48:50
【问题描述】:

我需要将 php-fpm 与 nginx 结合在一个 dockerfile 中以进行生产部署。

那么是不是更好:

(1) 使用 php:7.1.8-fpm 启动 dockerfile,然后在上面安装 nginx 镜像层?

(2) 或者你推荐使用 nginx 镜像,然后使用 apt-get 安装 php-fpm ?

PS:我没有用于生产部署的 docker-compose 构建选项。在我的开发环境中,我已经使用 docker-compose 并从两个图像轻松构建多容器应用程序。我们的组织 devops 不支持基于 docker-compose 的 prod 环境部署。

【问题讨论】:

  • “更好”是什么意思?你想达到什么目标?
  • 我不明白这个问题为什么这么着急就结束了。好的。更好的是,这将是最短的 docker 文件,不需要太多的 dockerfile 语句,也可以减少容器的大小。了解 docker 容器的人在理解更好的方法恕我直言时不会有任何问题。

标签: php docker nginx dockerfile fpm


【解决方案1】:

Nginx 的安装比 PHP 容易得多,所以你应该更容易将 Nginx 安装到一个现成的官方 PHP 映像中。下面是一个 Dockerfile 示例,展示了如何通过安装一些 PHP 扩展的示例来实现您的目标:

FROM php:7.2-fpm

RUN apt-get update -y \
    && apt-get install -y nginx

# PHP_CPPFLAGS are used by the docker-php-ext-* scripts
ENV PHP_CPPFLAGS="$PHP_CPPFLAGS -std=c++11"

RUN docker-php-ext-install pdo_mysql \
    && docker-php-ext-install opcache \
    && apt-get install libicu-dev -y \
    && docker-php-ext-configure intl \
    && docker-php-ext-install intl \
    && apt-get remove libicu-dev icu-devtools -y
RUN { \
        echo 'opcache.memory_consumption=128'; \
        echo 'opcache.interned_strings_buffer=8'; \
        echo 'opcache.max_accelerated_files=4000'; \
        echo 'opcache.revalidate_freq=2'; \
        echo 'opcache.fast_shutdown=1'; \
        echo 'opcache.enable_cli=1'; \
    } > /usr/local/etc/php/conf.d/php-opocache-cfg.ini

COPY nginx-site.conf /etc/nginx/sites-enabled/default
COPY entrypoint.sh /etc/entrypoint.sh

COPY --chown=www-data:www-data . /var/www/mysite

WORKDIR /var/www/mysite

EXPOSE 80 443

ENTRYPOINT ["/etc/entrypoint.sh"]

nginx-site.conf 文件包含您的 Nginx http 主机配置。以下示例适用于 Symfony 应用程序:

server {
    root    /var/www/mysite/web;

    include /etc/nginx/default.d/*.conf;

    index app.php index.php index.html index.htm;

    client_max_body_size 30m;

    location / {
        try_files $uri $uri/ /app.php$is_args$args;
    }

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        # Mitigate https://httpoxy.org/ vulnerabilities
        fastcgi_param HTTP_PROXY "";
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index app.php;
        include fastcgi.conf;
    }
}

entrypoint.sh 会在容器启动时运行 Nginx 和 php-fpm(否则只会启动 php-fpm 作为官方 PHP 镜像的默认操作):

#!/usr/bin/env bash
service nginx start
php-fpm

当然,从最佳实践的角度来看,这不是最好的方法,但我希望这是您问题的答案。

更新:

如果您在 entrypoint.sh 文件上收到权限被拒绝错误,如果您是在 Linux 下构建,请检查此文件是否具有可执行权限,或者如果您在 Windows 下,请将 RUN chmod +x /etc/entrypoint.sh 添加到 Dockerfile ( Windows 下的所有文件都在没有容器可执行权限的情况下复制。

如果您在 Google Cloud Run 下运行,请记住 Nginx 在 PHP 之前启动,它比 PHP 快得多。这就导致了Cloud Run发送第一个请求的时候,Nginx已经初始化了,但是PHP-FPM还没有,Cloud Run请求失败。要解决这个问题,您应该将入口点更改为在 Nginx 之前启动 PHP-FPM:

#!/usr/bin/env sh
set -e

php-fpm -D
nginx -g 'daemon off;'

此脚本仅在 Alpine Linux 下进行测试。我想它也应该适用于其他图像。该脚本首先在后台运行 php-fpm,然后在不退出的情况下运行 Nginx。这样,Nginx 总是在 PHP-FPM 初始化后开始监听端口。

【讨论】:

  • 使用ENTRYPOINT ["sh", "/etc/entrypoint.sh"] 可以避免出现permission denied 错误。
  • 并在 COPY 后添加“RUN chmod +x /etc/entrypoint.sh”将防止权限错误。
  • 您说这样做不是最佳做法。你能推荐另一种方法吗?
  • 最佳实践是每个容器保留一项服务。在单个容器中混合多个服务可能会导致长期支持此类 dockerfile 的问题。我并不是说有更好的方法来实现主题问题。我的意思是组合不是一个完美的方式。
  • 虽然这可能不是“最佳” docker 实践,但在某些环境中您只能部署单个容器(如 google cloud run),这是唯一可行的方法。
【解决方案2】:

您应该部署两个容器,一个带有fpm,另一个带有nginx,您应该将它们链接起来。 即使您可以使用supervisor 来监控同一个容器中的多个进程,Docker 的理念是每个容器有一个进程。

类似:

docker run --name php -v ./code:/code php:7-fpm
docker run --name nginx -v ./code:/code -v site.conf:/etc/nginx/conf.d/site.conf --link php nginx:latest

site.conf

server {
    index index.php index.html;
    server_name php-docker.local;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /code;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

(可耻地受到http://geekyplatypus.com/dockerise-your-php-application-with-nginx-and-php7-fpm/的启发)

【讨论】:

  • 问题是我们的 DevOps 只需要一个 docker 文件并重用他们现有的部署堆栈脚本,该脚本只执行 docker build 一次,然后 docker run。规则是一个单一的服务应该有一个单一的 dockerfile。如果我必须像上面提到的那样运行多个容器,那么使用 docker-compose 会更简单(我有它用于开发......但生产环境是另一回事)。
  • 当我在一个容器中同时运行 php-fpm 和 nginx 时,fastcgi_pass 将指向 unix sock 文件或 127.0.0.1:9000
  • 如果你真的只需要使用一张图片,你应该从debianalpine开始,安装nginxphp-fpm,然后运行supervisord。另一种可能性是使用apache,它不需要其他进程即可使用 PHP。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-30
  • 1970-01-01
  • 2012-04-17
  • 2023-03-19
  • 2017-11-19
  • 2014-02-28
  • 2011-04-06
相关资源
最近更新 更多