構建api gateway之 如何給openresty打patch

victor.x.qu發表於2023-02-11

如何給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檔案:

  1. 用過windows的同學應該都知道 .dll檔案吧, 這二者有什麼共通之處呢,其實 .so檔案就跟.dll檔案差不多
  2. 一般來說.so檔案就是常說的動態連結庫, 都是C或C++編譯出來的。與Java比較就是:它通常是用的Class檔案(位元組碼)
  3. Linux下的.so檔案時不能直接執行的,一般來講,.so檔案稱為共享庫 比如在docker環境由於 lfs.so 有著 gcc版本要求(畢竟編譯它的版本不算太低,有些docker閹割了gcc,導致載入有問題),所以就可以替換為符合docker環境的版本

簡陋的patch方式有沒有什麼問題呢?

聰明的同學們肯定已經想到了上面說的方式太簡陋了,

面臨著以下幾個問題:

  1. nginx 內部的一些程式碼無法patch,畢竟不是所有c 都變成了 so
  2. 手動打的這些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

目錄

相關文章