Your First OpenResty Program: Hello World
API7.ai
September 9, 2022
When we start learning a new development language, tutorials provide a simple hello world
case. So let's skip the installation first and see how to write this case in OpenResty:
$ resty -e "ngx.say('hello world')"
hello world
This should be the most straightforward hello world code you've ever seen, similar to Python:
$ python -c 'print("hello world")'
hello world
Behind this is a manifestation of OpenResty's philosophy. The code should be concise enough to let you get rid of the idea of "from entry to give up." This post will focus on the hello world case.
As we said in the What is the difference between OpenResty and NGINX post, OpenResty is based on NGINX
. So you may have a question: Why can't we see the shadow of NGINX here? Don't worry, let's add a line of code to see what is running behind resty:
$ resty -e "ngx.say('hello world'); ngx.sleep(10)" &
We added a ngx.sleep method so that the program will not exit after printing out the string hello world
. In this way, we have the opportunity to find out:
$ ps -ef | grep nginx
root 15944 6380 0 13:59 pts/6 00:00:00 grep --color=auto nginx
Finally the NGINX process appears! It seems that the resty
command essentially starts an NGINX service, so what is the resty
?
You may not have OpenResty installed on your machine, so next, let's go back to the installation steps we skipped at the beginning, and install OpenResty before continuing.
Installation
Like other open source software, we can install OpenResty in various ways, such as using the operating system's package manager, compiling from source code, or docker image. However, I recommend that you first use a package manager such as yum
, apt-get
, and brew
to install OpenResty. In this post, I will use the macOS as an example:
$ brew tap openresty/brewbrew install openresty
Using other operating systems is similar. First, add the OpenResty repository's URL to the package manager, and then use the package manager to install OpenResty. For more detailed steps, you can refer to the official documentation.
However, there are two problems behind this seemingly simple installation:
- Why do I not recommend using source code to install it?
- Why can't it be installed directly from the official repository of the operating system but need to set another repository first?
Please think about those two questions first.
Here I would like to add one more thing. I will put many "why" behind the appearance in this course. I hope you can think while learning new things. It doesn't matter whether the result is correct or not. Unfortunately, independent thinking is also scarce in the technical field. Due to the difference in each person's technical field and depth, teachers will inevitably have personal opinions and mistakes in knowledge in any course. We can gradually form our own technical system by asking a few more whys in the learning process and understanding it.
Many engineers enjoy building from source codes, and so did I many years ago. However, when using an open source project, I always hope that I can manually configure
and make
from the source code and modify some compilation parameters. I feel this is the best way to suit the environment of this machine and maximize its performance.
But this is not the case in reality. Every time I compile the source code, I encounter weird environmental problems, and I can only install it after stumbling. Now I understand that our original purpose is to use open source projects to solve business needs. We should not waste time and environment fighting, not to mention package managers and container technology. It is precisely to help us solve these problems.
Let's go back to the topic. Using OpenResty source code to install, not only are the steps cumbersome, you need to solve external dependencies such as PCRE
, OpenSSL
, etc., but you also need to patch the corresponding version of OpenSSL manually. Otherwise, there will be a lack of functionality when dealing with SSL sessions
. For example, Lua APIs such as ngx.sleep that cause yield
cannot be used. If you want to learn more about this part, you can refer to the official documentation for more detailed information.
OpenResty is maintaining those patches in the OpenSSL package script by itself. When OpenResty upgrades the OpenSSL
version, it must regenerate the corresponding patch and perform a complete regression testing.
Source0: https://www.openssl.org/source/openssl-%{version}.tar.gz
Patch0: https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-1.1.0d-sess_set_get_cb_yield.patch
Patch1: https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-1.1.0j-parallel_build_fix.patch
At the same time, we can take a look at the package script of OpenResty in CentOS to see if there are other hidden points:
BuildRequires: perl-File-Temp
BuildRequires: gcc, make, perl, systemtap-sdt-devel
BuildRequires: openresty-zlib-devel >= 1.2.11-3
BuildRequires: openresty-openssl-devel >= 1.1.0h-1
BuildRequires: openresty-pcre-devel >= 8.42-1
Requires: openresty-zlib >= 1.2.11-3
Requires: openresty-openssl >= 1.1.0h-1
Requires: openresty-pcre >= 8.42-1
As you can see here, OpenResty maintains its version of OpenSSL
and its own version of zlib
and PCRE
. However, the latter two adjusted the compilation parameters and did not preserve their patches.
So, considering these factors, I do not recommend compiling OpenResty from the source codes unless you already know the details.
It should be clear to you why the source installation is not recommended. When we answered the first question, we also answered the second question: why can't we install directly from the official package repositories of the operating system but need to set another repository first?
This is because the official repositories are unwilling to accept OpenSSL
, PCRE
, and zlib
packages maintained by third parties to prevent them from leading to confusion for other users who do not know which one to choose. On the other hand, OpenResty needs specified versions of OpenSSL
and PCRE
libraries to run normally, and the default versions of the system are relatively old.
OpenResty CLI
After installing OpenResty, the OpenResty CLI resty
is already installed by default. It is a Perl
script, and as we mentioned before, the OpenResty ecosystem tools are all written in Perl
, which is determined by the technical preference of the OpenResty author.
$ which resty
/usr/local/bin/resty
$ head -n 1 /usr/local/bin/resty
#!/usr/bin/env perl
The resty CLI is very powerful, and we can use resty -h
or read official documentation for a complete functionality list. Next, I'll introduce two exciting features.
$ resty --shdict='dogs 1m' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'
56
The example above shows an Nginx
configuration with the Lua
code, which accomplishes a shared memory dictionary setup and querying. The dogs 1m
is an Nginx
configuration that declares a shared memory space named dogs
with a size of 1m
. The shared memory is used as a dictionary in the Lua code.
Also, the --http-include
and --main-include
parameters are used to set up the NGINX
configuration file, so we could rewrite the above example as:
$ resty --http-conf 'lua_shared_dict dogs 1m;' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'
The standard debugging tools in the OpenResty world, such as gdb
, valgrind
, sysetmtap
, and Mozilla rr
can also be used with resty to facilitate normal development and testing. They have corresponded to different commands of resty
, so the internal implementation is straightforward, just an extra layer of command line calls. Let's take valgrind
as an example.
$ resty --valgrind -e "ngx.say('hello world'); "
ERROR: failed to run command "valgrind /usr/local/openresty/nginx/sbin/nginx -p /tmp/resty_rJeOWaYGIY/ -c conf/nginx.conf": No such file or directory
They are not only applicable to the OpenResty world but are also general tools for the server side, so let's learn them step by step.
More formal "hello world"
The first OpenResty program we wrote, in the beginning, used resty
command without the master
process and without listening on specific ports. Next, let's implement another hello world
program.
We need at least three steps to complete it.
- Create a working directory.
- Modify the
NGINX
configuration file to embedLua
code in it. - Start the
OpenResty
service.
Let's start by creating a working directory.
$ mkdir openresty-sample
$ cd openresty-sample
$ mkdir logs/ conf/
The following is a minimalist nginx.conf
with the OpenResty's content_by_lua
directive in the root directory, which embeds the ngx.say method.
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
content_by_lua '
ngx.say("hello, world")
';
}
}
}
Please make sure that openresty has been added to the PATH
environment first; then, start the OpenResty service:
$ openresty -p `pwd` -c conf/nginx.conf
If no errors occurred, the OpenResty service has been successfully started. We can access it by the cURL command to see the returned results.
$ curl -i 127.0.0.1:8080
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
hello, world
Congratulations! The formal Hello World
in OpenResty is complete!
Summary
Let's review what we learned today. First, we start the OpenResty installation and CLI with a simple line of "hello, world" code, and finally, we start the OpenResty process and run an actual backend program.
Among them, resty is a command-line tool that we will frequently use in the future. Therefore, the demo code in the course is run with it, rather than starting the OpenResty service in the background.
More importantly, many cultural and technical details are hidden behind OpenResty, and it is like an iceberg floating on the sea. Through this course, I hope to show you a more comprehensive OpenResty, not just its exposed API.