宿主机nginx使用容器php-fpm处理php请求

宿主机Nginx使用php容器解析php请求

环境说明

首先,我在宿主机上已经运行了一个nginx

[root@localhost html]# nginx -v
nginx version: nginx/1.18.0

宿主机上也安装运行了docker

[root@localhost html]# docker version
Client: Docker Engine - Community
 Version:           20.10.2
...

需求:在docker里面运行php容器,然后用php容器来解析所有访问nginx的php请求。

基于alpine定制php-fpm容器

php官方基础镜像缺少很多扩展,一般情况下不满足实际项目的运行,所以需要定制一个符合项目运行环境的php镜像。

了解php基础镜像

php的官方镜像分为三个分支:

  • cli :没有开启CGI,也就是不能运行fpm,只能运行命令行。
  • fpm :开启了CGI,可以用来运行web服务也可以运行cli命令。
  • zts :开启了线程安全的版本。

一般来说,lnmp环境使用 fpm即可。

镜像选择

这里我使用的php官方镜像是: php:7.3.23-fpm-alpine。php版本为7.3.23,是基于Alpine Linux 3.12基础镜像构建的,所以镜像体积会比较小。

默认官方的镜像有如下扩展:

/var/www/html # php -m
[PHP Modules]
Core
ctype
curl
date
dom
fileinfo
filter
ftp
hash
iconv
json
libxml
mbstring
mysqlnd
openssl
pcre
PDO
pdo_sqlite
Phar
posix
readline
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib

[Zend Modules]

除了以上扩展,我们还需要安装一些其他扩展:

  • redis
  • gd
  • mysqli
  • pdo_mysql
  • opcache
  • zip
  • bcmatch等
构建准备
# 创建目录
$ mkdir -p /root/docker/php
$ cd /root/docker/php

# 创建配置文件目录
$ mkdir conf.d

# 设置php时区为东八区
$ echo "date.timezone = Asia/Shanghai" >> conf.d/date.ini

# 设置opcode默认的参数
$ cat >> conf.d/opcode.ini << EOF
opcache.enable=${OPCODE}
enable_clopcache.enable_cli=1
opcache.revalidate_freq=60
opcache.max_accelerated_files=100000
opcache.validate_timestamps=1
EOF

# 设置alpine的apk源为国内源
$ cat >> repositories <<EOF
http://mirrors.aliyun.com/alpine/v3.12/main
http://mirrors.aliyun.com/alpine/v3.12/community
EOF

# 准备php-fpm配置文件
$ cat >> www.conf << EOF
[www]
user = www
group = www
listen = 0.0.0.0:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOF

# 项目目录结构如下:
[root@localhost php]# tree .
.
├── conf.d
│   ├── date.ini
│   └── opcode.ini
├── Dockerfile
├── repositories
└── www.conf

最终的Dockerfile文件如下:

FROM php:7.3.23-fpm-alpine

LABEL maintainer="syushin 1147070314@qq.com"

# 设置apk源为阿里云
COPY repositories /etc/apk/repositories
COPY ./conf.d/ $PHP_INI_DIR/conf.d/

ENV TZ "Asia/Shanghai"
ENV TERM xterm
# 默认关闭opcode
ENV OPCODE 0

# 添加用户
RUN addgroup -g 1000 -S www && adduser -s /sbin/nologin -S -D -u 1000 -G www www

# PHPIZE_DEPS 包含 gcc g++ 等编译辅助类库,完成编译后删除
RUN apk add --no-cache $PHPIZE_DEPS     && apk add --no-cache libstdc++ libzip-dev vim    && apk update     && pecl install redis-4.3.0     && pecl install zip     && pecl install swoole     && docker-php-ext-enable redis zip swoole    && apk del $PHPIZE_DEPS

# 安装扩展
RUN apk add --no-cache        freetype        libpng        libjpeg-turbo        freetype-dev        libpng-dev        jpeg-dev        libjpeg        libjpeg-turbo-dev        libwebp        libwebp-dev     && docker-php-ext-configure gd --with-gd --with-webp-dir --with-jpeg-dir        --with-png-dir --with-zlib-dir --with-freetype-dir     && NUMPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1)     && docker-php-ext-install -j${NUMPROC} gd     && docker-php-ext-install -j${NUMPROC} pdo_mysql     && docker-php-ext-install -j${NUMPROC} opcache     && docker-php-ext-install -j${NUMPROC} bcmath \ 
    && docker-php-ext-install -j${NUMPROC} mysqli
# 拷贝配置文件
COPY  www.conf /usr/local/etc/php-fpm.d/www.conf

RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

说明:

  • PHP_INI_DIR:这个环境变量是在php的基础镜像Dockerfile中有定义
  • PHPIZE_DEPS:这个也是定义在基础镜像Dockerfile中,包含了扩展编译安装时需要但是php运行不需要的linux软件库。我们需要把它们挑选出来,在编译完扩展之后删除。

构建:

# 创建构建命令脚本文件
$ cd /root/docker/php
$ cat >>  build-comand.sh << EOF
#/bin/bash
docker build -t myphp:7.3.23-alpine .
EOF 

# 执行构建
$ sh build-comand.sh
构建完成检查

构建完成之后,进入容器,检查定制的容器。

# 进入容器
[root@localhost php]# docker run -it --rm myphp:7.3.23 sh
/var/www/html # php -m
[PHP Modules]
bcmath
Core
ctype
curl
date
dom
fileinfo
filter
ftp
gd 	 # 安装的扩展
hash
iconv
json
libxml
mbstring
mysqli # 安装的扩展
mysqlnd # 安装的扩展
openssl
pcre
PDO
pdo_mysql # 安装的扩展
pdo_sqlite
Phar
posix
readline
redis # 安装的扩展
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
swoole
tokenizer
xml
xmlreader
xmlwriter
Zend OPcache
zip # 安装的扩展
zlib

[Zend Modules]
Zend OPcache

/var/www/html # id www # 用户也创建了
uid=1000(www) gid=1000(www) groups=1000(www),1000(www)

# 配置文件也拷贝进来了
/var/www/html # cat /usr/local/etc/php-fpm.d/www.conf
[www]
user = www
group = www
listen = 0.0.0.0:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

这样,一个自定义的php-fpm镜像就定制完成。

Nginx使用容器php-fpm进行解析

Nginx是在宿主机上,所以先定义一个Nginx的虚拟主机配置文件:

server{
    listen 80 default_server;
    server_name syushin.com;
    index index.html index.htm index.php;
    root /var/www/html;

    location ~ \.php$
    {
        root /var/www/html;
        include fastcgi_params;
        fastcgi_pass 0.0.0.0:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

这里,location php里面的root很重要,这里要填php容器中php项目所在目录 而不是nginx宿主机的web路径。以往的nginx和php都在同一台机器上时不存在这个问题,现在nginx和php算是分开的,所以需要注意一下。fastcgi_param 参数配置的是nginx请求php-fpm时需要带过去的参数,SCRIPT_FILENAME 表示fpm要执行的PHP文件的路径,而 $document_root的值 就是前面的 root 参数的值,所以root要配置成php容器中的php路径。fastcgi_pass 这里的ip地址可以使用php容器的ip,这里我打算使用端口映射的方式启动php容器,用宿主机9000端口映射php容器的9000端口,所以这里直接写 0.0.0.0:9000了。

启动自定义的php容器

$ docker run --itd -v /home/wwwroot/syushin:/var/www/html -p 9000:9000 --name myphp myphp:7.3.23

创建站点目录和测试文件

$ mkdir -p /home/wwwroot/syushin
$ cat index.php 
<?php
echo phpinfo();
?>

$ nginx -t 
$ nginx -s reload

浏览器访问宿主机IP测试,显示如下画面表示此次试验成功。

宿主机nginx使用容器php-fpm处理php请求

宿主机nginx使用容器php-fpm处理php请求

上一篇:PHP的变量赋值


下一篇:如何在 Angular CLI 创建的项目中自定义 webpack 配置