34
nginxとLuaの話 moriyoshi

Nginx lua

Embed Size (px)

Citation preview

Page 1: Nginx lua

nginxとLuaの話moriyoshi

Page 2: Nginx lua

Introduction

Page 3: Nginx lua

nginxとは

カザフスタン出身のИгорь Сысоевさん (43) によって開発されたHTTPサーバ

2002年より開発がスタート、2004年に公開

Page 4: Nginx lua

Luaとは

ブラジルの Pontifical Catholic University of Rio で開発されているプログラミング言語

埋め込み型のプログラミング言語として開発され、ゲーム業界を中心に浸透、現在は汎用的なプログラミング言語として一定の地位を得ている

ガーベジコレクション、コルーチン

Page 5: Nginx lua

nginx-lua

nginxでLuaを使うためのモジュール

nginxのモジュールで行えるような各種カスタマイズをLuaで記述可能

https://github.com/chaoslawful/lua-nginx-module/

Page 6: Nginx lua

OpenResty

nginx-lua の現在のメンテナの agentzh (章亦春さん) が提供しているバンドル

つぎのモジュールが全部入りarray-var / auth-request / coolkit / echo / encrypted-session / form-input / headers-more / iconv-nginx / lua / memc / postgres / redis / redis2 / set-misc / srcache / xss

あとこれらのビルドに必要なライブラリ一通り

ものすごく楽できるので使おう

Page 7: Nginx lua

nginxのリクエスト処理フローとカスタマイズポイント

Page 8: Nginx lua

nginxのライフサイクル

初期化

後始末

イベントループ

Page 9: Nginx lua

nginxのリクエスト処理フローリクエスト

preaccess / access

rewrite

content handler

output filter

レスポンス

limit_req / allow / deny / auth_basic 等

if / set / rewrite等

autoindex / proxy_pass 等

post read

location

log

server rewrite rewrite等

access_log 等

location

Page 10: Nginx lua

nginxのカスタマイズポイント

初期化フェーズnginxの起動直後、サーバとして動作し始める前に呼ばれるinit_by_lua / init_by_lua_file

Page 11: Nginx lua

nginxのカスタマイズポイント

rewriteフェーズ (1)rewriteが行われる前に呼ばれるset_by_lua / set_by_lua_file

rewriteフェーズ (2)accessフェーズの直前に呼ばれるrewrite_by_lua / rewrite_by_lua_file

accessフェーズcontent handlerをディスパッチする前に呼ばれるaccess_by_lua / access_by_lua_file

Page 12: Nginx lua

nginxのカスタマイズポイント

content handlerリクエストに基づいてレスポンスを生成するcontent_by_lua / content_by_lua_file

logフェーズアクセスログを記録するlog_by_lua / log_by_lua_file

Page 13: Nginx lua

nginxのカスタマイズポイント

output filternginxがレスポンスを返す直前に呼ばれるbody_filter_by_lua / body_filter_by_lua_fileheader_filter_by_lua / header_filter_by_lua_file

Page 14: Nginx lua

nginx_luaを使うにあたり覚えておくとよいこと (チートシート)

Page 15: Nginx lua

リクエスト関連ngx.var.XXX - nginx変数$XXXの取得ngx.var.uri - リクエストURI

ngx.var[1] ... ngx.var[n] - locationのマッチ ($1...n)ngx.req.get_uri_args() - リクエストURIのパラメータ部分をテーブルでngx.req.get_headers() - リクエストヘッダを取得ngx.req.get_post_args() - POSTパラメータをパース (ngx.req.read_post() を事前に呼んでおく / application/x-www-form-urlencodedのみ)

Page 16: Nginx lua

レスポンス関連

ngx.say - レスポンスボディを返す

ngx.header[”XXX”] - レスポンスヘッダを設定する

ngx.exit() - リクエストの処理を終了して、レスポンスコードをクライアントに返す

Page 17: Nginx lua

組み込み関数

ngx.time() / ngx.now() - 現在時刻を取得ngx.timer.at() - JSのsetTimeout()みたいなものngx.exec() - 内部リダイレクトを行うngx.location.capture() - サブリクエストを生成し、その結果をLuaスクリプト内部で利用できる外部のWebサーバのレスポンスを簡易的に取得するのに...内部的なHTTPレスポンスをフィルタするのに...

Page 18: Nginx lua

ngx.location.capture

location = /internal { internal; resolver 8.8.8.8; proxy_pass http://determiner.example.com;}

location /foo { rewrite_by_lua " res = ngx.location.capture(\"/internal\") local m, err = ngx.re.match(\"OOPS\", res.body) if m then return ngx.redirect(\"/oops.html\") end ";}

/internalのレスポンスに文字列”OOPS”が含まれていたら、/oops.html にリダイレクト

Page 19: Nginx lua

共有メモリ (ngx.shared)

ngx.shared[”XXX”] - リクエスト間で共有されるkey-value dictionaryを取得する

Redisなど使うまでもない場合に有用

Page 20: Nginx lua

ngx.shared

http { lua_shared_dict counter 12k; server { listen 8080;

location /reset { content_by_lua ' ngx.shared.counter:set("value", 0) ngx.say("counter reset") '; }

location /inc { content_by_lua ' local value = ngx.shared.counter:get("value") ngx.shared.counter:set("value", value + 1) ngx.say("count = " .. tostring(value)) '; } }}

簡易的なカウンタ: /inc へのアクセスでインクリメント

Page 21: Nginx lua

サンプル

Page 22: Nginx lua

rewrite_by_lua

location /foo { rewrite_by_lua " ngx.req.set_uri_args({ xkey = "xxx" }); "; proxy_pass http://some_upstream;}

アップストリームにリクエストを投げるときに、xkeyというパラメータを付加する

Page 23: Nginx lua

rewrite_by_lua

location /foo { set $bucket "hoge"; set $access_key "XXXXXX"; set $secret_key "YYYYYY"; rewrite_by_lua ' local date = ngx.http_time(ngx.time()) local string_to_sign = ngx.req.get_method() .. "\\n\\n\\n" .. date .. "\\n/" .. ngx.var.bucket .. "/" .. ngx.var[1] ngx.req.set_header("Date", date) ngx.req.set_header("Authorization", "AWS " .. ngx.var.access_key .. ":" .. ngx.encode_base64(ngx.hmac_sha1(ngx.var.secret_key, string_to_sign))) '; proxy_pass http://$bucket.s3.amazonaws.com/$1;}

認証のかかったS3をアップストリームとして使う

Page 24: Nginx lua

acess_by_lua

location /foo { access_by_lua " local t = ngx.time() % 86400 if t >= 3600 * 12 then ngx.exit(ngx.HTTP_FORBIDDEN) end ";}

日本時間の9~21時以外のアクセスを禁止する

Page 25: Nginx lua

header_filter_by_lua

location /foo { header_filter_by_lua " ngx.header[\"X-Powered-By\"] = \"PHP 7.0.0\" ";}

レスポンスヘッダにX-Powered-Byを強制付加

Page 26: Nginx lua

ありがとうございました

Page 27: Nginx lua

Appendix:Lua基礎文法

Page 28: Nginx lua

Hello World

function hello() local table = {"h", "e", "l", "l", "o"} local hello = "" for _, c in ipairs(table) do hello = hello .. c end return helloendprint(hello(), "world")

Page 29: Nginx lua

数値型・文字列・ブール型a = 1b = (a + 1) * 2c = b / 3 -- c = 1.33333333...d = "string"e = f .. "string" -- e = "stringstring"f = e + 3 -- ERRORg = "1" + "2" -- g == 3, type(j) == "number"h = true or false -- truei = true and false -- false

Page 30: Nginx lua

テーブル

a = { 1, 2, 3, 4, 5 }print(a[1], a[2], a[3]) -- 1 2 3b = { a=1, b=2, c=3, d=4, e=5 }print(b["a"], b["b"], b["c"]) -- 1 2 3print(b.a, b.b, b.c) -- 1 2 3

Page 31: Nginx lua

関数function fibo(n) if n == 0 then return 0 elseif n == 1 then return 1 else return fibo(n - 2) + fibo(n - 1) endend

print(fibo(10)) -- 55

Page 32: Nginx lua

繰り返し処理

for i = 0, 9, 1 do print(i)end -- 0 / 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9

for i, v in ipairs({ 0, 1, 2, 3 }) do print(i, v)end -- 1, 0 / 2, 1 / 3, 2 / 4, 3

for k, v in pairs({ a=0, b=1, c=2, d=3 }) do print(k, v)end -- ”a”, 0 / ”b”, 1 / ”c”, 2 / ”d”, 3

Page 33: Nginx lua

イテレータ関数i = 0function iterate() i = i + 1 if i < 10 then return i endend

for k in iterate do print(k)end -- 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9

Page 34: Nginx lua

正規表現

a = "abcdef"beg, end_, capture = string.find(a, "([abc]+)")print(beg, end_, capture) -- 1, 3, "abc"b = string.gsub(a, "[de]", "*")print(b) -- "abc**f"c = "abc def ghi jkl"for m in string.gmatch(c, "([a-z]+)") do print(m)end -- ”abc” / ”def” / ”ghi” / ”jkl”