Intro to Lua and Openresty, Part 4: Using Envvars

Posted on March 4, 2017

In Part 3 of this series, we used Lua and Openresty to write a JSON message (extracted from HTTP POST) to a table in Postgres. This next post will demonstrate how to access and use environment variables.

For our example, we will use envvars to tell our lua app how to connect to the Postgres database. To do this, we will use the os.getenv() function and the env nginx directive.

Here is an example

If you are following along in the code, we are here.

worker_processes  1;
env DB_HOST;
env DB_USER;
env DB_PASS;
env DB_NAME;
error_log error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen        8000;
        charset       utf-8;
        charset_types application/json;
        default_type  application/json;
        location / {
            content_by_lua '
                local cjson = require "cjson"
                local pgmoon = require("pgmoon")
                local pg = pgmoon.new({
                  host     = os.getenv("DB_HOST"),
                  port     = "5432",
                  user     = os.getenv("DB_USER"),
                  password = os.getenv("DB_PASS"),
                  database = os.getenv("DB_NAME")
                })
                assert(pg:connect())
                local encode_json = require("pgmoon.json").encode_json
                local get, post, files = require "resty.reqargs"()
                assert(pg:query("INSERT INTO posts (data) VALUES(" .. encode_json(post) .. ");"))
                pg:keepalive()
                pg = nil   
                ngx.status  = ngx.HTTP_OK
                ngx.say(cjson.encode({status = "saved", msg=post}))
                return ngx.exit(ngx.HTTP_OK)
            ';
        }
    }
}   

The lua application will now use the DB_HOST, DB_USER, DB_PASS, and DB_NAME for the various pieces of info for the connection to Postgres. In other words, when we run nginx, we will need to set those envvars. We have been running our nginx lua app in a docker container, so defining these envvars is very simple:

FROM openresty/openresty:alpine-fat

EXPOSE 8000
ENV DB_HOST 127.0.0.1
ENV DB_USER postgres
ENV DB_PASS password
ENV DB_NAME lua-app
RUN /usr/local/openresty/luajit/bin/luarocks install pgmoon
RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-reqargs
ADD nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' > /etc/nsswitch.conf

Build / Test / Run

Use make build to create the Docker images.

Run:

ᐅ make run
docker run -d --name db  --net host -p 127.0.0.1:5342:5432 db:5
34f3178df5f6e47bf87ef95016038561ed43f318bc38287ca8eb8b9764143f16
docker run -d --name app --net host -p 127.0.0.1:8000:8000 app:5
61ef0e0d497c1a443d534a873f54c80debe3ddca1937d2773b07ccd605853e69

Test:

ᐅ curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz"}' localhost:8000/
{"status":"saved","msg":{"password":"xyz","username":"xyz"}}

Then teardown the running containers with make clean.

Stand-Alone Scripts

BTW, we can demonstrate this use of os.getenv() in a stand-alone script as well:

local host = os.getenv("DB_HOST")
print(host)

Run it…

ᐅ docker run -it --rm --entrypoint /bin/sh -v `pwd`/app:/src openresty/openresty:alpine
/ # /usr/local/openresty/luajit/bin/luajit /src/worker.lua
nil
/ # DB_HOST=foobar /usr/local/openresty/luajit/bin/luajit /src/worker.lua
foobar

Continue on to Part 5, Redis