Docker の Ubuntu 上に Lua + Luarocks + MoonScript + Lapis (OpenResty) の環境を構築する

経緯

みょんなことから、 Luaスクリプト でものを作りたくなったので、開発 + 実行環境を Docker で作ってみることにしました。

ついでと言っては何ですが、 Luaスクリプト のエコシステムとして以下のようなものがあることも判明。

  • Luarocks:
    • パッケージマネージャ。
    • npm (Yarn) とか composer とか cargo とか go mod とか gem とかのイメージ。
  • MoonScript:
    • JavaScript における CoffeeScript (久々に見ました。構文が Ruby 寄りというかインデントでブロックを付けるタイプなのでこちらの方がイメージが近い気がしたので) といった AltJS のような立ち位置。
      • 言ってしまえば AltLua のようなもの。
    • 当然実行環境に移す前にトランスパイルが必要。バニラ Lua は拡張子 .lua ですが MoonScript は .moon
  • Lapis:
    • Lua の Webアプリケーション用フレームワーク。
  • etlua:
    • テンプレートエンジン。

……パッケージマネージャとか、糖衣構文な拡張言語があるとか、何だか2010年代の JavaScript 界隈のような雰囲気がします。

ついでにアプリケーションフレームワークでプロジェクトの初期生成が行えたり、テンプレートエンジンもありますし。

また、アプリケーションサーバとしては OpenResty (Nginx に LuaJIT ( Lua の JITコンパイラ) やライブラリ等を追加したプラットフォーム) で稼働させます。

成果物

早速ですができあがったものを。

.env

# Lapis
# PATH
SRC_DIR=/opt
OPENRESTY_PREFIX=/opt/openresty
# Version
OPENRESTY_VERSION=1.19.9.2
LAPIS_VERSION=1.16.0
# Port
LAPIS_HOST_PORT=15415
LAPIS_SERVER_PORT=8080

各種パラメータ。 OpenResty のインストールパスや OpenResty, Lapis のバージョン、 Lapis の待ち受けポートの指定です。

compose.yml

services:
  lapis:
    build:
      context: ./
      dockerfile: Dockerfile
      args:
        SRC_DIR: $SRC_DIR
        OPENRESTY_PREFIX: $OPENRESTY_PREFIX
        OPENRESTY_VERSION: $OPENRESTY_VERSION
        LAPIS_VERSION: $LAPIS_VERSION
    labels:
      f.genesis.rock: "Apollo 15"
    volumes:
      - ./entrypoint:/entrypoint
      - ./workspace/app.moon:/workspace/app.moon
      - ./workspace/views:/workspace/views
    tty: true
    ports:
      - "$LAPIS_HOST_PORT:$LAPIS_SERVER_PORT"
    entrypoint: bash -c "bash /entrypoint/entrypoint.sh && /bin/bash"

Docker Compose 用 YAMLファイル。

Dockerfile.env のパラメータを渡したり、エントリポイントを実行したり。

ボリュームは Lapis のデフォルトでは app.lua が実行されるスクリプトになるので、 MoonScript の app.moon とテンプレートエンジンの配置場所である viewディレクトリ をマウントしています。

lapis new で Lapis の初期設定を行うと Openresty の設定ファイル等諸々のファイルが生えるのですが、それらも含めてボリュームマウントしてしまうと実行環境が重くなってしまったのであえて最小限のファイルに絞っています。

Dockerfile

FROM ubuntu:latest

ARG SRC_DIR
ARG OPENRESTY_PREFIX
ARG OPENRESTY_VERSION
ARG LAPIS_VERSION

# apk
RUN apt-get -qq update && apt-get -qqy install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make curl git-core luarocks libz-dev iproute2
# OpenResty
RUN cd ${SRC_DIR} && curl -LOs https://openresty.org/download/openresty-${OPENRESTY_VERSION}.tar.gz \
    && tar xzf openresty-${OPENRESTY_VERSION}.tar.gz && cd openresty-${OPENRESTY_VERSION} \
    && ./configure --prefix=${OPENRESTY_PREFIX} \
    --with-luajit \
    --with-http_realip_module \
    --with-http_stub_status_module \
    && make && make install && rm -rf openresty-${OPENRESTY_VERSION}*
# MoonScript
RUN luarocks install moonscript
# Lapis
RUN luarocks install lapis-console

# Workdir
WORKDIR ${OPENRESTY_PREFIX}/nginx/conf

# env path
ENV LAPIS_OPENRESTY ${OPENRESTY_PREFIX}/nginx/sbin/nginx

# port
EXPOSE 8080
EXPOSE 80

# Nginx
RUN mv nginx.conf nginx.conf.bk \
 && mv mime.types mime.types.bk

# Setup sample lapis project.
RUN mkdir /workspace

ベースは以下のリポジトリのものを使用しています。

そこに諸々調整を加えた結果が今回の一式となります。

環境としては冒頭の通り、 Lua (指定なしだと 5.1 が入る) をベースに Luarocks, MoonScript, OpenResty, Lapis を一通りインストールしています。

※ただし挙動的に LuaRocks で追加インストールしたパッケージが認識されていなさそう(コマンド自体は正常に完了する)なので、パス指定等で抜けている設定があるのかもしれません。今回は時間がなかったので追加パッケージがなくてもできる方法で先に進んでしまいましたが……。

entrypoint/entrypoint.sh

#!/bin/bash

cd /workspace
lapis new
moonc app.moon
moonc -w . &
lapis server production &

エントリポイント。行っていることは先述した lapis new のプロジェクトの初期化と、マウントした app.moon のトランスパイル (初回一回)。

その後は .moon ファイルをホットリロード的に自動トランスパイルするように moonc -w . & でバックグラウンド実行させつつ lapis server production & で Lapis から実行環境を起動しています。

余談

名前は YAMLファイル のラベルにあるように「ジェネシス・ロック (アポロ15号の探査で持ち帰った月の鉱物サンプル)」より。月(満月→十五夜)とアポロ15号より F

Lua がポルトガル語で月で意味し、それに付随して MoonScript 、またそこから鉱石関係なのか LuaRocks (Rock: 岩) や Lapis (ラテン語の石) といった「月」と「石」に関連する単語が多かったので「月の石」ということで採用しました。

何気にホスト側の待ち受けポート番号の 15415 もジェネシスロックのサンプル番号からです。

参考

LuaRocks

OpenResty

Lapis

Moonscript

Ubuntu

ベース

libpcre3-dev

zlib

Nginx

mime.types
include

Docker 周りの Tips

Docker のビルドキャッシュ

docker builder prune

Linux コマンド

netstat, ss

apt-get install iproute2

find

末尾に追記


Alpine (上手く行かなかったので没)

ベース

OpenResty

Alpine

ERROR: failed to run command: sh ./configure

ERROR: failed to run command: sh ./configure

Nginx

./configure: error: the HTTP gzip module requires the zlib library. 48.11 You can either disable the module by using –without-http_gzip_module 48.11 option, or install the zlib library into the system, or build the zlib library 48.11 statically from the source with nginx by using –with-zlib=option.

zlib1g-dev
openresty file doesn’t exist `nginx.conf’

openresty file doesn’t exist `nginx.conf’

LuaRocks

LuaRocks のパスが通らない
env: ‘lua’: no such file or directory

env: ‘lua’: no such file or directory

‘luarocks.core.cfg’ not found:

‘luarocks.core.cfg’ not found:

nginx: [error] init_by_lua error: error loading module ‘lpeg’ from file ‘/usr/local/lib/lua/5.4/lpeg.so’:

nginx: [error] init_by_lua error: error loading module ‘lpeg’ from file ‘/usr/local/lib/lua/5.4/lpeg.so’:

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。