Open7
NginxでLuaを使う
nginx公式から、third-party moduleを組み込んだnginxコンテナイメージを作る方法が提供されている。
curl -O https://raw.githubusercontent.com/nginxinc/docker-nginx/master/modules/Dockerfile
docker build --build-arg ENABLED_MODULES="ndk lua" -t nginx-with-lua .
ndkはluaモジュールを動かすのに必要。
docker run --rm --name nginx -p 80:80 nginx-with-lua
無事動作した。
証明書を作ろう。ついでにmTLSの確認もしたいので、クライアント証明書も作ろう。
PROJ_NAME="nginx-lua-hands-on"
mkdir -p server-certs/{private,public}
mkdir -p client-ca/{private,public,issued}
# サーバ証明書(自己署名)を作成
CN= # IP or server name
openssl req -x509 -nodes -newkey rsa:4096 \
-keyout server-certs/private/my-server.key \
-out server-certs/public/my-server.pem \
-subj "/C=JP/O=astk/OU=${PROJ_NAME}/CN=${CN}"
# クライアント証明書を発行するCA
openssl req -x509 -nodes \
-newkey rsa:4096 -keyout client-ca/private/my-client-ca.key \
-out client-ca/public/my-client-ca.pem -sha256 -days 7 \
-subj "/C=JP/O=astk/OU=${PROJ_NAME}/CN=my-client-ca"
# クライアント証明書を発行
openssl req -nodes -new \
-newkey rsa:4096 -keyout client-ca/issued/user1.key \
-out client-ca/issued/user1.csr -sha256 -days 7 \
-subj "/C=JP/O=astk/OU=${PROJ_NAME}/CN=user1"
openssl x509 -req -in client-ca/issued/user1.csr \
-CA client-ca/public/my-client-ca.pem -CAkey client-ca/private/my-client-ca.key -CAcreateserial \
-out client-ca/issued/user1.pem -sha256 -days 7
作り終えるとディレクトリは以下のようになる。
.
├── Dockerfile
├── client-ca
│ ├── issued
│ │ ├── user1.csr
│ │ ├── user1.key
│ │ └── user1.pem
│ ├── private
│ │ └── my-client-ca.key
│ └── public
│ ├── my-client-ca.pem
│ └── my-client-ca.srl
└── server-certs
├── private
│ └── my-server.key
└── public
└── my-server.pem
とりあえずLuaも証明書も使わずに普通に動かしてみる。
$ cat nginx/www/index.html
<h1>It works!</h1>
<p>nginx-lua-hands-on</p>
$ cat nginx/conf/nginx.conf
error_log /var/log/error.log;
events {
worker_connections 4096;
}
http {
server {
listen 80;
location / {
root /usr/share/nginx/html;
}
}
}
docker run --rm --name nginx \
-p 80:80 \
-v ${PWD}/nginx/www:/usr/share/nginx/html:ro \
-v ${PWD}/nginx/conf:/etc/nginx:ro \
nginx-with-lua
動いた。
error_log /var/log/error.log;
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_lua_module.so;
load_module modules/ngx_stream_lua_module.so;
events {
worker_connections 4096;
}
http {
server {
listen 80;
location / {
root /usr/share/nginx/html;
content_by_lua_block {
ngx.say('Hello, world!')
}
}
}
}
luaモジュールを読み込んで動かしてみる。
2022/02/19 18:00:46 [emerg] 1#1: dlopen() "/etc/nginx/modules/ndk_http_module.so" failed (/etc/nginx/modules/ndk_http_module.so: cannot open shared object file: No such file or directory) in /etc/nginx/nginx.conf:3
nginx: [emerg] dlopen() "/etc/nginx/modules/ndk_http_module.so" failed (/etc/nginx/modules/ndk_http_module.so: cannot open shared object file: No such file or directory) in /etc/nginx/nginx.conf:3
動かない。モジュールは /usr/lib/nginx/modules
にインストールされているが、load_modules
では /etc/nginx
からのパスとして解釈されている。
root@b68c8aa542f8:/# nginx -V 2>&1 | tr ' ' \\n | grep -- --modules-path
--modules-path=/usr/lib/nginx/modules
root@b68c8aa542f8:/# nginx -V 2>&1 | tr ' ' \\n | grep -- --prefix
--prefix=/etc/nginx
root@b68c8aa542f8:/# ls /usr/lib/nginx/modules
ngx_http_geoip_module-debug.so ngx_http_image_filter_module.so ngx_http_xslt_filter_module-debug.so ngx_stream_geoip_module.so
ngx_http_geoip_module.so ngx_http_js_module-debug.so ngx_http_xslt_filter_module.so ngx_stream_js_module-debug.so
ngx_http_image_filter_module-debug.so ngx_http_js_module.so ngx_stream_geoip_module-debug.so ngx_stream_js_module.so
root@b68c8aa542f8:/# nginx -V 2>&1 | tr ' ' \\n | grep -- --prefix
--prefix=/etc/nginx
--prefix
を見ているような気がする。nginx -p
で指定できるみたいなので /usr/lib/nginx
を指定してみる。
docker run --rm --name nginx -p 80:80 \
-v ${PWD}/nginx/www:/usr/share/nginx/html:ro \
-v ${PWD}/nginx/conf:/etc/nginx:ro \
nginx-with-lua nginx -p /usr/lib/nginx -g 'daemon off;'
で動いた。nginxは普通に起動するとデーモンとして動いてしまうみたいなのでオプションでその挙動をオフにした。
astk@u21a:~$ curl localhost:80
Hello, world!
astk@u21a:~$
Luaが実行されたメッセージが返ってくる。
nginx_lua_moduleのデバッグのテクニックをまとめよう。
まずはシンプルに、プリントデバッグができるようになろう。
-
https://github.com/openresty/lua-nginx-module#print
-
ngx.print
を使ってログをerror_log
に設定したファイルに出力できる -
ngx.log(ngx.NOTICE, ...
と同等
-
-
https://nginx.org/en/docs/ngx_core_module.html#error_log
-
error_log
はデフォルトではerror
レベルなのでnitice
に指定してやる。
-
設定はこんな感じ。
nginx.conf
error_log /var/log/error.log notice;
load_module /usr/lib/nginx/modules/ndk_http_module.so;
load_module /usr/lib/nginx/modules/ngx_http_lua_module.so;
load_module /usr/lib/nginx/modules/ngx_stream_lua_module.so;
events {
worker_connections 4096;
}
http {
server {
listen 80;
location / {
root /usr/share/nginx/html;
content_by_lua_block {
print('Hello, Lua!')
}
}
}
}
こんなふうに表示される。
astk@u21a:~$ docker exec -it nginx tail -f /var/log/error.log
2022/02/21 18:23:50 [notice] 1#1: using the "epoll" event method
2022/02/21 18:23:50 [warn] 1#1: 4096 worker_connections exceed open file resource limit: 1024
2022/02/21 18:23:50 [notice] 1#1: nginx/1.21.6
2022/02/21 18:23:50 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2022/02/21 18:23:50 [notice] 1#1: OS: Linux 5.13.0-28-generic
2022/02/21 18:23:50 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1024:524288
2022/02/21 18:23:50 [notice] 1#1: start worker processes
2022/02/21 18:23:50 [notice] 1#1: start worker process 22
2022/02/21 18:24:07 [notice] 22#22: *1 [lua] content_by_lua(nginx.conf:18):2: Hello, Lua!, client: 172.17.0.1, server: , request: "GET / HTTP/1.1", host: "localhost"