Arm64架构下静态编译Nginx
这段时间,我一直忙于将 [Rainbond](https://www.rainbond.com/?channel=guox) 源码构建模块移植到 Arm64/aarch64 架构中。这一源码构建模块可以将指定代码仓库中包含的源码,拉取构建成为容器镜像,在各种容器平台中运行。目前支持的源码类型包括:Java(Maven、Gradle、jar、war)、Nodejs(前端Vue、后端项目)、Golan
这段时间,我一直忙于将 Rainbond 源码构建模块移植到 Arm64/aarch64 架构中。这一源码构建模块可以将指定代码仓库中包含的源码,拉取构建成为容器镜像,在各种容器平台中运行。目前支持的源码类型包括:Java(Maven、Gradle、jar、war)、Nodejs(前端Vue、后端项目)、Golang、Python、PHP、.NetCore、静态Html。
Rainbond源码构建简介
Rainbond 源码构建模块由 builder 和 runner 两个子模块组成。
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 模块需要它。
-
zlib:小而美的压缩库,Nginx 的 Gzip 模块需要它。
-
OpenSSL:用于安全通信的工具包,非常著名,Nginx 所有和安全通信相关的模块都需要它,比如Https。
我已经把它们的安装包上传到 Rainbond 官方对象存储上,下载速度会快很多。
进行编译的硬件环境,是位于拥有 M1 芯片的 MacBookPro 笔记本 ,利用 Docker Desktop 启动的 ubuntu:1404 容器。容器中预装了 gcc
、 make
、g++
软件包。
编译过程
解压所有的依赖软件包,以及 Nginx 的源码包,所有源码包都位于同级目录下:
# 下载并解压依赖软件包
$ wget https://buildpack.oss-cn-shanghai.aliyuncs.com/static/r6d/nginx/nginx-compile-lib/pcre-8.44.tar.gz
$ tar xzf pcre-8.44.tar.gz
$ wget https://buildpack.oss-cn-shanghai.aliyuncs.com/static/r6d/nginx/nginx-compile-lib/zlib-1.2.11.tar.gz
$ tar xzf zlib-1.2.11.tar.gz
$ wget https://buildpack.oss-cn-shanghai.aliyuncs.com/static/r6d/nginx/nginx-compile-lib/openssl-1.1.1l.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 /app/nginx/sbin/nginx
/app/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
若干问题
CentOS 编译环境的问题
很久之后,我又有一次机会重新静态编译 Nginx,这次的不同之处在于我的构建环境是 CentOS 7 操作系统。执行 ./configure
命令时,遇到了一个问题:
./configure: error: the invalid value in --with-ld-opt="-static"
竟然不识别负责连接的构建参数 --with-ld-opt="-static"
,经过一番搜索,原来在 CentOS 环境中,需要安装以下这个包,来解决这个问题:
yum install glibc-static -y
看到包名就释然了,这个包的功能必然围绕着静态编译 C 语言库。重新执行 ./configure
,问题得以解决。
又是丧气满满的一天。
Pcre 编译问题
承接上个问题,在执行 make && make install
命令的时候,又报了一个和 pcre 相关的问题:
configure: error: Invalid C++ compiler or C++ compiler flags
make[1]: *** [../pcre-8.44/Makefile] Error 1
看起来, pcre 去寻找 C++ 编译器了,然而 CentOS 7 操作系统中并没有预装,那么解决之道应该是执行以下命令:
yum install -y gcc-c++
重新执行 make && make install
,编译过程又欢快的跑动了起来。
由此看来,作为编译环境而言,CentOS 7 相比 Ubuntu 14.04 少了很多必要工具,需要用到时自行安装,累了一点,确更明白了一点。
更多推荐
所有评论(0)