Tu Primer Programa en OpenResty: Hola Mundo

API7.ai

September 9, 2022

OpenResty (NGINX + Lua)

Cuando comenzamos a aprender un nuevo lenguaje de desarrollo, los tutoriales proporcionan un caso simple de hello world. Así que saltemos la instalación por ahora y veamos cómo escribir este caso en OpenResty:

$ resty -e "ngx.say('hello world')"
hello world

Este debería ser el código de hello world más directo que hayas visto, similar a Python:

$ python -c 'print("hello world")'
hello world

Detrás de esto hay una manifestación de la filosofía de OpenResty. El código debe ser lo suficientemente conciso para que te deshagas de la idea de "de la entrada al abandono". Este post se centrará en el caso de hello world.

Como mencionamos en el post ¿Cuál es la diferencia entre OpenResty y NGINX?, OpenResty está basado en NGINX. Entonces, podrías tener una pregunta: ¿Por qué no vemos la sombra de NGINX aquí? No te preocupes, agreguemos una línea de código para ver qué está corriendo detrás de resty:

$ resty -e "ngx.say('hello world'); ngx.sleep(10)" &

Agregamos un método ngx.sleep para que el programa no salga después de imprimir la cadena hello world. De esta manera, tenemos la oportunidad de descubrir:

$ ps -ef | grep nginx
root     15944  6380  0 13:59 pts/6    00:00:00 grep --color=auto nginx

¡Finalmente aparece el proceso de NGINX! Parece que el comando resty esencialmente inicia un servicio NGINX, entonces, ¿qué es resty?

Es posible que no tengas OpenResty instalado en tu máquina, así que a continuación, volvamos a los pasos de instalación que omitimos al principio e instalemos OpenResty antes de continuar.

Instalación

Como otros software de código abierto, podemos instalar OpenResty de varias maneras, como usar el gestor de paquetes del sistema operativo, compilar desde el código fuente o usar una imagen de docker. Sin embargo, recomiendo que primero uses un gestor de paquetes como yum, apt-get y brew para instalar OpenResty. En este post, usaré macOS como ejemplo:

$ brew tap openresty/brewbrew install openresty

Usar otros sistemas operativos es similar. Primero, agrega la URL del repositorio de OpenResty al gestor de paquetes y luego usa el gestor de paquetes para instalar OpenResty. Para pasos más detallados, puedes consultar la documentación oficial.

Sin embargo, hay dos problemas detrás de esta instalación aparentemente simple:

  1. ¿Por qué no recomiendo usar el código fuente para instalarlo?
  2. ¿Por qué no se puede instalar directamente desde el repositorio oficial del sistema operativo, sino que se necesita configurar otro repositorio primero?

Por favor, piensa en esas dos preguntas primero.

Aquí me gustaría agregar una cosa más. Pondré muchos "por qué" detrás de la apariencia en este curso. Espero que puedas pensar mientras aprendes cosas nuevas. No importa si el resultado es correcto o no. Desafortunadamente, el pensamiento independiente también es escaso en el campo técnico. Debido a la diferencia en el campo técnico y la profundidad de cada persona, los profesores inevitablemente tendrán opiniones personales y errores en el conocimiento en cualquier curso. Podemos formar gradualmente nuestro propio sistema técnico haciendo algunas preguntas más en el proceso de aprendizaje y entendiéndolo.

Muchos ingenieros disfrutan construyendo desde el código fuente, y yo también lo hice hace muchos años. Sin embargo, al usar un proyecto de código abierto, siempre espero poder configurar y compilar manualmente desde el código fuente y modificar algunos parámetros de compilación. Siento que esta es la mejor manera de adaptarse al entorno de esta máquina y maximizar su rendimiento.

Pero este no es el caso en la realidad. Cada vez que compilo el código fuente, encuentro problemas ambientales extraños y solo puedo instalarlo después de tropezar. Ahora entiendo que nuestro propósito original es usar proyectos de código abierto para resolver necesidades comerciales. No deberíamos perder tiempo y ambiente luchando, sin mencionar los gestores de paquetes y la tecnología de contenedores. Es precisamente para ayudarnos a resolver estos problemas.

Volvamos al tema. Usar el código fuente de OpenResty para instalar no solo es engorroso, necesitas resolver dependencias externas como PCRE, OpenSSL, etc., sino que también necesitas parchear manualmente la versión correspondiente de OpenSSL. De lo contrario, habrá una falta de funcionalidad al manejar sesiones SSL. Por ejemplo, las APIs de Lua como ngx.sleep que causan yield no se pueden usar. Si deseas aprender más sobre esta parte, puedes consultar la documentación oficial para obtener información más detallada.

OpenResty está manteniendo esos parches en el script de paquete de OpenSSL por sí mismo. Cuando OpenResty actualiza la versión de OpenSSL, debe regenerar el parche correspondiente y realizar una prueba de regresión completa.

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

Al mismo tiempo, podemos echar un vistazo al script de paquete de OpenResty en CentOS para ver si hay otros puntos ocultos:

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

Como puedes ver aquí, OpenResty mantiene su versión de OpenSSL y su propia versión de zlib y PCRE. Sin embargo, los dos últimos ajustaron los parámetros de compilación y no conservaron sus parches.

Por lo tanto, considerando estos factores, no recomiendo compilar OpenResty desde el código fuente a menos que ya conozcas los detalles.

Debería quedar claro por qué no se recomienda la instalación desde el código fuente. Cuando respondimos la primera pregunta, también respondimos la segunda pregunta: ¿por qué no se puede instalar directamente desde los repositorios oficiales de paquetes del sistema operativo, sino que se necesita configurar otro repositorio primero?

Esto se debe a que los repositorios oficiales no están dispuestos a aceptar paquetes de OpenSSL, PCRE y zlib mantenidos por terceros para evitar que lleven a confusión para otros usuarios que no saben cuál elegir. Por otro lado, OpenResty necesita versiones específicas de las bibliotecas OpenSSL y PCRE para funcionar normalmente, y las versiones predeterminadas del sistema son relativamente antiguas.

CLI de OpenResty

Después de instalar OpenResty, la CLI de OpenResty resty ya está instalada por defecto. Es un script de Perl, y como mencionamos antes, las herramientas del ecosistema de OpenResty están todas escritas en Perl, lo cual está determinado por la preferencia técnica del autor de OpenResty.

$ which resty
/usr/local/bin/resty

$ head -n 1 /usr/local/bin/resty
#!/usr/bin/env perl

La CLI de resty es muy poderosa, y podemos usar resty -h o leer la documentación oficial para obtener una lista completa de funcionalidades. A continuación, presentaré dos características interesantes.

$ resty --shdict='dogs 1m' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'

56

El ejemplo anterior muestra una configuración de Nginx con el código Lua, que logra la configuración y consulta de un diccionario de memoria compartida. dogs 1m es una configuración de Nginx que declara un espacio de memoria compartida llamado dogs con un tamaño de 1m. La memoria compartida se usa como un diccionario en el código Lua.

Además, los parámetros --http-include y --main-include se usan para configurar el archivo de configuración de NGINX, por lo que podríamos reescribir el ejemplo anterior como:

$ resty --http-conf 'lua_shared_dict dogs 1m;' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'

Las herramientas de depuración estándar en el mundo de OpenResty, como gdb, valgrind, sysetmtap y Mozilla rr, también se pueden usar con resty para facilitar el desarrollo y las pruebas normales. Tienen correspondencia con diferentes comandos de resty, por lo que la implementación interna es sencilla, solo una capa adicional de llamadas de línea de comandos. Tomemos valgrind como ejemplo.

$ 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

No solo son aplicables al mundo de OpenResty, sino que también son herramientas generales para el lado del servidor, así que aprendámoslas paso a paso.

Un "hello world" más formal

El primer programa de OpenResty que escribimos, al principio, usó el comando resty sin el proceso master y sin escuchar en puertos específicos. A continuación, implementemos otro programa hello world.

Necesitamos al menos tres pasos para completarlo.

  1. Crear un directorio de trabajo.
  2. Modificar el archivo de configuración de NGINX para incrustar el código Lua en él.
  3. Iniciar el servicio de OpenResty.

Comencemos creando un directorio de trabajo.

$ mkdir openresty-sample
$ cd openresty-sample
$ mkdir logs/ conf/

El siguiente es un nginx.conf minimalista con la directiva content_by_lua de OpenResty en el directorio raíz, que incrusta el método ngx.say.

events {
    worker_connections 1024;
}

http {
    server {
        listen 8080;
        location / {
            content_by_lua '
                ngx.say("hello, world")
            ';
        }
    }
}

Asegúrate de que openresty se haya agregado a la variable de entorno PATH primero; luego, inicia el servicio de OpenResty:

$ openresty -p `pwd` -c conf/nginx.conf

Si no ocurrieron errores, el servicio de OpenResty se ha iniciado correctamente. Podemos acceder a él mediante el comando cURL para ver los resultados devueltos.

$ 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

¡Felicidades! ¡El Hello World formal en OpenResty está completo!

Resumen

Revisemos lo que aprendimos hoy. Primero, comenzamos la instalación de OpenResty y la CLI con una simple línea de código "hello, world", y finalmente iniciamos el proceso de OpenResty y ejecutamos un programa backend real.

Entre ellos, resty es una herramienta de línea de comandos que usaremos con frecuencia en el futuro. Por lo tanto, el código de demostración en el curso se ejecuta con él, en lugar de iniciar el servicio de OpenResty en segundo plano.

Más importante aún, muchos detalles culturales y técnicos están ocultos detrás de OpenResty, y es como un iceberg flotando en el mar. A través de este curso, espero mostrarte un OpenResty más completo, no solo su API expuesta.