如何給openresty打patch
由於很多功能實現的限制,我們不得不修改openresty,但我們又不一定能持續維護一個 openresty 分支,所有有了patch 這一操作。
patch是怎麼補“漏洞”的?
patch 中文含義為補丁,給大家的感覺就像在原來的基礎上修復漏洞,就像小時候舊衣服上縫縫補補的那些痕跡
比如在window 系統更新等等地方,每一個patch都是在做類似補漏洞的事情(或者新增一些新功能之類)
系統包含的東西太多,有核心,有功能元件,一個功能可能是一個程式,也可能是一堆程式,所以比較複雜。
我們不如將範圍縮小到 openresty 這樣單獨具體的程式來舉例說明。
首先我們回憶一下 openresty 各種各樣的功能是怎麼組合起來的呢?
openresty基於 nginx, Nginx 具有高擴充套件特性,它從設計上完全就由多個不同功能、不同層次、不同型別且耦合度極低的模組構成,因此,當對某一個模組修復 Bug 或 進行升級的時候,可以專注於模組本身,無需在意其他。
模組示意
下圖展示了一次常規請求和響應的時序圖
所以第一種打補丁的方式: 替換掉模組程式
替換掉模組程式
我們針對不同的模組程式,可以做不同的事情,舉例如下:
1. 替換掉lua 程式碼
openresty 中lua為動態程式碼特性提供這個可能性
比如下圖我們可以改掉 log的程式碼
2. 替換掉so
大家都知道 openresty的很多 c 庫都是編譯成 so 檔案使用
so檔案是Linux下的程式函式庫,即編譯好的可以供其他程式使用的程式碼和資料
linux下何謂.so檔案:
- 用過windows的同學應該都知道 .dll檔案吧, 這二者有什麼共通之處呢,其實 .so檔案就跟.dll檔案差不多
- 一般來說.so檔案就是常說的動態連結庫, 都是C或C++編譯出來的。與Java比較就是:它通常是用的Class檔案(位元組碼)
- Linux下的.so檔案時不能直接執行的,一般來講,.so檔案稱為共享庫 比如在docker環境由於 lfs.so 有著 gcc版本要求(畢竟編譯它的版本不算太低,有些docker閹割了gcc,導致載入有問題),所以就可以替換為符合docker環境的版本
簡陋的patch方式有沒有什麼問題呢?
聰明的同學們肯定已經想到了上面說的方式太簡陋了,
面臨著以下幾個問題:
- nginx 內部的一些程式碼無法patch,畢竟不是所有c 都變成了 so
- 手動打的這些patch 很難管理, openresty 一直在更新,每個版本都手動一行行改太累了
patch 的管理方式
現在大家在需要改動程式碼做patch 一般都使用 git 來完成這個事情
接下來我給大家做個示例:
1. 修改程式碼,生成 patch檔案
修改程式碼就不用示例了吧
生成patch 檔案可以用git 命令
git diff f915e0dbe520938b7a84bd0e5c1cf12cf64c4186 97d1b704d0d86b5370d57604a9e2e3f86e4a33ec --no-prefix > enable_keepalive.patch
部分檔案結果
2. 應用 patch
在需要打補丁的目錄下執行命令
patch -p0 --verbose < "enable_keepalive.patch"
程式碼檔案就會被改變
一般這些patch 我們都會編寫指令碼做管理,
完整的一個例子你們可以參見 https://github.com/fs7744/nature/tree/main/openresty_patch