1. 程式人生 > 實用技巧 >宿主機nginx使用容器php-fpm處理php請求

宿主機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 [email protected]"

# 設定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測試,顯示如下畫面表示此次試驗成功。