Upload
moriyoshi-koizumi
View
4.064
Download
3
Embed Size (px)
Citation preview
nginxとLuaの話moriyoshi
Introduction
nginxとは
カザフスタン出身のИгорь Сысоевさん (43) によって開発されたHTTPサーバ
2002年より開発がスタート、2004年に公開
Luaとは
ブラジルの Pontifical Catholic University of Rio で開発されているプログラミング言語
埋め込み型のプログラミング言語として開発され、ゲーム業界を中心に浸透、現在は汎用的なプログラミング言語として一定の地位を得ている
ガーベジコレクション、コルーチン
nginx-lua
nginxでLuaを使うためのモジュール
nginxのモジュールで行えるような各種カスタマイズをLuaで記述可能
https://github.com/chaoslawful/lua-nginx-module/
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
あとこれらのビルドに必要なライブラリ一通り
ものすごく楽できるので使おう
nginxのリクエスト処理フローとカスタマイズポイント
nginxのライフサイクル
初期化
後始末
イベントループ
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
nginxのカスタマイズポイント
初期化フェーズnginxの起動直後、サーバとして動作し始める前に呼ばれるinit_by_lua / init_by_lua_file
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
nginxのカスタマイズポイント
content handlerリクエストに基づいてレスポンスを生成するcontent_by_lua / content_by_lua_file
logフェーズアクセスログを記録するlog_by_lua / log_by_lua_file
nginxのカスタマイズポイント
output filternginxがレスポンスを返す直前に呼ばれるbody_filter_by_lua / body_filter_by_lua_fileheader_filter_by_lua / header_filter_by_lua_file
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のみ)
レスポンス関連
ngx.say - レスポンスボディを返す
ngx.header[”XXX”] - レスポンスヘッダを設定する
ngx.exit() - リクエストの処理を終了して、レスポンスコードをクライアントに返す
組み込み関数
ngx.time() / ngx.now() - 現在時刻を取得ngx.timer.at() - JSのsetTimeout()みたいなものngx.exec() - 内部リダイレクトを行うngx.location.capture() - サブリクエストを生成し、その結果をLuaスクリプト内部で利用できる外部のWebサーバのレスポンスを簡易的に取得するのに...内部的なHTTPレスポンスをフィルタするのに...
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 にリダイレクト
共有メモリ (ngx.shared)
ngx.shared[”XXX”] - リクエスト間で共有されるkey-value dictionaryを取得する
Redisなど使うまでもない場合に有用
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 へのアクセスでインクリメント
サンプル
rewrite_by_lua
location /foo { rewrite_by_lua " ngx.req.set_uri_args({ xkey = "xxx" }); "; proxy_pass http://some_upstream;}
アップストリームにリクエストを投げるときに、xkeyというパラメータを付加する
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をアップストリームとして使う
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時以外のアクセスを禁止する
header_filter_by_lua
location /foo { header_filter_by_lua " ngx.header[\"X-Powered-By\"] = \"PHP 7.0.0\" ";}
レスポンスヘッダにX-Powered-Byを強制付加
ありがとうございました
Appendix: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")
数値型・文字列・ブール型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
テーブル
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
関数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
繰り返し処理
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
イテレータ関数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
正規表現
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”