Linux Study Lab !

当前位置:   网站首页 >> Linux 应用实践

在一台物理机上安装两个版本相同的PHP

有时候因为特殊情况(嗯,比如某些公司开发出来的不可理喻的应用程序)需要在一台物理机上安装两个版本相同(或不同)的运行环境,并且因为一些其他限制,还不能在docker里分开跑,于是就有了本文。

通常我们的做法是yum安装php,但为了达成本文的目标,我们需要编译安装。本文范例使用的php版本是5.3.29,我和你一样,非常不理解为什么要选用这个高不成低不就的版本。本范例的单一目标是在一台物理服务器上安装两个版本相同的php,你一定觉得我们脑袋秀逗了,但是这里有一个应用偏偏要这个版本,而且还要同时运行zts和nts的环境。很好,我想你已经明白软件开发商是有多么的愚蠢了。

首先编译一个ZTS版本的php,在编译前请将所需的各种依赖和环境先安装以及编译好,不知道需要哪些的话请在博客内搜索之前关于编译php的文章。

./configure --prefix=/usr/local/php53zts --with-config-file-path=/etc/php53zts --with-config-file-scan-dir=/etc/php.d --enable-mbstring  --with-mcrypt --with-curl --with-gettext --with-bz2 --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --enable-shmop --enable-calendar --enable-ftp --with-openssl --with-zlib --enable-exif --with-gmp --enable-sysvmsg --enable-sockets --enable-wddx --libdir=/usr/lib --with-libdir=lib --with-gd --with-jpeg-dir=/usr/lib --with-png-dir=/usr/lib --with-freetype-dir=/usr/lib --enable-zip --enable-sockets --enable-ftp --without-pear --enable-fpm --enable-maintainer-zts

特别要注意的是--prefix=、--with-config-file-path=这两条定义,这里将要定义该php安装到哪个目录,如果不定义就是默认的路径,然而我们需要安装两个php,所以一定要定义。编译完成并make install后,程序会汇报它的路径,本范例中,ZTS版本的路径为

Installing PHP SAPI module:       fpm
Installing PHP CLI binary:        /usr/local/php53zts/bin/
Installing PHP CLI man page:      /usr/local/php53zts/man/man1/
Installing PHP FPM binary:        /usr/local/php53zts/sbin/
Installing PHP FPM config:        /usr/local/php53zts/etc/
Installing PHP FPM man page:      /usr/local/php53zts/man/man8/
Installing PHP FPM status page:      /usr/local/php53zts/share/php/fpm/
Installing build environment:     /usr/lib/build/
Installing header files:          /usr/local/php53zts/include/php/
Installing helper programs:       /usr/local/php53zts/bin/
  program: phpize
  program: php-config
Installing man pages:             /usr/local/php53zts/man/man1/
  page: phpize.1
  page: php-config.1
/tmp/php-5.3.29/build/shtool install -c ext/phar/phar.phar /usr/local/php53zts/bin
ln -s -f /usr/local/php53zts/bin/phar.phar /usr/local/php53zts/bin/phar
Installing PDO headers:          /usr/local/php53zts/include/php/ext/pdo/

接下来需要编译一个NTS版本的环境,不过我在编译中遇到了一个奇特的错误,提示缺少了某个库,但ZTS编译时并未提示,为防万一,我又重新编译了缺少的库libmcrypt

cd /tmp
wget http://sourceforge.net/projects/mcrypt/files/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.gz/download
tar zxvf libmcrypt-2.5.8.tar.gz
cd libmcrypt-2.5.8/
./configure
make && make install
/sbin/ldconfig
cd libltdl/
./configure --enable-ltdl-install
make && make install

按序执行上述命令后,再次开始编译NTS的PHP

./configure --prefix=/usr/local/php53 --with-config-file-path=/etc/php53 --with-config-file-scan-dir=/etc/php.d --enable-mbstring  --with-mcrypt --with-curl --with-gettext --with-bz2 --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --enable-shmop --enable-calendar --enable-ftp --with-openssl --with-zlib --enable-exif --with-gmp --enable-sysvmsg --enable-sockets --enable-wddx --libdir=/usr/lib --with-libdir=lib --with-gd --with-jpeg-dir=/usr/lib --with-png-dir=/usr/lib --with-freetype-dir=/usr/lib --enable-zip --enable-sockets --enable-ftp --without-pear --enable-fpm

除了--prefix=、--with-config-file-path=这两条定义外,相信你已经看出来NTS和ZTS版本在编译时的区别,对,就取决于一条编译参数--enable-maintainer-zts。编译后NTS版本的路径为

Installing PHP SAPI module:       fpm
Installing PHP CLI binary:        /usr/local/php53/bin/
Installing PHP CLI man page:      /usr/local/php53/man/man1/
Installing PHP FPM binary:        /usr/local/php53/sbin/
Installing PHP FPM config:        /usr/local/php53/etc/
Installing PHP FPM man page:      /usr/local/php53/man/man8/
Installing PHP FPM status page:      /usr/local/php53/share/php/fpm/
Installing build environment:     /usr/lib/build/
Installing header files:          /usr/local/php53/include/php/
Installing helper programs:       /usr/local/php53/bin/
  program: phpize
  program: php-config
Installing man pages:             /usr/local/php53/man/man1/
  page: phpize.1
  page: php-config.1
/tmp/php-5.3.29/build/shtool install -c ext/phar/phar.phar /usr/local/php53/bin
ln -s -f /usr/local/php53/bin/phar.phar /usr/local/php53/bin/phar
Installing PDO headers:          /usr/local/php53/include/php/ext/pdo/

接下来很重要的一步是为这两个版本相同但是运行模式不同的php环境各自配置相关的服务启动脚本

ZTS版本的服务启动脚本:

cd /etc/init.d
vi zts-php-fpm
复制黏贴下面的代码
#! /bin/sh

### BEGIN INIT INFO
# Provides:          php-fpm
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts php-fpm
# Description:       starts the PHP FastCGI Process Manager daemon
### END INIT INFO

prefix=/usr/local/php53zts
exec_prefix=${prefix}

php_fpm_BIN=/usr/local/php53zts/sbin/php-fpm
php_fpm_CONF=/etc/zts-php-fpm.conf
php_fpm_PID=/var/run/zts-php-fpm.pid


php_opts="--fpm-config $php_fpm_CONF --pid $php_fpm_PID"


wait_for_pid () {
        try=0

        while test $try -lt 35 ; do

                case "$1" in
                        'created')
                        if [ -f "$2" ] ; then
                                try=''
                                break
                        fi
                        ;;

                        'removed')
                        if [ ! -f "$2" ] ; then
                                try=''
                                break
                        fi
                        ;;
                esac

                echo -n .
                try=`expr $try + 1`
                sleep 1

        done

}

case "$1" in
        start)
                echo -n "Starting php-fpm "

                $php_fpm_BIN --daemonize $php_opts

                if [ "$?" != 0 ] ; then
                        echo " failed"
                        exit 1
                fi

                wait_for_pid created $php_fpm_PID

                if [ -n "$try" ] ; then
                        echo " failed"
                        exit 1
                else
                        echo " done"
                fi
        ;;

        stop)
                echo -n "Gracefully shutting down php-fpm "

                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi

                kill -QUIT `cat $php_fpm_PID`

                wait_for_pid removed $php_fpm_PID

                if [ -n "$try" ] ; then
                        echo " failed. Use force-quit"
                        exit 1
                else
                        echo " done"
                fi
        ;;

        force-quit)
                echo -n "Terminating php-fpm "

                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi

                kill -TERM `cat $php_fpm_PID`

                wait_for_pid removed $php_fpm_PID

                if [ -n "$try" ] ; then
                        echo " failed"
                        exit 1
                else
                        echo " done"
                fi
        ;;

        restart)
                $0 stop
                $0 start
        ;;

        reload)

                echo -n "Reload service php-fpm "

                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi

                kill -USR2 `cat $php_fpm_PID`

                echo " done"
        ;;

        *)
                echo "Usage: $0 {start|stop|force-quit|restart|reload}"
                exit 1
        ;;

esac

NTS版本的服务启动脚本:

#! /bin/sh

### BEGIN INIT INFO
# Provides:          php-fpm
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts php-fpm
# Description:       starts the PHP FastCGI Process Manager daemon
### END INIT INFO

prefix=/usr/local/php53
exec_prefix=${prefix}

php_fpm_BIN=/usr/local/php53/sbin/php-fpm
php_fpm_CONF=/etc/nts-php-fpm.conf
php_fpm_PID=/var/run/nts-php-fpm.pid


php_opts="--fpm-config $php_fpm_CONF --pid $php_fpm_PID"


wait_for_pid () {
        try=0

        while test $try -lt 35 ; do

                case "$1" in
                        'created')
                        if [ -f "$2" ] ; then
                                try=''
                                break
                        fi
                        ;;

                        'removed')
                        if [ ! -f "$2" ] ; then
                                try=''
                                break
                        fi
                        ;;
                esac

                echo -n .
                try=`expr $try + 1`
                sleep 1

        done

}

case "$1" in
        start)
                echo -n "Starting php-fpm "

                $php_fpm_BIN --daemonize $php_opts

                if [ "$?" != 0 ] ; then
                        echo " failed"
                        exit 1
                fi

                wait_for_pid created $php_fpm_PID

                if [ -n "$try" ] ; then
                        echo " failed"
                        exit 1
                else
                        echo " done"
                fi
        ;;

        stop)
                echo -n "Gracefully shutting down php-fpm "

                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi

                kill -QUIT `cat $php_fpm_PID`

                wait_for_pid removed $php_fpm_PID

                if [ -n "$try" ] ; then
                        echo " failed. Use force-quit"
                        exit 1
                else
                        echo " done"
                fi
        ;;

        force-quit)
                echo -n "Terminating php-fpm "

                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi

                kill -TERM `cat $php_fpm_PID`

                wait_for_pid removed $php_fpm_PID

                if [ -n "$try" ] ; then
                        echo " failed"
                        exit 1
                else
                        echo " done"
                fi
        ;;

        restart)
                $0 stop
                $0 start
        ;;

        reload)

                echo -n "Reload service php-fpm "

                if [ ! -r $php_fpm_PID ] ; then
                        echo "warning, no pid file found - php-fpm is not running ?"
                        exit 1
                fi

                kill -USR2 `cat $php_fpm_PID`

                echo " done"
        ;;

        *)
                echo "Usage: $0 {start|stop|force-quit|restart|reload}"
                exit 1
        ;;

esac

然后给两个服务脚本赋予执行权限,并加入系统服务中

chmod +x /etc/init.d/zts-php-fpm
chmod +x /etc/init.d/nts-php-fpm
chkconfig --add zts-php-fpm
chkconfig --add nts-php-fpm
chkconfig zts-php-fpm off
chkconfig nts-php-fpm off
chkconfig zts-php-fpm --level 3 on
chkconfig nts-php-fpm --level 3 on

接下来需要更改两个版本的php-fpm的配置文件,使服务监听不同的端口。在本范例中,我们让ZTS版本的php监听9001端口,而NTS版本的php监听9002端口。这部分比较简单,将php-fpm.conf文件复制两份,一份命名zts-php-fpm.conf一份命名nts-php-fpm.conf,然后修改其中的监听端口即可,默认端口是9000.修改后,使用命令分别运行两个php-fpm

service zts-php-fpm start
service nts-php-fpm start

通过查看netstat -lptn可以看到有两个fpm进程监听不同的端口,此时只要上级请求转发服务如nginx,转发php请求到相应的端口就可以区分哪些去ZTS版本解析,哪些去NTS版本解析。

最后,需要特别注意的是,在本例中编译时对mysql库文件的引入已经不再使用

--with-mysql=/usr/local/mysql 
--with-mysqli=/usr/local/mysql 
--with-pdo-mysql=/usr/local/mysql

而是使用php官方建议的内置数据驱动

--with-mysql=mysqlnd
--with-mysqli=mysqlnd
--with-pdo-mysql=mysqlnd

建议编译php5.3版本及以上时使用该编译参数替代。


发表我的评论

Hi,您需要填写昵称和邮箱!

  • 必填项