跳到主要内容

Nginx 支持 Lua:使用动态模块集成 LuaJIT 完整实践

· 阅读需 18 分钟
Apache王也道长
软件开发者与技术作者

本文记录一种在现有生产 Nginx 基础上增加 Lua 能力的实现方案。

核心思路:不重新编译、不替换生产环境的 Nginx,只编译 ngx_http_lua_module.so 动态模块,并配套部署 LuaJIT 及 Lua 依赖库。


一、为什么需要让 Nginx 支持 Lua?

Nginx 本身非常擅长处理网络请求,例如:

  • HTTP 反向代理
  • HTTPS
  • 负载均衡
  • WebSocket
  • URL Rewrite
  • Header 操作
  • 静态资源
  • Stream/TCP 代理

但是,当网关逻辑逐渐复杂之后,仅仅依靠 Nginx 原生配置会比较困难。

例如下面这样的需求:

客户端


Nginx

├── Token 校验
├── 动态路由
├── Header 处理
├── 调用 HTTP API
├── JSON 处理
└── 缓存


后端服务

这类逻辑如果全部交给后端实现,可能需要增加大量接口调用。

而通过 Lua,可以直接在 Nginx 请求处理阶段执行代码。

例如:

location /api/ {

access_by_lua_block {
ngx.log(ngx.INFO, "Lua is running")
}

proxy_pass http://backend;
}

于是 Nginx 就从一个单纯的:

Web Server / Reverse Proxy

变成:

可编程的 API Gateway

二、Nginx + Lua 到底由哪些部分组成?

完整的 Nginx Lua 环境并不是只有一个组件。

整体结构如下:

Nginx


ngx_http_lua_module.so


LuaJIT

┌───────────┼───────────┐
▼ ▼ ▼
lua-resty-core resty-http cjson
│ │ │
└───────────┼───────────┘

Lua Script

主要组件包括:

组件作用
NginxWeb Server / Reverse Proxy
lua-nginx-module将 Lua 集成到 Nginx
LuaJITLua 运行时
lua-resty-coreOpenResty Lua 核心库
lua-resty-httpLua HTTP Client
lua-resty-string字符串及相关工具
lua-resty-lrucacheLRU 缓存
lua-cjsonJSON 编解码

其中最核心的是:

Nginx
+
ngx_http_lua_module.so
+
LuaJIT

三、安装 LuaJIT 并不等于 Nginx 支持 Lua

这是很多人在第一次接触 Nginx Lua 时容易产生的误解。

例如:

luajit test.lua

能够运行,只能说明:

系统已经安装 LuaJIT

但是 Nginx 并不能因此执行:

location /test {

content_by_lua_block {
ngx.say("Hello Lua")
}

}

因为 Nginx 还需要:

ngx_http_lua_module

因此:

LuaJIT

负责执行 Lua

lua-nginx-module

负责把 Lua 接入 Nginx

两者缺一不可。


四、为什么采用动态模块?

如果生产服务器已经部署了一个稳定运行的 Nginx,那么我们通常不希望为了增加 Lua 功能而重新替换整个 Nginx。

传统静态编译方式:

Nginx Source


加入 Lua Module


重新编译 Nginx


新的 Nginx

这样意味着生产环境需要替换:

nginx

而本文采用的是动态模块方案:

生产 Nginx

│ load_module

ngx_http_lua_module.so


LuaJIT


Lua Runtime

生产环境原来的:

nginx

保持不变。

只增加:

ngx_http_lua_module.so

以及 LuaJIT Runtime。


五、为什么 Dockerfile 还要下载 Nginx 源码?

这里是整个方案最容易让人产生疑问的地方。

既然生产环境已经存在 Nginx:

nginx/1.26.3

为什么 Dockerfile 还要下载:

nginx-1.26.3.tar.gz

原因是:

我们不是使用源码重新安装生产 Nginx,而是利用对应版本的 Nginx 源码编译动态模块。

整个过程:

Nginx 1.26.3 Source


lua-nginx-module


./configure


make modules


ngx_http_lua_module.so

最后真正需要部署到生产服务器的是:

ngx_http_lua_module.so

而不是重新生成一个 Nginx。


六、为什么 Nginx 版本必须保持一致?

假设生产服务器:

nginx -V

得到:

nginx/1.26.3

那么构建 Lua 动态模块时也使用:

nginx-1.26.3

而不是:

nginx-1.24.x

或者:

nginx-1.27.x

因为动态模块与 Nginx 的构建环境、模块 ABI 等存在关联。

因此本文:

ARG NGINX_VERSION=1.26.3

就是为了明确指定:

生产 Nginx = 1.26.3
构建模块 = 1.26.3

七、为什么 configure 参数也需要尽量一致?

除了版本之外,还应该关注生产环境的:

nginx -V

例如生产环境:

nginx/1.26.3

configure arguments:

--prefix=/home/opt/local/nginx
--with-http_stub_status_module
--with-http_ssl_module
--with-stream
--with-http_v2_module

那么编译动态模块时也使用:

./configure \
--prefix=/home/opt/local/nginx \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream \
--with-http_v2_module \
--add-dynamic-module=/build/lua-nginx-module

核心原则就是:

生产 Nginx

模块构建环境

越接近,动态模块加载时出现兼容性问题的概率越低。


八、--add-dynamic-module 到底是什么意思?

Dockerfile 中最重要的参数之一:

--add-dynamic-module=/build/lua-nginx-module

它的意思是:

将指定目录中的第三方 Nginx 模块作为动态模块进行编译。

这里:

/build/lua-nginx-module

就是 Lua Nginx Module 的源码。

执行:

make modules

之后,会生成:

objs/ngx_http_lua_module.so

然后:

RUN cp \
/build/nginx-${NGINX_VERSION}/objs/ngx_http_lua_module.so \
/output/nginx/modules/ngx_http_lua_module.so

最终得到:

/output/nginx/modules/ngx_http_lua_module.so

九、为什么不是 make install?

因为我们的目标不是构建新的 Nginx。

如果执行:

make
make install

主要目标是:

编译 Nginx
+
安装 Nginx

而本文的目标是:

只生成动态模块

所以执行:

make modules

即可。

可以简单理解为:

make

构建 Nginx

make install

安装 Nginx

make modules

构建动态模块

因此整个 Docker Builder 实际上是:

Nginx Module Builder

而不是:

Nginx Installer

十、LuaJIT 的编译

Dockerfile 中:

ARG LUAJIT_BRANCH=v2.1

ARG LUAJIT_PREFIX=/home/opt/local/luajit

然后:

RUN git clone \
--depth=1 \
--branch=${LUAJIT_BRANCH} \
${GITHUB_PROXY}https://github.com/LuaJIT/LuaJIT.git \
/build/LuaJIT

编译:

RUN cd /build/LuaJIT && \
make -j$(nproc) && \
make install PREFIX=${LUAJIT_PREFIX}

最终:

/home/opt/local/luajit

里面会包含:

bin/
luajit

lib/
libluajit-5.1.so

include/
luajit-2.1

十一、为什么 LuaJIT 安装路径非常重要?

本文没有把 LuaJIT 安装到:

/usr/local

而是:

/home/opt/local/luajit

这是一个非常重要的设计。

因为后面编译 Nginx Lua Module 时使用:

--with-ld-opt="-Wl,-rpath,${LUAJIT_PREFIX}/lib"

实际就是:

-Wl,-rpath,/home/opt/local/luajit/lib

它会把 LuaJIT 的动态库搜索路径写入模块。


十二、RPATH 是什么?

ngx_http_lua_module.so 本身依赖 LuaJIT:

ngx_http_lua_module.so


libluajit-5.1.so.2

系统加载动态模块时,需要找到:

libluajit-5.1.so.2

如果找不到,就可能出现:

error while loading shared libraries

或者:

libluajit-5.1.so.2: cannot open shared object file

因此通过:

-Wl,-rpath,/home/opt/local/luajit/lib

告诉动态链接器:

LuaJIT 动态库在:

/home/opt/local/luajit/lib

这样生产环境只要保持目录结构一致即可。


十三、为什么还需要 lua-resty-core?

安装 LuaJIT 后,只能执行基础 Lua。

而 Nginx Lua 开发通常需要大量 OpenResty API。

例如:

ngx.req.get_headers()
ngx.req.set_header()
ngx.var
ngx.shared

等等。

这些能力需要 OpenResty Lua 生态提供支持。

因此 Dockerfile 下载:

lua-resty-core

并复制:

lib/resty
lib/ngx

到:

/output/luajit/share/lua/5.1/

最终:

share/lua/5.1/
├── ngx/
└── resty/

十四、lua-resty-http

如果 Lua 需要访问其他 HTTP 服务,可以使用:

local http = require "resty.http"

例如:

local http = require "resty.http"

local client = http.new()

local res, err = client:request_uri(
"http://127.0.0.1:8080/test",
{
method = "GET"
}
)

if not res then
ngx.log(ngx.ERR, err)
return
end

ngx.say(res.body)

这样就可以实现:

Nginx

Lua

HTTP Client

其他服务

对于 API Gateway 非常有用。


十五、lua-resty-lrucache

lua-resty-lrucache 可以提供 LRU 缓存。

例如:

第一次请求

访问后端

结果写入 Cache

第二次请求

读取 Cache

减少后端请求

可以用于:

  • Token 缓存
  • 配置缓存
  • 用户信息缓存
  • 临时数据缓存

十六、lua-resty-string

lua-resty-string 是 OpenResty Lua 生态中的常用基础库。

在实际项目中,经常会涉及:

Base64
SHA
HMAC
AES
随机数
字符串处理

因此将它一起打包到 Runtime 中。


十七、lua-cjson

网关开发几乎离不开 JSON。

例如:

local cjson = require "cjson.safe"

local data = {
code = 0,
message = "success"
}

ngx.say(cjson.encode(data))

Dockerfile 中:

RUN git clone \
--depth=1 \
--branch=${LUA_CJSON_BRANCH} \
${GITHUB_PROXY}https://github.com/openresty/lua-cjson.git \
/build/lua-cjson

然后编译:

RUN cd /build/lua-cjson && \
make \
LUA_INCLUDE_DIR=${LUAJIT_PREFIX}/include/luajit-2.1

最终得到:

cjson.so

放到:

/home/opt/local/luajit/lib/lua/5.1/

十八、Lua 模块搜索路径

Lua 加载模块的时候需要知道:

Lua 文件在哪里?
C 扩展在哪里?

因此设置:

ENV LUA_PATH="/output/luajit/share/lua/5.1/?.lua;/output/luajit/share/lua/5.1/?/init.lua;;"

ENV LUA_CPATH="/output/luajit/lib/lua/5.1/?.so;;"

对应关系:

LUA_PATH

.lua 文件

LUA_CPATH

.so 文件

例如:

require("resty.http")

最终寻找:

resty/http.lua

而:

require("cjson.safe")

则需要加载对应的 C 模块。


十九、为什么构建阶段必须做验证?

一个比较可靠的工程实践是:

能在 Docker Build 阶段发现的问题,不要留到生产环境。

因此 Dockerfile 中增加了:

RUN test -f /output/nginx/modules/ngx_http_lua_module.so && \
test -f /output/luajit/bin/luajit && \
test -f /output/luajit/lib/libluajit-5.1.so.2 && \
test -f /output/luajit/lib/lua/5.1/cjson.so && \
test -f /output/luajit/share/lua/5.1/resty/core.lua && \
test -f /output/luajit/share/lua/5.1/resty/http.lua && \
test -f /output/luajit/share/lua/5.1/resty/string.lua && \
test -f /output/luajit/share/lua/5.1/resty/lrucache.lua && \
test -f /output/luajit/share/lua/5.1/ngx/balancer.lua && \
echo "LUA OUTPUT FILES OK"

如果任何一个文件不存在:

Docker Build

失败

这样可以避免:

构建成功

发布生产

Nginx 启动失败

二十、使用 file 检查动态模块

还可以检查:

RUN file /output/nginx/modules/ngx_http_lua_module.so

主要用于确认它是正确的 ELF Shared Object。

例如:

ELF 64-bit LSB shared object

二十一、使用 ldd 检查依赖

这是整个 Dockerfile 中非常重要的一项检查:

RUN ldd /output/nginx/modules/ngx_http_lua_module.so

重点关注:

libluajit-5.1.so.2

如果显示:

not found

就说明动态链接库无法找到。

这时候即使:

ngx_http_lua_module.so

文件存在,生产环境也可能无法正常加载。


二十二、最终 Runtime Package

Docker Build 完成后:

/output
├── VERSION.txt

├── nginx
│ └── modules
│ └── ngx_http_lua_module.so

└── luajit
├── bin
│ └── luajit

├── include
│ └── luajit-2.1

├── lib
│ ├── libluajit-5.1.so
│ ├── libluajit-5.1.so.2
│ └── lua
│ └── 5.1
│ └── cjson.so

└── share
└── lua
└── 5.1
├── ngx
└── resty

这就是完整的 Lua Runtime。


二十三、生产环境部署

假设生产环境:

/home/opt/local/

原本已经存在:

nginx/

现在只增加:

luajit/

并把动态模块放到:

nginx/modules/

最终:

/home/opt/local/
├── nginx/
│ ├── nginx
│ ├── conf/
│ └── modules/
│ └── ngx_http_lua_module.so

└── luajit/
├── bin/
│ └── luajit
├── lib/
│ ├── libluajit-5.1.so.2
│ └── lua/
│ └── 5.1/
│ └── cjson.so
└── share/
└── lua/
└── 5.1/
├── ngx/
└── resty/

二十四、Nginx 加载 Lua 模块

在 Nginx 配置文件顶部增加:

load_module modules/ngx_http_lua_module.so;

例如:

load_module modules/ngx_http_lua_module.so;

events {
}

http {

}

注意:

load_module 必须位于顶层配置区域。

不能写成:

server {

load_module modules/ngx_http_lua_module.so;

}

也不能放到:

location {
}

里面。


二十五、配置 Lua Package Path

http 中增加:

http {

lua_package_path "/home/opt/local/luajit/share/lua/5.1/?.lua;/home/opt/local/luajit/share/lua/5.1/?/init.lua;;";

lua_package_cpath "/home/opt/local/luajit/lib/lua/5.1/?.so;;";

}

这样:

require("resty.http")

就可以找到:

/home/opt/local/luajit/share/lua/5.1/resty/http.lua

而:

require("cjson.safe")

可以找到:

/home/opt/local/luajit/lib/lua/5.1/cjson.so

二十六、第一个 Lua 测试

配置:

location /lua-test {

content_by_lua_block {

ngx.say("Hello Lua!")

}

}

首先:

nginx -t

如果:

syntax is ok
test is successful

说明 Nginx 配置正常。

然后访问:

http://127.0.0.1/lua-test

返回:

Hello Lua!

说明整个调用链已经成功:

HTTP Request

Nginx

ngx_http_lua_module.so

LuaJIT

Lua

ngx.say()

HTTP Response

二十七、测试 HTTP Client

继续测试:

location /lua-http {

content_by_lua_block {

local http = require "resty.http"

local client = http.new()

local res, err = client:request_uri(
"http://127.0.0.1:8080/test",
{
method = "GET"
}
)

if not res then
ngx.status = 500
ngx.say(err)
return
end

ngx.say(res.body)

}

}

整个请求流程变成:

客户端

Nginx

Lua

lua-resty-http

后端服务

这也是 Nginx + Lua 作为 API Gateway 时非常典型的使用方式。


二十八、Nginx + Lua 可以实现什么?

1. 动态鉴权

请求

Lua

Token 校验

通过 → Backend
失败 → 401 / 403

2. 动态路由

例如根据:

Header
Cookie
Query 参数
Token
用户信息
租户信息

选择不同后端。

请求

Lua

判断条件

Backend A / Backend B / Backend C

3. API Gateway

可以将:

鉴权
限流
路由
缓存
Header
HTTP 调用
JSON

统一放在 Nginx + Lua 层处理。


4. 动态修改 Header

例如:

ngx.req.set_header("X-User-Id", user_id)

然后再转发给后端。


5. 缓存

使用:

lua-resty-lrucache

可以实现进程内的 LRU 缓存。


二十九、整个方案的架构

最终可以理解为:

Production Server
┌─────────────────────────────────────────────────────┐
│ │
│ Nginx 1.26.3 │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ ngx_http_lua_module.so │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ │
│ ▼ │
│ LuaJIT 2.1 │
│ │ │
│ ┌───────────┼───────────┐ │
│ ▼ ▼ ▼ │
│ resty.core resty.http cjson │
│ │ │ │ │
│ └───────────┼───────────┘ │
│ ▼ │
│ Lua Script │
│ │
└─────────────────────────────────────────────────────┘

三十、Dockerfile 的职责

这份 Dockerfile 并不是用来重新制作生产 Nginx。

它的职责实际上是:

编译 LuaJIT

编译 ngx_http_lua_module.so

准备 lua-resty-core

准备 lua-resty-http

准备 lua-resty-string

准备 lua-resty-lrucache

编译 lua-cjson

检查动态库依赖

生成 Runtime Package

因此它更准确的定位是:

Nginx Lua Runtime Builder

三十一、为什么这个方案适合已有生产环境?

如果生产环境已经有:

Nginx 1.26.3

不需要:

重新安装 Nginx
重新编译 Nginx
替换 Nginx 二进制

只需要:

部署 LuaJIT

部署 Lua Libraries

部署 ngx_http_lua_module.so

load_module

nginx -t

reload

因此改造范围相对较小。


三十二、部署前检查清单

正式部署之前建议检查:

Nginx

nginx -V

确认:

版本一致
configure 参数尽量一致

LuaJIT

/home/opt/local/luajit/bin/luajit -v

动态模块

file /home/opt/local/nginx/modules/ngx_http_lua_module.so

动态依赖

ldd /home/opt/local/nginx/modules/ngx_http_lua_module.so

确认:

libluajit-5.1.so.2

没有:

not found

Nginx 配置

nginx -t

确认:

syntax is ok
test is successful

三十三、总结

为已有 Nginx 增加 Lua 能力,本质上需要建立下面这条运行链:

Nginx

ngx_http_lua_module.so

LuaJIT

Lua Runtime

lua-resty-* / cjson

本文采用的是:

动态模块
+
LuaJIT Runtime
+
OpenResty Lua Libraries

而不是重新编译并替换整个 Nginx。

整个方案的关键点有三个。

第一:Nginx 版本匹配

生产环境:

Nginx 1.26.3

构建动态模块:

Nginx 1.26.3

第二:只构建动态模块

核心参数:

--add-dynamic-module=/build/lua-nginx-module

然后:

make modules

最终得到:

ngx_http_lua_module.so

而不是重新安装 Nginx。


第三:保证 LuaJIT Runtime 完整

除了:

ngx_http_lua_module.so

还需要:

LuaJIT
lua-resty-core
lua-resty-http
lua-resty-string
lua-resty-lrucache
lua-cjson

同时需要保证:

RPATH
Lua Package Path
Lua C Package Path

配置正确。

最终,原有 Nginx 不需要被替换,只需要加载:

load_module modules/ngx_http_lua_module.so;

即可获得 Lua 执行能力。

这套方案特别适合已经运行在生产环境中的 Nginx:保留原有 Nginx 二进制和配置体系,通过独立的动态模块和 LuaJIT Runtime 增加可编程能力。

完整编译Dockerfile

FROM ubuntu:22.04 AS builder

ENV DEBIAN_FRONTEND=noninteractive

# ============================================================
# Build arguments
# ============================================================

ARG NGINX_VERSION=1.26.3

ARG LUAJIT_BRANCH=v2.1
ARG LUA_NGINX_MODULE_BRANCH=master
ARG LUA_RESTY_CORE_BRANCH=master
ARG LUA_RESTY_LRUCACHE_BRANCH=master
ARG LUA_RESTY_STRING_BRANCH=master
ARG LUA_RESTY_HTTP_BRANCH=master
ARG LUA_CJSON_BRANCH=master

# GitHub proxy prefix
#
# 最终:
# https://ghfast.top/https://github.com/xxx
#
ARG GITHUB_PROXY=https://ghfast.top/

# ============================================================
# Important:
#
# 这是生产服务器 LuaJIT 的最终安装路径。
#
# ngx_http_lua_module.so 会使用这个路径作为 RPATH,
# 所以不能使用 Docker 内部的 /opt/build/luajit。
# ============================================================

ARG LUAJIT_PREFIX=/home/opt/local/luajit

ENV LUAJIT_PREFIX=${LUAJIT_PREFIX}

WORKDIR /build


# ============================================================
# 1. Build dependencies
# ============================================================

RUN apt-get update && \
apt-get install -y \
build-essential \
gcc \
g++ \
make \
git \
wget \
curl \
ca-certificates \
perl \
pkg-config \
file \
binutils \
libpcre3 \
libpcre3-dev \
zlib1g-dev \
libssl-dev \
&& \
rm -rf /var/lib/apt/lists/*


# ============================================================
# 2. Build LuaJIT
# ============================================================

RUN git clone \
--depth=1 \
--branch=${LUAJIT_BRANCH} \
${GITHUB_PROXY}https://github.com/LuaJIT/LuaJIT.git \
/build/LuaJIT

RUN cd /build/LuaJIT && \
make -j$(nproc) && \
make install PREFIX=${LUAJIT_PREFIX}


# ============================================================
# 3. Verify LuaJIT
# ============================================================

RUN ${LUAJIT_PREFIX}/bin/luajit -v


# ============================================================
# 4. Download Nginx source
#
# 这里只是为了使用 nginx 1.26.3 的源码编译动态模块。
#
# 不会生成新的 nginx 二进制用于生产部署。
# ============================================================

RUN wget \
https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz \
-O /build/nginx-${NGINX_VERSION}.tar.gz

RUN tar \
-xzf /build/nginx-${NGINX_VERSION}.tar.gz \
-C /build


# ============================================================
# 5. Download lua-nginx-module
# ============================================================

RUN git clone \
--depth=1 \
--branch=${LUA_NGINX_MODULE_BRANCH} \
${GITHUB_PROXY}https://github.com/openresty/lua-nginx-module.git \
/build/lua-nginx-module


# ============================================================
# 6. Configure Nginx dynamic module
#
# 必须与你生产环境的 nginx -V 保持一致。
#
# 你的生产环境:
#
# nginx/1.26.3
#
# configure:
#
# --prefix=/home/opt/local/nginx
# --with-http_stub_status_module
# --with-http_ssl_module
# --with-stream
# --with-http_v2_module
#
# 注意:
#
# 1. 不使用 --with-compat
# 2. 不执行 make install
# 3. 只执行 make modules
# 4. RPATH 指向生产环境 LuaJIT 路径
# ============================================================

WORKDIR /build/nginx-${NGINX_VERSION}

RUN export LUAJIT_LIB=${LUAJIT_PREFIX}/lib && \
export LUAJIT_INC=${LUAJIT_PREFIX}/include/luajit-2.1 && \
./configure \
--prefix=/home/opt/local/nginx \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream \
--with-http_v2_module \
--with-ld-opt="-Wl,-rpath,${LUAJIT_PREFIX}/lib" \
--add-dynamic-module=/build/lua-nginx-module


# ============================================================
# 7. Compile ONLY dynamic modules
# ============================================================

RUN make -j$(nproc) modules


# ============================================================
# 8. Prepare output directories
# ============================================================

RUN mkdir -p \
/output/nginx/modules \
/output/luajit/bin \
/output/luajit/lib \
/output/luajit/include \
/output/luajit/share


# ============================================================
# 9. Copy ngx_http_lua_module.so
# ============================================================

RUN cp \
/build/nginx-${NGINX_VERSION}/objs/ngx_http_lua_module.so \
/output/nginx/modules/ngx_http_lua_module.so


# ============================================================
# 10. Download lua-resty-core
# ============================================================

RUN git clone \
--depth=1 \
--branch=${LUA_RESTY_CORE_BRANCH} \
${GITHUB_PROXY}https://github.com/openresty/lua-resty-core.git \
/build/lua-resty-core

RUN mkdir -p \
/output/luajit/share/lua/5.1

RUN cp -a \
/build/lua-resty-core/lib/resty \
/output/luajit/share/lua/5.1/

RUN cp -a \
/build/lua-resty-core/lib/ngx \
/output/luajit/share/lua/5.1/

# ============================================================
# 11. Download lua-resty-lrucache
# ============================================================

RUN git clone \
--depth=1 \
--branch=${LUA_RESTY_LRUCACHE_BRANCH} \
${GITHUB_PROXY}https://github.com/openresty/lua-resty-lrucache.git \
/build/lua-resty-lrucache

RUN cp -a \
/build/lua-resty-lrucache/lib/resty/. \
/output/luajit/share/lua/5.1/resty/


# ============================================================
# 12. Download lua-resty-string
# ============================================================

RUN git clone \
--depth=1 \
--branch=${LUA_RESTY_STRING_BRANCH} \
${GITHUB_PROXY}https://github.com/openresty/lua-resty-string.git \
/build/lua-resty-string

RUN cp -a \
/build/lua-resty-string/lib/resty/. \
/output/luajit/share/lua/5.1/resty/


# ============================================================
# 13. Download lua-resty-http
# ============================================================

RUN git clone \
--depth=1 \
--branch=${LUA_RESTY_HTTP_BRANCH} \
${GITHUB_PROXY}https://github.com/ledgetech/lua-resty-http.git \
/build/lua-resty-http

RUN cp -a \
/build/lua-resty-http/lib/resty/. \
/output/luajit/share/lua/5.1/resty/

# ============================================================
# 14. Build lua-cjson
# ============================================================

RUN git clone \
--depth=1 \
--branch=${LUA_CJSON_BRANCH} \
${GITHUB_PROXY}https://github.com/openresty/lua-cjson.git \
/build/lua-cjson

RUN cd /build/lua-cjson && \
make \
LUA_INCLUDE_DIR=${LUAJIT_PREFIX}/include/luajit-2.1

RUN mkdir -p \
/output/luajit/lib/lua/5.1

RUN cp \
/build/lua-cjson/cjson.so \
/output/luajit/lib/lua/5.1/cjson.so


# ============================================================
# 15. Copy LuaJIT runtime
# ============================================================

RUN cp \
${LUAJIT_PREFIX}/bin/luajit \
/output/luajit/bin/luajit

RUN cp -a \
${LUAJIT_PREFIX}/lib/libluajit-5.1.so* \
/output/luajit/lib/


# ============================================================
# 16. Copy LuaJIT headers
#
# 生产运行其实不需要 headers,
# 但保留它们方便以后继续编译 Lua 模块。
# ============================================================

RUN cp -a \
${LUAJIT_PREFIX}/include/luajit-2.1 \
/output/luajit/include/


# ============================================================
# 17. Verify Lua modules
#
# 这里非常重要。
#
# 在 Docker build 阶段直接验证:
#
# require("resty.core")
# require("resty.http")
# require("resty.string")
# require("resty.lrucache")
# require("cjson.safe")
# ============================================================

ENV LUA_PATH="/output/luajit/share/lua/5.1/?.lua;/output/luajit/share/lua/5.1/?/init.lua;;"
ENV LUA_CPATH="/output/luajit/lib/lua/5.1/?.so;;"

RUN test -f /output/nginx/modules/ngx_http_lua_module.so && \
test -f /output/luajit/bin/luajit && \
test -f /output/luajit/lib/libluajit-5.1.so.2 && \
test -f /output/luajit/lib/lua/5.1/cjson.so && \
test -f /output/luajit/share/lua/5.1/resty/core.lua && \
test -f /output/luajit/share/lua/5.1/resty/http.lua && \
test -f /output/luajit/share/lua/5.1/resty/string.lua && \
test -f /output/luajit/share/lua/5.1/resty/lrucache.lua && \
test -f /output/luajit/share/lua/5.1/ngx/balancer.lua && \
echo "LUA OUTPUT FILES OK"

# ============================================================
# 18. Verify nginx lua module
# ============================================================

RUN echo "===== file =====" && \
file /output/nginx/modules/ngx_http_lua_module.so


# ============================================================
# 19. Verify dynamic dependencies
# ============================================================

RUN echo "===== ldd ngx_http_lua_module.so =====" && \
ldd /output/nginx/modules/ngx_http_lua_module.so


# ============================================================
# 20. Verify LuaJIT dynamic library
# ============================================================

RUN echo "===== LuaJIT libraries =====" && \
ls -lah /output/luajit/lib/


# ============================================================
# 21. Verify cjson
# ============================================================

RUN echo "===== cjson =====" && \
ls -lah /output/luajit/lib/lua/5.1/cjson.so


# ============================================================
# 22. Verify resty libraries
# ============================================================

RUN echo "===== resty libraries =====" && \
find /output/luajit/share/lua/5.1/resty \
-type f \
| sort


# ============================================================
# 23. Generate VERSION.txt
# ============================================================

RUN { \
echo "=================================================="; \
echo "Nginx Lua Runtime Package"; \
echo "=================================================="; \
echo ""; \
echo "Nginx Version: ${NGINX_VERSION}"; \
echo "LuaJIT Branch: ${LUAJIT_BRANCH}"; \
echo ""; \
echo "Production Nginx Prefix:"; \
echo "/home/opt/local/nginx"; \
echo ""; \
echo "Production LuaJIT Prefix:"; \
echo "/home/opt/local/luajit"; \
echo ""; \
echo "Nginx Configure:"; \
echo "--prefix=/home/opt/local/nginx"; \
echo "--with-http_stub_status_module"; \
echo "--with-http_ssl_module"; \
echo "--with-stream"; \
echo "--with-http_v2_module"; \
echo "--add-dynamic-module=lua-nginx-module"; \
echo ""; \
echo "Lua Modules:"; \
find /output/luajit/share/lua/5.1/resty \
-type f | sort; \
echo ""; \
echo "C Modules:"; \
find /output/luajit/lib/lua/5.1 \
-type f | sort; \
} > /output/VERSION.txt


# ============================================================
# ============================================================
# Final image
# ============================================================
# ============================================================

FROM ubuntu:22.04

COPY --from=builder /output /output

CMD ["bash"]

本文阅读量:--

总访问量 -- · 访客数 --