
Lua 常用於嵌入式、遊戲、Nginx/OpenResty 等高效能場景。寫 Lua 雖然輕巧,但遇到 bug 沒有好工具很痛苦。這篇教你用 VSCode 打造現代化 Lua 除錯環境,讓你能設斷點、單步執行、即時觀察變數,效率大提升!
本專案實際採用 VSCode + Docker + EmmyLua 進行 Lua 斷點除錯,以下是完整實戰流程與設定:
docker-compose.yml:定義 openresty 服務、埠號對應、volume 掛載conf/nginx.conf:Nginx 與 OpenResty 設定lua/myapp.lua:主要 Lua 業務邏輯與偵錯入口lua/.vscode/launch.json:VSCode 偵錯設定docker-compose.yml 需包含:
version: '3.8'
services:
openresty:
build: .
container_name: openresty-dev
ports:
- "8080:80" # HTTP
- "8081:443" # HTTPS
- "9966:9966" # EmmyLua Debugger (Lua 除錯)
volumes:
- ./conf/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro
- ./lua:/usr/local/openresty/nginx/lua
- ./logs:/usr/local/openresty/nginx/logs
- ./db/GeoLite2-City.mmdb:/usr/local/openresty/nginx/lua/GeoLite2-City.mmdb:ro
environment:
TZ: Asia/Taipei
restart: unless-stopped
8080:80:對外 HTTP 服務8081:443:對外 HTTPS 服務(如有設定 SSL)9966:9966:Lua 除錯(EmmyLua Debugger 連接埠)TZ: Asia/Taipei:設定容器時區,方便日誌對時restart: unless-stopped:自動重啟容器,除非手動停止以下為本專案用於 OpenResty + Lua 除錯的 Dockerfile 範例,已內建 lua-resty-maxminddb、EmmyLua Debugger、GeoLite2-City 資料庫等:
FROM openresty/openresty:alpine-fat
# 安裝必要套件與工具
RUN apk add --no-cache \
git \
build-base \
cmake \
libmaxminddb-dev \
perl \
libmaxminddb \
wget \
tar \
unzip \
luarocks
# 安裝 lua-resty-maxminddb
RUN luarocks install lua-resty-maxminddb
# 設定時區
ENV TZ=Asia/Taipei
# 建立資料夾結構
RUN mkdir -p /usr/local/openresty/nginx/lua \
&& mkdir -p /usr/local/openresty/nginx/logs \
&& mkdir -p /usr/local/openresty/nginx/db
# 下載最新 MaxMind GeoLite2-City 資料庫
RUN wget -O /tmp/GeoLite2-City.tar.gz "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=<YOUR_LICENSE_KEY>&suffix=tar.gz" \
&& tar -xzf /tmp/GeoLite2-City.tar.gz -C /tmp \
&& find /tmp -name "GeoLite2-City.mmdb" -exec cp {} /usr/local/openresty/nginx/db/ \; \
&& rm -rf /tmp/GeoLite2-City.tar.gz /tmp/GeoLite2-City_*
# === 下載並編譯 emmy_core.so ===
WORKDIR /tmp
RUN git clone https://github.com/EmmyLua/EmmyLuaDebugger.git \
&& cd EmmyLuaDebugger \
&& mkdir build && cd build \
&& cmake .. -DCMAKE_BUILD_TYPE=Release -DLUA_INCLUDE_DIR=/usr/local/openresty/luajit/include/luajit-2.1 \
&& make \
&& find . -name emmy_core.so -exec cp {} /usr/local/openresty/lualib/emmy_core.so \; \
&& cd / && rm -rf /tmp/EmmyLuaDebugger
# 設定 Lua 模組路徑
ENV LUA_PATH="/usr/local/openresty/lualib/?.lua;;"
ENV LUA_CPATH="/usr/local/openresty/lualib/?.so;;"
# 預設啟動
CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]
注意:
license_key=<YOUR_LICENSE_KEY>請至 MaxMind 官網 註冊帳號並取得專屬金鑰。- 此金鑰屬於個人授權,請勿公開於網路或版本控制系統。
- 若未填寫正確金鑰,GeoLite2-City 資料庫將無法下載。
在 lua/myapp.lua 最前面加上:
local dbg = require("emmy_core")
dbg.tcpListen("0.0.0.0", 9966) -- 讓容器內偵錯器監聽所有網卡
dbg.waitIDE() -- 等待 IDE 連線才繼續執行
dbg.breakHere() -- 進入斷點
在 lua/.vscode/launch.json 中加入:
{
"version": "0.2.0",
"configurations": [
{
"type": "emmylua_new",
"request": "attach",
"name": "Attach by process id",
"pid": 0,
"processName": "",
"captureLog": false,
"host": "localhost",
"port": 9966,
"cwd": "${workspaceFolder}/lua",
"ext": [".lua", "lua.txt", ".lua.bytes"]
}
]
}
host請設為localhost,因為我們已將 9966 埠號從容器映射到主機。
docker-compose restart openresty)。http://localhost:8080/),程式會自動停在斷點。以 lua/myapp.lua 為例,示範如何設置斷點與觀察變數:
local dbg = require("emmy_core")
dbg.tcpListen("0.0.0.0", 9966)
dbg.waitIDE()
dbg.breakHere()
local cjson = require 'cjson'
local geo = require 'resty.maxminddb'
geo.init("/usr/local/openresty/nginx/lua/GeoLite2-City.mmdb")
-- 假設這裡有一個函式要查詢 IP 位置
local function get_country(ip)
local res, err = geo.lookup(ip)
if not res then
ngx.log(ngx.ERR, "Geo lookup error: ", err)
return nil
end
return res
end
local ip = ngx.var.arg_ip or ngx.var.remote_addr
local country_info = get_country(ip)
ngx.say(cjson.encode(country_info))
只要在 myapp.lua 開頭插入偵錯程式碼,就能用 VSCode 斷點、單步追蹤每個變數!
接下來,需在 nginx.conf 中設定路由,讓 OpenResty 能將請求導向剛剛的 myapp.lua:
location /lua {
default_type 'text/plain';
content_by_lua_file /usr/local/openresty/nginx/lua/myapp.lua;
}
這樣設定後,當你訪問 http://localhost:8080/lua 時,Nginx 會將請求導向 myapp.lua 處理,並回應結果。
當用戶端(如瀏覽器或 curl)請求 http://localhost:8080/lua 時,Nginx 會將該請求交給 myapp.lua 處理,並將結果回傳給用戶端。你也可以依需求調整路由。
/usr/local/openresty/nginx/logs/error.lognginx.conf 設 error_log ... debug;ngx.log(ngx.ERR, "Debug info: ", cjson.encode(var))dbg.tcpListen("0.0.0.0", 9966),不是 localhost。docker-compose.yml 有沒有 9966:9966。host 設定為 localhost。/usr/local/openresty/nginx/logs/error.log。ngx.log(ngx.ERR, "debug info") 輔助。| 方法 | 指令/說明 |
|---|---|
| 進容器看日誌 | docker exec -it openresty-dev /bin/shtail -f /usr/local/openresty/nginx/logs/error.log |
| 直接看容器 log | docker logs -f openresty-dev |
| 掛本地目錄 | docker run -v /your/local/logs:/usr/local/openresty/nginx/logs ... openresty |
| 抓封包看流量 | sudo tcpdump -i docker0 port 8080 |
| VSCode Remote | 直接用 VSCode 編輯、debug 容器裡的檔案 |