nginx
でLua
を使いたいとなるとOpenresty
が定番ですが最近はnginxで使える組み込み言語としてnjs
というものがあります。
nginx/njs: An official read-only mirror of http://hg.nginx.org/njs/ which is updated hourly.
njs
は2016年に登場したNginx, Incが開発を進めているJavascriptのサブセットとなる言語です。
njsはlua同様に設定ファイルを動的に変更することが可能です。機能の豊富さなどではluaに軍配が上がりますが導入のしやすさあまり複雑なことをしない場合にはnjsも使いやすいのではないかと思います。
また、Web系のエンジニアとしてはluaよりもJavascriptの文法に馴染みがあると思うのでluaの学習コストを払いたくない場合などにnjsが選択肢になってくると思います。(自分はバックエンド系を中心に触ってきたのでJavascriptは趣味程度でしか分からないのでluaもJavascriptでもどっちも同レベルぐらいにしか書けませんが。)
そこで、luaとnjsの比較したいと思い調べてみたのですがlua,とnjsを同時に試すことが出来る環境が見つからなかったので自分でDockerで作ってみました。
上のgistの記事を参考にopenrestyのイメージをベースに環境を作りました。
nginxで動的モジュールをビルド/導入する際に注意する点がいくつかあり、Nginx本体と同じバージョンでビルドしかつ./configure
も同じにする必要があります。そして、load_module
は設定ファイルの早い段階で読み込むする必要があります。
FROM openresty/openresty:1.15.8.2-alpine-fat AS builder
# Our NCHAN version
ENV NGINX_VERSION 1.15.8
ENV NJS_VERSION 0.2.8
# For latest build deps, see https://github.com/nginxinc/docker-nginx/blob/master/mainline/alpine/Dockerfile
RUN apk add --no-cache --virtual .build-deps \
gcc \
libc-dev \
make \
openssl-dev \
pcre-dev \
zlib-dev \
linux-headers \
curl \
gnupg \
libxslt-dev \
gd-dev \
geoip-dev
# Download sources
RUN wget "http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" -O nginx.tar.gz && \
wget "https://github.com/nginx/njs/archive/${NJS_VERSION}.tar.gz" -O njs.tar.gz
# Reuse same cli arguments as the nginx:alpine image used to build
RUN CONFARGS=$(nginx -V 2>&1 | sed -n -e 's/^.*arguments: //p') \
tar -zxC /usr/local -f nginx.tar.gz && \
tar -xzvf "njs.tar.gz" -C /usr/local/nginx-${NGINX_VERSION} && \
NJSDIR="/usr/local/nginx-${NGINX_VERSION}/njs-${NJS_VERSION}/nginx" && \
cd /usr/local/nginx-${NGINX_VERSION} && \
./configure --with-compat $CONFARGS --add-dynamic-module=$NJSDIR && \
make modules && make install
FROM openresty/openresty:1.15.8.2-6-alpine
# Extract the dynamic module NCHAN from the builder image
COPY --from=builder /usr/local/nginx/modules/ngx_http_js_module.so /usr/local/openresty/nginx/modules/ngx_http_js_module.so
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]
# nginx.conf -- docker-openresty
#
# This file is installed to:
# `/usr/local/openresty/nginx/conf/nginx.conf`
# and is the file loaded by nginx at startup,
# unless the user specifies otherwise.
#
# It tracks the upstream OpenResty's `nginx.conf`, but removes the `server`
# section and adds this directive:
# `include /etc/nginx/conf.d/*.conf;`
#
# The `docker-openresty` file `nginx.vh.default.conf` is copied to
# `/etc/nginx/conf.d/default.conf`. It contains the `server section
# of the upstream `nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
#
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
load_module modules/ngx_http_js_module.so;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
# See Move default writable paths to a dedicated directory (#119)
# https://github.com/openresty/docker-openresty/issues/119
client_body_temp_path /var/run/openresty/nginx-client-body;
proxy_temp_path /var/run/openresty/nginx-proxy;
fastcgi_temp_path /var/run/openresty/nginx-fastcgi;
uwsgi_temp_path /var/run/openresty/nginx-uwsgi;
scgi_temp_path /var/run/openresty/nginx-scgi;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
# load_module modules/ngx_http_js_module.so;
js_include hello_world.js;
server {
# see: http://nginx.org/en/docs/http/server_names.html
server_name _;
location = /favicon.ico { access_log off; log_not_found off; }
location /hello {
default_type text/html;
content_by_lua '
ngx.say("<p>Hello World</p>")
';
}
location /js_hello {
js_content hello;
}
}
njsは設定ファイルにそのままJavascriptのコードを書くということが出来ないのでコードを別ファイルに切り出す必要があります。
function hello(r) {
r.return(200, "Hello njs!");
}
この状態ビルドしてdocker run
するときに自作アプリ用のnginx.confとJavascriptファイルをマウントして利用します。
# docker build
$ docker build -t njs .
# docker run
$ docker run -d --rm --name=my-njs -p 8082:80 \
-v $(pwd)/default.conf:/etc/nginx/conf.d/default.conf \
-v $(pwd)/hello_world.js:/usr/local/openresty/nginx/conf/hello_world.js \
-it njs
動作確認として立ち上げたDockerコンテナにアクセスしてみます。
$ curl 192.168.99.100:8082/hello
<p>Hello World</p>
$ curl 192.168.99.100:8082/js_hello
Hello njs!
エラーも出ずちゃんとレスポンスが返ってきました。
以上、Openrestyにnjsの動的モジュールを導入するためのTipsでした。
今回利用したファイル一覧はこちら。