Arm64架構下靜態編譯Nginx

DrunkCat90發表於2021-12-27

這段時間,我一直忙於將 Rainbond 原始碼構建模組移植到 Arm64/aarch64 架構中。這一原始碼構建模組可以將指定程式碼倉庫中包含的原始碼,拉取構建成為容器映象,在各種容器平臺中執行。目前支援的原始碼型別包括:Java(Maven、Gradle、jar、war)、Nodejs(前端Vue、後端專案)、Golang、Python、PHP、.NetCore、靜態Html。

Rainbond原始碼構建簡介

Rainbond 原始碼構建模組由 builderrunner 兩個子模組組成。

builder 負責將原始碼進行編譯,並打包成為 Heroku 風格的 slug.tgz 包。slug.tgz 包中會包含編譯完成的產物(比如jar包、二進位制等),以及編譯產物執行所需要的基礎環境(比如 jdk、tomcat、nginx、apache)。

runner 負責提供 slug.tgz 包執行的基礎環境。這是一個通用的基礎環境,不必再區分語言,無論何種語言生成的 slug.tgz 包都適用。

為何要編譯Nginx

Nginx 是靜態Html 、 Nodejs前端專案執行所使用的預設 Web-Server。builder 會在這兩種語言編譯完成後,前往 Rainbond 專用的雲端物件儲存中拉取 Nginx 安裝包。這種預編譯的安裝包,Nginx 官方只會提供 x86_64 版本。

在原始碼構建模組移植到 Arm64/aarch64 架構的過程中,我不可避免的要自己重新編譯 Arm 架構可用的 Nginx 預編譯安裝包。

為何要進行靜態編譯

最開始,我是希望走一些捷徑,Nginx 的核心是要有一個可執行二進位制檔案,那麼我是否可以從別處得到這種可執行檔案。

Nginx 官方雖不提供我直接需要的 Arm64 預編譯安裝包,但是卻為各大作業系統發行版提供 Arm64 環境下的安裝源。對於 builder 所使用的 Ubuntu:14.04 作業系統而言,可以通過 apt install nginx 的方式安裝。然後我就可以得到我想要的可執行檔案了。但是下面兩個問題的出現,阻斷了這條思路。

  • Ubuntu:14.04 源提供的 Nginx 版本過低。
  • 使用更高版本的 Ubuntu:18.04 安裝的 Nginx 版本可以滿足我的要求,但是提取到的可執行檔案在 Ubuntu:14.04 無法執行,缺少必要的庫檔案。

此時我意識到,由源安裝而來的 Nginx 是動態編譯版本,apt 等包管理工具會自動處理所需的依賴,然而我並不想要一點點嘗試我所缺少的庫都由哪些包安裝,這很耗神。

我希望這個可執行檔案可以像 golang 語言編譯出的二進位制檔案一樣,將所有需要的庫都編譯到二進位制中去,從而免除對作業系統的要求。理論上,這種方式得到的二進位制在執行效率上也會更高。

簡單的查詢後,我瞭解到,我所需要的,是進行靜態編譯。

準備工作

閱讀 Nginx 官方提供的 原始碼編譯文件 瞭解到,我至少需要以下依賴需要處理:

  • PCRE(Perl Compatible Regular Expressions):基於 Perl 的正規表示式函式庫,Nginx 的 Core 、Rewrite 模組需要它。pcre-8.44.tar.gz

  • zlib:小而美的壓縮庫,Nginx 的 Gzip 模組需要它。zlib-1.2.11.tar.gz

  • OpenSSL:用於安全通訊的工具包,非常著名,Nginx 所有和安全通訊相關的模組都需要它,比如Https。openssl-1.1.1l.tar.gz

我已經把它們的安裝包上傳到 Rainbond 官方物件儲存上,讀者若有需求,可以點選下載。

進行編譯的硬體環境,是位於擁有 M1 晶片的 MacBookPro 筆記本 ,利用 Docker Desktop 啟動的 ubuntu:1404 容器。容器中預裝了 gccmake 軟體包。

編譯過程

解壓所有的依賴軟體包,以及 Nginx 的原始碼包,所有原始碼包都位於同級目錄下:

# 解壓已經下載好的依賴軟體包
$ tar xzf pcre-8.44.tar.gz
$ tar xzf zlib-1.2.11.tar.gz
$ tar xzf openssl-1.1.1l.tar.gz
# 下載並解壓 nginx stable 原始碼包
$ wget https://nginx.org/download/nginx-1.18.0.tar.gz
$ tar zxf nginx-1.18.0.tar.gz
$ cd nginx-1.18.0

執行 configure ,並指定靜態編譯引數:

$ ./configure \
--with-cc-opt='-static -static-libgcc' \
--with-ld-opt=-static \
--prefix=/app/nginx \
--with-http_ssl_module \
--with-openssl=../openssl-1.1.1l \
--with-pcre=../pcre-8.44 \
--with-zlib=../zlib-1.2.11

開始執行編譯:

$ make && make install

打包編譯出來的 Nginx 目錄即可:

$ tar czf nginx-1.18.0-arm64.tar.gz /app/nginx

驗證

檢視編譯後產生的可執行檔案,會發現該二進位制檔案的編譯型別為靜態型別,這樣的檔案,可以在 arm64 架構下的任意 Linux 環境下執行。

$ file /usr/local/nginx/sbin/nginx
/usr/local/nginx/sbin/nginx: ELF 64-bit LSB  executable, ARM aarch64, version 1 (SYSV), statically linked, for GNU/Linux 3.7.0, BuildID[sha1]=66e5740a16bdfe6bc2f04c5371fd706ae7ca5395, not stripped

相關文章