CentOS 7 下 PHP 多版本部屬方式

最近我的 Server 升級到 CentOS 7 還有 PHP7,其實有以前的舊專案要測試會出點相容性問題,因此要讓新的 Server 能夠跑多個版本的 PHP,目前比較好的做法是用 SCL 的方式跑多個版本比較好管理,CentOS 官方本身有收納,可以看 http://mirror.centos.org/centos/7/sclo/x86_64/rh/ ,但官方僅收錄 php54 和 php55,其實是很少的。

我一直都是使用 Remi's RPM repository 提供的 PHP 套件來部屬,所以接下來介紹的也是使用 Remi 提供的 SCL 方式來部屬多版本 PHP。

部屬目標

  • Nginx + php-fpm (Fast CGI 模式)
  • php 5.6
  • php 7.0
  • PHP 主要版本是 7.0

安裝 Remi Repo

可以參見 http://blog.remirepo.net/pages/Config-en 有所有版本的 CentOS 安裝方式,CentOS 7 的方式如下 :

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm

安裝 PHP 7.0 成為主要版本

yum --enablerepo=remi,remi-php70 install php php-fpm

這段下了之後會有 php cli 和 php-fpm 能用,我們未來跑的主要版本就是這個版本了。

安裝 PHP 5.6

yum --enablerepo=remi install php56 php56-php-fpm

這段下了之後,Server 上會有 PHP 5.6 的套件,但是套件內所有檔案會放在 /opt/remi/php56/root,看下圖列出的目錄結構,應該不難想像,就是模擬整個環境,因此所有設定都可以往這去修改,這不會影響到我們的主要版本。

remi-php56

CLI 模式下測試多版本運作

主要版本 PHP 7.0

[root@localhost root]# php -v
PHP 7.0.0 (cli) (built: Dec  1 2015 17:53:27) ( NTS )
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologies

這就是一般的方式執行了,接下來是 PHP 5.6

[root@localhost root]# scl enable php56 "php -v"
PHP 5.6.16 (cli) (built: Nov 26 2015 07:03:47)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies

或者也可以用絕對路徑

[root@localhost root]# /opt/remi/php56/root/bin/php -v
PHP 5.6.16 (cli) (built: Nov 26 2015 07:03:47)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies

更簡單點

[root@localhost root]# php56 -v
PHP 5.6.16 (cli) (built: Nov 26 2015 07:03:47)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies

 

到目前為止,看來 CLI 的部分確實能確認有多個版本的 PHP,如果也想要安裝 php 5.5 ,Remi Repo 也是有包的,目前是知道 php54 , php55 , php56 , php70 都有包成 SCL。

PHP-FPM 多版本運作

我們現在有了主要版本(7.0) 和 5.6 了,但是網站的部分必須要讓 php-fpm 兩種版本同時跑起來。

現在有個問題,預設情況下,php-fpm 的設定檔會以 tcpip port 9000 當作 fastcgi 監聽 port,那麼兩個版本並存怎麼辦 ?

所以一定要分別設定,主要版本我們可以不用動,但是 php56 的就要動了,也許可以將 php56 的監聽 port 改成 9001 也行,不過我比較喜歡 Unix Socket ,效率比較好,而且 Unix Socket 設定法在 CentOS 7 可能會遇到一些些權限問題,所以拿來介紹比較好

我以環境是 nginx 為例子,要修改的比較多,如果是跑 Apache ,其實不需要修改很多,可以斟酌

修改預設的 php-fpm.d/www.conf 設定檔,底下先以主要版本 PHP70 為例子,PHP56 也一樣可以如法炮製

  1. 用編輯器打開 /etc/php-fpm.d/www.conf
  2. 將 listen = 127.0.0.1:9000 這一行改成 listen = /var/run/php-fpm/php70-fpm.sock
  3. 將 user = nobody 及 group = nobody 改成  user = nginx 及 group = nginx
  4. 將 listen.owner 及 listen.group 改成 nginx
  5. 將 php_admin_value[error_log] 設定為 /var/log/nginx/php-fpm-error.log
  6. 將 php_value[session.save_path] 設定為 /var/lib/php/session-nginx
  7. 將 php_value[soap.wsdl_cache_dir] 設定為 /var/lib/php/wsdlcache-nginx
  8. 存檔

接下來建立一些目錄及檔案

touch /var/log/nginx/php-fpm-error.log
chown nginx:adm /var/log/nginx/php-fpm-error.log
mkdir /var/lib/php/session-nginx
chown root:nginx /var/lib/php/session-nginx
mkdir /var/lib/php/wsdlcache-nginx
chown root:nginx /var/lib/php/wsdlcache-nginx

建立這些目錄及檔案其實是不想去修改 php-fpm 預設搭配 Apache 的目錄結構而已,所以另外設定給 nginx 用。

上述的過程中  listen = /var/run/php-fpm/php70-fpm.sock 這個要特別說明,因為 CentOS 7.1(或 RHEL 7.1) 的 systemd 導入了 PrivateTmp 的方式,如果我們將 Unix Socket 建立在 /tmp 或 /var/tmp ,其實會有權限問題,將來可能 Nginx 無法連上 php-fpm,解決的方法就是避開 /tmp 或 /var/tmp,又或者是修改 systemd 的 php-fpm 設定檔將 PrivateTmp 設為 false 也行。

主要版本都設定好了,PHP56 這個版本設定的方式一樣,但是請注意 PHP56 的路徑要由 /opt/remi/php56/root ,不要和主要版本一樣免得出問題。

PHP56 的 php-fpm/www.conf 是在 /opt/remi/php56/root/etc/php-fpm.d 底下,直接修改即可

都修改好之後,啟動兩個版本的 php-fpm 試試看

執行以下命令

systemctl enable php-fpm
systemctl start php-fpm
systemctl enable php56-php-fpm
systemctl start php56-php-fpm

上述分別設定 php 兩個版本於開機時啟動,而且也一併當下啟動起來,如果沒意外,我們看 netstat 狀況會如下

[root@localhost /]# netstat -nap | grep php-fpm
unix  2      [ ACC ]     STREAM     LISTENING     355842   17207/php-fpm: mast  /var/run/php-fpm/php70-fpm-nginx.sock
unix  2      [ ACC ]     STREAM     LISTENING     425377   25419/php-fpm: mast  /opt/remi/php56/root/var/run/php-fpm/php56-fpm-nginx.sock
unix  3      [ ]         STREAM     CONNECTED     355840   17207/php-fpm: mast
unix  3      [ ]         STREAM     CONNECTED     355841   17207/php-fpm: mast
unix  3      [ ]         STREAM     CONNECTED     425375   25419/php-fpm: mast
unix  3      [ ]         STREAM     CONNECTED     425376   25419/php-fpm: mast

我們可以看見有兩個 Unix Sokcet 被建立了,這樣接下來輕鬆了。

Nginx 的設定

建立 php-fpm.conf 在 /etc/nginx/conf.d 之下,內容如下

upstream php-fpm-sock {
    server unix:/var/run/php-fpm/php70-fpm-nginx.sock;
}

upstream php56-fpm-sock {
    server unix:/opt/remi/php56/root/var/run/php-fpm/php56-fpm-nginx.sock;
}

現在我們定義了兩個 upstream ,因此在 Virtual Host 中使用就簡單了

如果有多個 VirtualHost 就可以分別使用上述的 upstream 來運行不同的版本,例如

# server 1
server {
    # .... 略 ....
    location ~ \.php$ {
        root           /srv/www/wordpress;
        fastcgi_pass php-fpm-sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

# server 2
server {
    # .... 略 ....
    location ~ \.php$ {
        root           /srv/www/wordpress;
        fastcgi_pass php56-fpm-sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

上述 VirtualHost 設定檔定義 server 1 及 server 2 ,分別跑兩個不同版本 php,其實差別就在於 fastcgi_pass 這個參數,分別指向不同的 upstream,如此就可以讓 nginx 支援不同版本 PHP 了。

後記

有朋友問,docker 好像也可以做到,沒錯,但是 docker 比較肥,而且效能差了一些,管理上也不見得好管,SCL 的方式就是把套件另外安裝到某個路徑而已,不算虛擬化所以不會影響效能,要升級或移除也可以用 yum or rpm 方式移除。

發佈留言