ScarShow

< IS >

使用 Docker 打造多版本 PHP 開發環境

2018-08-19  /  IT  /  Docker Nginx PHP

過去在這幾年間 PHP 終於從 5.x 升版到了 7.x,所以公司內的新專案也因應改版也順勢使用新版本,那原本的專案就保持舊版本或是之後有計畫升級新版本。

但這樣就會造成環境混雜的問題,所以同時可能會有 5.45.6 或是 7.0 的專案需要開發。

而在一般的開發環境之下,每台電腦就只能安裝單一版本的 PHP,就算有機會安裝多個環境也有機會造成環境污染,以及無法快速切換版本。

所以利用 Container 的方式將不同的環境打包到個別的 Image 獨立運作,再利用 PHP-FPM 可以聆聽 socket 或是 port 的特性,以及 NginxProxy 將請求送到不同的環境去執行。

撰寫 Dockerfile

這邊我們使用 Alpine Linux 作為 Image 的基底,再安裝上我們所需要的套件,下面就使用 NginxPHP 為範例,不同的 PHP 版本只需要透過修改 Alpine Linux 的版本來調整。

Nginx 1.14

FROM alpine:3.8
MAINTAINER Scar Wu <xneriscool@gmail.com>
WORKDIR /build

RUN VERSION="1.14" \
    && NEED_APK="nginx>$VERSION" \
    && apk --update add $NEED_APK

RUN mkdir /volume \
    && mkdir /volume/log \
    && mkdir /volume/data \
    && mkdir /volume/config \

    && mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak \
    && ln -s /volume/config/nginx.conf /etc/nginx/nginx.conf

VOLUME ["/volume/config", "/volume/data", "/volume/log"]

COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

EXPOSE 80/tcp
EXPOSE 443/tcp

CMD /usr/sbin/nginx -g "daemon off;"

PHP 5.6

FROM alpine:3.8
MAINTAINER Scar Wu <xneriscool@gmail.com>
WORKDIR /build

RUN VERSION="5.6" \
    && NEED_APK="php5>$VERSION php5-fpm>$VERSION" \
    && apk --update add $NEED_APK

ENV PHP_DIR /etc/php5

RUN mkdir /volume \
    && mkdir /volume/log \
    && mkdir /volume/data \
    && mkdir /volume/config \

    && mv $PHP_DIR/php.ini $PHP_DIR/php.ini.bak \
    && ln -s /volume/config/php.ini $PHP_DIR/php.ini \

    && mv $PHP_DIR/php-fpm.conf $PHP_DIR/php-fpm.conf.bak \
    && ln -s /volume/config/php-fpm.conf $PHP_DIR/php-fpm.conf

VOLUME ["/volume/config", "/volume/data", "/volume/log"]

COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

RUN addgroup nginx \
    && adduser -D nginx -G nginx

EXPOSE 9000/tcp

CMD /usr/bin/php-fpm5 --nodaemonize

PHP 7.2

FROM alpine:3.8
MAINTAINER Scar Wu <xneriscool@gmail.com>
WORKDIR /build

RUN VERSION="7.2" \
    && NEED_APK="php7>$VERSION php7-fpm>$VERSION" \
    && apk --update add $NEED_APK

ENV PHP_DIR /etc/php7

RUN mkdir /volume \
    && mkdir /volume/log \
    && mkdir /volume/data \
    && mkdir /volume/config \

    && mv $PHP_DIR/php.ini $PHP_DIR/php.ini.bak \
    && ln -s /volume/config/php.ini $PHP_DIR/php.ini \

    && mv $PHP_DIR/php-fpm.conf $PHP_DIR/php-fpm.conf.bak \
    && ln -s /volume/config/php-fpm.conf $PHP_DIR/php-fpm.conf

VOLUME ["/volume/config", "/volume/data", "/volume/log"]

COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

RUN addgroup nginx \
    && adduser -D nginx -G nginx

EXPOSE 9000/tcp

CMD /usr/sbin/php-fpm7 --nodaemonize

調整 Server Config

在這裡我們需要修改 NginxFactCGI 傳遞的方式,以及 PHP-FPM 的聆聽模式,Nginx 可以透過判斷 request_uri 的方式指定將不同的請求送到不同的 PHP 的版本。

在這邊的設定檔案不是完整檔,只是表名設定的重點,完整的設定在我的 Github 上有,見下方連結。

Nginx: www.conf

server {
    listen 80;

    root /volume/data;
    index index.html index.htm index.php;

    charset utf-8;
    autoindex off;

    error_page 403 = 404;
    error_page 404 /404.html;

    location ~ /\.ht {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~ \.php$ {
        fastcgi_pass PHP-7.2:9000;
        fastcgi_index index.php;
        fastcgi_split_path_info ^(.+\.php)(.*)$;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        if ($request_uri = "/php56") {
            fastcgi_pass PHP-5.6:9000;
        }

        if ($request_uri = "/php72") {
            fastcgi_pass PHP-7.2:9000;
        }
    }
}

PHP-FPM: pools/main.conf

[main]
listen = 0.0.0.0:9000

撰寫 Docker Compose File

利用 Docker Compose 將環境設定起來,這邊要注意的是將相對應資料夾掛到 Container 中,再來是 external_linksdepends_on 的關聯設定。

version: '3'
services:

    nginx:
        image: scarwu/demo-nginx:1.14
        volumes:
            - ./config/Nginx:/volume/config
            - ./data:/volume/data
            - ./log/nginx:/volume/log
        ports:
            - "80:80"
        external_links:
            - "php56:PHP-5.6"
            - "php72:PHP-7.2"
        depends_on:
            - "php56"
            - "php72"
        restart: always

    php56:
        image: scarwu/demo-php:5.6
        volumes:
            - ./config/PHP-5.6:/volume/config
            - ./data:/volume/data
            - ./log/php56:/volume/log
        restart: always

    php72:
        image: scarwu/demo-php:7.2
        volumes:
            - ./config/PHP-7.2:/volume/config
            - ./data:/volume/data
            - ./log/php72:/volume/log
        restart: always

Source Code

下面是範例專案,至於要怎樣投入到生產環境那就要看個人的調校了。

MultiPHPEnvWithDocker