Open7

NginxでLuaを使う

astkastk
astkastk

nginx公式から、third-party moduleを組み込んだnginxコンテナイメージを作る方法が提供されている。
https://github.com/nginxinc/docker-nginx/tree/master/modules

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

無事動作した。

astkastk

証明書を作ろう。ついでに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
astkastk

とりあえず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

動いた。

astkastk
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が実行されたメッセージが返ってくる。

astkastk

nginx_lua_moduleのデバッグのテクニックをまとめよう。

astkastk

まずはシンプルに、プリントデバッグができるようになろう。

設定はこんな感じ。

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"