使用 Docker 打造多版本 PHP 開發環境
過去在這幾年間 PHP
終於從 5.x
升版到了 7.x
,所以公司內的新專案也因應改版也順勢使用新版本,那原本的專案就保持舊版本或是之後有計畫升級新版本。
但這樣就會造成環境混雜的問題,所以同時可能會有 5.4
、5.6
或是 7.0
的專案需要開發。
而在一般的開發環境之下,每台電腦就只能安裝單一版本的 PHP
,就算有機會安裝多個環境也有機會造成環境污染,以及無法快速切換版本。
所以利用 Container
的方式將不同的環境打包到個別的 Image
獨立運作,再利用 PHP-FPM
可以聆聽 socket
或是 port
的特性,以及 Nginx
的 Proxy
將請求送到不同的環境去執行。
撰寫 Dockerfile
這邊我們使用 Alpine Linux
作為 Image
的基底,再安裝上我們所需要的套件,下面就使用 Nginx
及 PHP
為範例,不同的 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
在這裡我們需要修改 Nginx
的 FactCGI
傳遞的方式,以及 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_links
及 depends_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
下面是範例專案,至於要怎樣投入到生產環境那就要看個人的調校了。