Lua(とOpenResty)に入門した

きっかけ

最近、小学生を中心にプログラミングを教える機会があり、その中でRoblox Studioによるゲーム開発に取り組んでいる子がいました。
Roblox Studio はLua言語でゲームを作成するため、質問に答える際などにLuaがある程度扱えないと困るということで触ってみました。

僕は新しい言語を学ぶ際によくポーカーの役判定ロジックを作成するので、今回もそうしています。
Luaを用いてAPIを作成する方法を調べたところ、OpenResty というフレームワークでできそうだったため、OpenRestyを利用しています。

先に感想

  • LuaRubyJavaScriptの中間のような印象。書き味はRubyっぽい。一方でいわゆるclassはなく、すべてテーブルで作る点はJavaScriptっぽい。
  • 正直Tableの使い方はまだよくわかってない。
  • Nginxを拡張する選択肢としてのOpenRestyを知れたのは良かった。

成果物

github.com 勢いで作ったので汚いのは許してください。

以下実装周り

環境構築

Dockerfile

FROM openresty/openresty:alpine

COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY lua/ /usr/local/openresty/nginx/lua/

EXPOSE 8080

CMD ["openresty", "-g", "daemon off;"]

OpenRestyのイメージを利用すればOK。ただしluarocksというLuaのパッケージマネージャーは含まれていないため、別途ライブラリが必要な場合は openresty:alpine-fat イメージを利用します。後述の単体テストでは openresty:alpine-fat を利用しています。

docker-compose.yaml

services:
  openresty:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8082:8080"
    volumes:
      - ./nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf
      - ./lua/:/usr/local/openresty/nginx/lua/

8082番なのは、その時他のアプリケーションで8080, 8081が埋まっていたからというだけの理由です。

実装

nginx.conf

worker_processes 1;

events {
    worker_connections 1024;
}

http {
    include mime.types;
    default_type application/octet-stream;

    keepalive_timeout 15;
    
    # 読み込むLuaファイルのパス
    lua_package_path '/usr/local/openresty/nginx/lua/?.lua;;';

    server {
        listen 8080;
        server_name localhost;

        # キャッシュを無効にすることで、毎回リクエストを処理する(実質ホットロード)
        lua_code_cache off;

        # API
        location /api/v1/draw {
            content_by_lua_file /usr/local/openresty/nginx/lua/handler/draw.lua;
        }
    }
}

最初のスクリプト

local function handle_request()
  ngx.say("Hello World!")
end

handle_request()

実行

docker-compose up -d openresty
curl localhost:8082/api/v1/draw

ユニットテスト

Luaユニットテストbustedというライブラリがデファクトっぽかったのでそちらを利用しました。

github.com

bustedを利用するにはluarocksでインストールする必要がありますが、 openresty/openresty:alpine イメージにluarocksは含まれていません。個別にインストールしようとしてもうまくいかなかったため、dockerhubを参考に openresty/openresty:alpine-fat を利用しました。

DockerfileTest

# luarocksを使いたいためfatを指定
# https://hub.docker.com/r/openresty/openresty#luarocks
FROM openresty/openresty:alpine-fat

RUN /usr/local/openresty/luajit/bin/luarocks install busted

COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf

COPY lua/ /usr/local/openresty/nginx/lua/

WORKDIR /usr/local/openresty/nginx/lua

CMD ["busted", "."]

docker-compose.yaml

services:
  test:
    build:
      context: .
      dockerfile: DockerfileTest
    volumes:
      - ./lua:/usr/local/openresty/nginx/lua
    command: ["busted", "."]

実行

docker-compose up -d test