経緯
みょんなことから、 Luaスクリプト でものを作りたくなったので、開発 + 実行環境を Docker で作ってみることにしました。
ついでと言っては何ですが、 Luaスクリプト のエコシステムとして以下のようなものがあることも判明。
- Luarocks:
- パッケージマネージャ。
- npm (Yarn) とか composer とか cargo とか go mod とか gem とかのイメージ。
- MoonScript:
- JavaScript における CoffeeScript (久々に見ました。構文が Ruby 寄りというかインデントでブロックを付けるタイプなのでこちらの方がイメージが近い気がしたので) といった AltJS のような立ち位置。
- 言ってしまえば AltLua のようなもの。
- 当然実行環境に移す前にトランスパイルが必要。バニラ Lua は拡張子
.lua
ですが MoonScript は.moon
。
- JavaScript における CoffeeScript (久々に見ました。構文が Ruby 寄りというかインデントでブロックを付けるタイプなのでこちらの方がイメージが近い気がしたので) といった AltJS のような立ち位置。
- 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
- Requests and Actions – Lapis Reference Manual
- MoonScriptしようや… #Lua – Qiita
- 糖衣がけのMoonScriptはいかが? – Ryusei’s Notes (a.k.a. M59のブログ)
- Lua web framework Lapis | 有限会社アテージ
- isucon4予選問題のLua(Lapis)バージョンを書いてみた – アルパカDiary Pro
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 のパスが通らない
- LuaRocksで環境ごとにパッケージをインストールしてパスを通す #LuaRocks – Qiita
- Docker+AlpineLinux3.4+Go1.7+Nginxでfreshを使って自動ビルドする開発環境を作る #nginx – Qiita
- OpenRestyでLuaを使った動的リバースプロキシを構築1 | らじねすブログ
- LuaRocks で Lua のモジュールを管理する #GitHub – Qiita
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’: