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