Lua Syntax Fundamentals
Nginx and Lua Environment
Objective: Use Nginx combined with Lua to implement a canary release strategy.
- Lua Overview
A lightweight, compact, and highly extensible scripting language. - Nginx+Lua Advantages
Combines the efficient concurrency handling of Nginx's event-driven mechanism (epoll) with the agility of Lua, making it ideal for high-concurrency scenarios requiring simple logic execution.
Lua Syntax Basics
Variables
data = [[raw string \"content\"]]data = 'escaped\nstring'data = '\97lo\10\04923'
Boolean types consider only nil and false as false; numeric 0 and empty strings are evaluated as true. By default, variables are global unless explicitly declared local.
Loops
total = 0
i = 1
while i <= 100 do
total = total + i
i = i + 1
end
print("Total sum: ", total)
-- Lua does not support ++ or += operators
-- For loop example
aggregate = 0
for k = 1, 100 do
aggregate = aggregate + k
end
Conditional Logic
if user_age == 30 and gender == "female" then
print("30 year old female")
elseif user_age > 30 and gender ~= "male" then
print("Older non-male")
else
local input_age = io.read()
print("Entered age: " .. input_age)
end
Reference: Lua Tutorial
Nginx and Lua Deployment
Deployment Guide Reference: Article Link
- Install LuaJIT
wget http://luajit.org/download/LuaJIT-2.0.2.tar.gz tar -zxvf LuaJIT-2.0.2.tar.gz cd LuaJIT-2.0.2 make install PREFIX=/usr/local/LuaJIT # Append environment variables to /etc/profile export LUAJIT_LIB=/usr/local/lib export LUAJIT_INC=/usr/local/include/luajit-2.0 - Download Modules
cd /opt/download wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz wget https://github.com/openresty/lua-nginx-module/archive/v0.10.9rc7.tar.gz # Extract both archives for inclusion during compilation - Recompile Nginx
# Download Nginx Source cd /data wget http://nginx.org/download/nginx-1.12.1.tar.gz tar -zxvf nginx-1.12.1.tar.gz;cd nginx-1.12.1 # Install Prerequisites yum install openssl openssl-devel -y yum install zlib zlib-devel -y yum install pcre-devel -y # Compile Configuration ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-module=/data/ngx_devel_kit-0.3.0 --add-module=/data/lua-nginx-module-0.10.9rc7 make && make install echo "/usr/local/lib" >> /etc/ld.so.conf ldconfig # Verify installation nginx -V
Verifying Lua Integration
# Add to /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name web01.fadewalk.com;
location /lua {
set $message "hello,world";
content_by_lua '
ngx.header.content_type="text/plain"
ngx.say(ngx.var.message)';
}
}
Nginx Lua Module Directives
Nginx processes requests through 11 distinct phases. Lua modules can hook into specific stages of this lifecycle.
- set_by_lua / set_by_lua_file: Assigns values to Nginx variables, enabling complex logic during variable assignment.
- access_by_lua / access_by_lua_file: Executes during the access phase, typically used for access control and authentication.
- content_by_lua / content_by_lua_file: Handles the content generation phase, processing requests and outputting responses.
Key Lua API Functions
ngx.var: Access to Nginx variables.ngx.req.get_headers(): Retrieves HTTP request headers.ngx.req.get_uri_args(): Retrieves URL query parameters.ngx.redirect: Performs an HTTP redirect.ngx.print: Outputs response body data.ngx.say: Similar tongx.printbut appends a newline character.ngx.header: Modifies output response headers.
Implementing Canary Release
Canary release involves rolling out new code versions to a subset of users to ensure stability before a full deployment. This strategy relies on differentiation logic such as user cookies, geographical location, or specific IP ranges.
dep.conf Configuration
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/log/host.access.log main;
location /hello {
default_type 'text/plain';
content_by_lua 'ngx.say("hello, lua")';
}
location /myip {
default_type 'text/plain';
content_by_lua '
local cli_ip = ngx.req.get_headers()["x_forwarded_for"]
ngx.say("Client IP:", cli_ip)';
}
location / {
default_type "text/html";
content_by_lua_file /opt/app/lua/dep.lua;
}
location @production_server{
proxy_pass http://127.0.0.1:9090;
}
location @canary_server{
proxy_pass http://127.0.0.1:8080;
}
error_page 500 502 503 504 404 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
dep.lua Script
-- Determine Client IP
local client_ip = ngx.req.get_headers()["X-Real-IP"]
if client_ip == nil then
client_ip = ngx.req.get_headers()["x_forwarded_for"]
end
if client_ip == nil then
client_ip = ngx.var.remote_addr
end
-- Connect to Memcached
local memcached = require "resty.memcached"
local memc, err = memcached:new()
if not memc then
ngx.say("failed to instantiate memc: ", err)
return
end
local ok, err = memc:connect("127.0.0.1", 11211)
if not ok then
ngx.say("failed to connect: ", err)
return
end
-- Check Feature Flag in Cache
local res, flags, err = memc:get(client_ip)
if err then
ngx.say("failed to get clientIP ", err)
return
end
ngx.say("lookup result: ", res, " for IP: ", client_ip)
if res == "1" then
-- Redirect to Canary Environment
ngx.exec("@canary_server")
return
end
-- Default to Production
ngx.exec("@production_server")