相較於比較現代的程式語言(如 Golang 或 Nodejs),PHP 的佈署是相對麻煩許多的--這主要是因為 PHP 的執行環境需要綁定一個網頁伺服器。
PHP 官方主要支援兩種佈署方式:
- Apache + PHP Module:較簡單,由 Apache 統一管理 PHP 的生命周期
- PHP-FPM:能夠搭配大部份支援 FastCGI 協定的 Web Server
註:在大部份應用情境下,Apache + PHP Module 會比 Apache + PHP-FPM 慢上一些,尤其是當 Apache + PHP-FPM 時可以啟用 Event MPM,相較於傳統的 prefork MPM 而言可以快上 50%
Laravel 應用程式的佈署
Laravel 是當前 PHP 社群中最熱門的框架,這得益於其設計模式的應用及社群間的活躍程度。
與大部份的 PHP 應用程式類似,Laravel 的佈署仍然受限於 PHP 的佈署模型。只 不過,為了實現某些進階功能(如 Cronjob 或 Queue),Laravel 的複雜度又更高了一些。
總結來說,一個 Laravel 應用程式的佈署需要以下三種功能:
- Web:提供傳統的 HTTP Request 與 Response 的服務
- Queue Worker:執行 Queue Job,用於處理耗時較高的任務或用於降低尖峰負載
- Cronjob Worker:執行 Cronjob,用於處理定時任務
Web 的佈署設計
Nginx
礙於篇幅緣故,這邊不詳細列出 Nginx 的 Config,只要保持幾個注意事項即可:
- Error Log 應該輸出到
/dev/stderr
;Access log 應該輸出到/dev/stdout
- FastCGI 應該用
{fpm_container_name}:9000
的型式表現,這是因為 Container Runtime 會自動分配 Domain Name 給容器
可以參閱 Laravel 官方的 Nginx 設定檔改寫
FROM nginx:alpine
WORKDIR /app
COPY . .
# COPY nginx.conf /etc/nginx/nginx.conf
# COPY www.conf /etc/nginx/conf.d/www.conf
CMD ["nginx", "-g", "daemon off;"]
- 可以利用 Multi-stage Build 的特性,先行編譯 Assets 資源,再 COPY 到 nginx image 之中
- 記得使用適當的 Nginx Config
PHP 與 PHP-FPM
FROM composer AS builder
WORKDIR /code
COPY . .
RUN composer install
FROM alpine:edge
ENV PHP_PACKAGES php81 php81-fpm \
php81-bcmath php81-ctype php81-dom php81-exif php81-fileinfo php81-gd php81-intl php81-mbstring php81-opcache \
php81-openssl php81-pcntl php81-pdo php81-pdo_sqlite php81-pdo_pgsql php81-posix \
php81-session php81-tokenizer php81-xml php81-xmlwriter \
php81-pecl-redis
ENV SOFTWARES postgresql
WORKDIR /app
RUN apk update && apk upgrade && \
apk add ${PHP_PACKAGES} ${SOFTWARES}
COPY /code .
CMD ["php-fpm81", "--allow-to-run-as-root", "-F"]
composer install
時,可以加入一些優化參數- 建議使用
alpine
作為 PHP-FPM 的 Base Image- 官方提供的
php:alpine-fpm
在安裝額外 extension 時會花費較多時間(因需要重新編譯),且以 pecl 安裝外部 extension 時偶爾會出現下載失敗導致 Image 建置失敗的例外狀況 - Alpine Linux 中可以利用 APK 安裝與更新各種擴充套件,惟要注意各版本對於軟體的支援程度不一
- Alpine 3.15 若要安裝 PHP 8.1 需要使用 testing repository
- 官方提供的
- 記得修改
php-fpm.conf
,將listen
改為0.0.0.0:9000
,這是為了讓 nginx 容器能夠存取 php-fpm 容器的必要設定- 務必注意:php-fpm 容器絕對不應該對外開放,應該只有 Nginx 容器能夠以 FastCGI 存取 php-fpm 容器
Queue, Schedule Worker
事實上 Queue Worker 與 Schedule Worker 的 Image 是相同的,只不過它使用的指令不同。
- Queue Worker:
php artisan queue:work
- Schedule Worker:
php artisan schedule:work
根據 Laravel 的官方文件,Schedule Worker 應該使用
php artisan schedule:run
啟動,然而這個指令是一次性的(配合 cron,每分鐘執行一次),此處為了配合 Docker Compose 沒有提供 Cronjob 的機制,改用php artisan schedule:work
的方式啟動常駐服務
事實上,可以直接把上一個階段構建的 PHP Image 直接拿來使用,只需要更換啟動指令即可。