Back

Laravel 佈署指南

相較於比較現代的程式語言(如 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 設定檔改寫

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 --from=builder /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 直接拿來使用,只需要更換啟動指令即可。

PHP-FPM 的效能監測

對於一些比較現代的應用程式,通常都會整合 Prometheus 指標並且利用 Grafana 呈現清晰易懂的 Dashboard。

然而 PHP-FPM 是比較傳統的應用程式,儘管它有提供 status page 但卻沒有預設 Prometheus 指標,為此可以利用 hipages/php-fpm_exporter 將 PHP-FPM 內建的 status 轉化為 Prometheus 指標。

PHP-FPM 的設定

在 PHP-FPM 中,需要設定 pm.status_pathpm.status_listen(預設未開啟)

1
2
pm.status_path = /status
pm.status_listen = 0.0.0.0:9001

使用 php-fpm_exporter

在 Docker Compose 中,將 php-fpm_exporter 加入 services:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
services:

  nginx: ...
  php-fpm: ...

  php-fpm-exporter:
    image: 'hipages/php-fpm_exporter'
    ports:
      - "9253:9253"
    environment:
      - PHP_FPM_SCRAPE_URI=tcp://php-fpm:9001/status

最後,只要使用 Prometheus 到 localhost:9253 即可存取這些指標。

補充資訊

2021 年 5 月,Laravel 官方發佈名為 Laravel Octane 的套件,採用 SwooleRoadrunner 作為沒有 Web Server 的 PHP 佈署解決方案。

這些解決方案會從根本上改變 PHP Runtime 的特性,許多生態系內的既有工具(如 XDebug 或一些 Profiler)都需要修改後才能使用,儘管它們(宣稱)可以提供令人驚豔的效能,但需要權衡其開發成本是否足以支應這樣的效能改善。

Built with Hugo
Theme Stack designed by Jimmy