--- GA: UA-101930725-2 tags: LaravelConf Taiwan 2018 --- 如何正確佈署 Laravel 專案 - LaravelConf Taiwan 2018 === **講者:紀冠宇 (芥龍) 希幔科技 / Backend Engineer** {%hackmd zKDIhFJzQ5GM23euKlgq2Q %} ## 開始之前 [向講者提問 sli.do #Z271](https://app.sli.do/Z271) [簡報](https://slides.com/chivincent/deploy-laravel-application-in-correct-way) ## 議程筆記 [Can Laravel be Hacked ?](https://medium.com/@Bohr/can-laravel-be-hacked-47ca5165d357) 因為一些部署錯誤的關係,導致一些敏感資訊被洩漏。 ## 從基礎環境開始 * web server * 持續維護 * HTTP/2 * SSL/TLS * FASTCGI * IPv6 IIS >需要大量的時間,才能處理好,不建議 liteSpeed web server >要$ > Apache HTTP Server >設定複雜,但是處理好也是很好。 OpenLiteSpeed Caddy > 預設有SSL > 據說 SSL 有雷 Nginx >輕量、設定簡單 >講者推薦 * php runtime * 版本>=7.1 * Extension * OpenSSL * PDO * Mbstring >處理多位元字元時會需要 >例如梵文、阿拉伯文中文之類。 * Tokenizer * XML * Ctype * JSON * laravel官方文件沒寫的事 * Extension * memcached * opcache > 將PHP預編譯為bytecode, > 避免重複編譯的問題。 * gd >開發時,如果要產生假圖, >底層使用gd lib * bcmath * pcntl * zip >composer會用到 * predis vs php-redis * php-redis 另外支援 PIPELINE 模式 * database * 官方聲明 * MySQL * Postgresql * SQLite * MS SQL * 理論上 * 有支援 PDO 的都能用 * 實際上 * 要注意 Database 特性 * in-memory 不支援 transaction * Queue - 任務佇列 * 務必建立failed_jobs * 務必注意 retry 及 sleep * 利用 supervisor/systemd 保證執行 * Queue的另一種思路 * php 不適合拿來做 Queue 的功能,可以思考是不是要用其他語言實現。 * PHP 是一個「快速啟動、快速銷毀」的語言,不適合常駐於記憶體中,在 Queue 實現上應考量其它可常駐記憶體的語言(如 Golang、Rust 甚至是 C/C++) * CronJob - 定時任務 * 盡量避免使用時區的功能 * 部份時區有夏令時間,可能造成 Cron Job 不執行或執行兩次 * 最好設定全域 Cache,以達成 onOneServer 功能 ### 部署注意事項 應用程式進入點設為 * laravel-app/public/index.php > public跟app同層吧? > 講者補充:這邊講的 app 是指 laravel root root對到public的原因 避免client存取無關檔案 * .env * .git/ * composer.json * node_modules/ * 統一應用程式進入點 只載入autoload.php一次 > 講者補充:index.php 位於 public/index.php 之下 ### 如何設定資料夾權限 * 與 nginx 的權限無關 * 需要讓 php-fpm 在加可寫權限 * 絕對不要把資料夾權限設為777 * 如果發現權限都 777 了,但仍然無法使用,八成是 SELinux 的問題 ## 在演講完之後 其實還有大概 2/3 的東西尚未講完,對於時間控制的部份相當抱歉。 以下的內容在此進行補充: ### 加速應用程式 * Composer 設定 * composer -o * 建立 ClassMap,避免每次都去存取 File System * 若沒有在 ClassMap 上的,才去 File System 嘗試尋找 * 這個特性在 PHP >= 5.6 上且有開啟 OPCache 時,成效不大 * composer -a * 不可與 --apcu-autoloader 共用 * 除了建立完整的 ClassMap,不到 File System 上嘗試存取 * 動態生成的 Class 會出錯 * Laravel 層設定 * config:cache * 建立 config 快取,避免多次存取 .env 及 local environment * 會讓 config/ 之外的 env() 函式永遠 return null; * route:cache * 對 Laravel 的路由進行序列化(serialize),並且編譯為單獨的 Symfony Routing Cache Class * 要注意 route:cache 不支援 closure 的路由方法 * view:cache * 將 blade 模板編譯為純 PHP 檔案,避免重複編譯 * 如果沒有 resources/view 資料夾,會報錯 ### 分散式架構下的 Laravel 佈署 * 拆分 Database:用 Laravel Connection Feature * 優點:原生支援 Laravel 各項特性 * 缺點:需要修改程式碼 * 拆分 Database:用 ProxySQL * 優點:方便以規則管理各式存取方式 * 缺點:不支援 Laravel 原生的 Prepared Statement 存取方式 > 小筆記:Prepared Statement 有兩種:TCP 層級的與 SQL 層級的 > 因為 Laravel 設定 Simulate Prepares 為 false,是 SQL 層級的 Prepared Statement 存取方式,ProxySQL 是不支援的 > > 註:ProxySQL 不支援的原因是效能問題以及可能會有非預期存取情況 > > 詳情可以參見:[PHP 騙你,PDO prepared 並沒有準備好](https://medium.com/wetprogrammer/php-%E9%A8%99%E4%BD%A0-pdo-prepare-%E4%B8%A6%E6%B2%92%E6%9C%89%E6%BA%96%E5%82%99%E5%A5%BD-600e15cd4cfe) * 拆分快取及其它服務 * 當「其它服務」不是嚴重依賴 PHP,可以考慮拆分出來。 * 快取分為「本地快取」及「全域快取」 * 應用情況視自己家的 DevOps 而定 * 拆分核心應用(依賴 PHP 的服務) * Cron Job 重複執行 * 只在一台 Server 執行 Cron Job * 如何保證高可用性? * 用 onOneServer 解決(記得設全域快取) * Queue Worker 資源閒置 * 無法正確取得 Clinet IP * 記得使用 Trusted Proxies Middleware * 邁向現代化 DevOps * 容器化的迷思 * PHP 天生不適合容器化? * FastCGI 與 Web Server 強烈綁定 * 檔案結構複雜,不利容器運作 > 根據業務需求及 DevOps 人力,可以考慮將 PHP-fpm 綁在 Web Server 中,這樣同生共死,服務較容易監控;也可以將 PHP-fpm 分出來,容易擴充(scaling) * 邁向現代化 DevOps * 在 MicroService 的時代,PHP 終將被淘汰? > 其實,換個角度來看,PHP-fpm 就是一個微服務,從這個角度切入的話,PHP 早就是 Microservice 的良好實踐。 * 走向現實:容器化 * Source Code 應該如何被使用? > 如果服務能夠忍受 container mount 造成的效能損耗,而且要求不重新建置 image,可以考慮 mount > 如果服務有完整的 CI/CD 流程,較建議用 copy 的方式發版