Votre premier programme OpenResty : Hello World

API7.ai

September 9, 2022

OpenResty (NGINX + Lua)

Lorsque nous commençons à apprendre un nouveau langage de développement, les tutoriels fournissent généralement un cas simple de hello world. Alors, sautons d'abord l'installation et voyons comment écrire ce cas avec OpenResty :

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

Ce devrait être le code hello world le plus simple que vous ayez jamais vu, similaire à Python :

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

Derrière cela se cache une manifestation de la philosophie d'OpenResty. Le code doit être suffisamment concis pour vous éviter l'idée de "passer de l'entrée à l'abandon". Ce post se concentrera sur le cas de hello world.

Comme nous l'avons mentionné dans le post Quelle est la différence entre OpenResty et NGINX, OpenResty est basé sur NGINX. Vous pourriez donc vous demander : Pourquoi ne voyons-nous pas l'ombre de NGINX ici ? Ne vous inquiétez pas, ajoutons une ligne de code pour voir ce qui se cache derrière resty :

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

Nous avons ajouté une méthode ngx.sleep pour que le programme ne se termine pas après avoir affiché la chaîne hello world. Ainsi, nous avons l'opportunité de découvrir :

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

Enfin, le processus NGINX apparaît ! Il semble que la commande resty démarre essentiellement un service NGINX. Alors, qu'est-ce que resty ?

Vous n'avez peut-être pas OpenResty installé sur votre machine, alors revenons aux étapes d'installation que nous avons sauté au début et installons OpenResty avant de continuer.

Installation

Comme pour d'autres logiciels open source, nous pouvons installer OpenResty de différentes manières, comme utiliser le gestionnaire de paquets du système d'exploitation, compiler à partir du code source ou utiliser une image docker. Cependant, je vous recommande d'abord d'utiliser un gestionnaire de paquets comme yum, apt-get ou brew pour installer OpenResty. Dans ce post, je vais utiliser macOS comme exemple :

$ brew tap openresty/brewbrew install openresty

L'utilisation d'autres systèmes d'exploitation est similaire. D'abord, ajoutez l'URL du dépôt OpenResty au gestionnaire de paquets, puis utilisez le gestionnaire de paquets pour installer OpenResty. Pour des étapes plus détaillées, vous pouvez vous référer à la documentation officielle.

Cependant, derrière cette installation apparemment simple se cachent deux problèmes :

  1. Pourquoi ne recommanderais-je pas d'utiliser le code source pour l'installer ?
  2. Pourquoi ne peut-on pas l'installer directement depuis le dépôt officiel du système d'exploitation mais doit-on d'abord configurer un autre dépôt ?

Réfléchissez d'abord à ces deux questions.

Ici, j'aimerais ajouter une chose. Je vais poser de nombreux "pourquoi" derrière les apparences dans ce cours. J'espère que vous pourrez réfléchir tout en apprenant de nouvelles choses. Peu importe que le résultat soit correct ou non. Malheureusement, la pensée indépendante est également rare dans le domaine technique. En raison de la différence dans le domaine technique et la profondeur de chaque personne, les enseignants auront inévitablement des opinions personnelles et des erreurs dans les connaissances dans n'importe quel cours. Nous pouvons progressivement former notre propre système technique en posant quelques "pourquoi" supplémentaires dans le processus d'apprentissage et en le comprenant.

De nombreux ingénieurs aiment construire à partir des codes sources, et j'en faisais partie il y a de nombreuses années. Cependant, lors de l'utilisation d'un projet open source, j'espère toujours pouvoir configurer manuellement et make à partir du code source et modifier certains paramètres de compilation. Je pense que c'est la meilleure façon de s'adapter à l'environnement de cette machine et de maximiser ses performances.

Mais ce n'est pas le cas dans la réalité. Chaque fois que je compile le code source, je rencontre des problèmes environnementaux étranges, et je ne peux l'installer qu'après avoir trébuché. Maintenant, je comprends que notre objectif initial est d'utiliser des projets open source pour répondre aux besoins commerciaux. Nous ne devrions pas perdre de temps à lutter contre l'environnement, sans parler des gestionnaires de paquets et de la technologie des conteneurs. C'est précisément pour nous aider à résoudre ces problèmes.

Revenons au sujet. Utiliser le code source d'OpenResty pour l'installation est non seulement fastidieux, mais vous devez également résoudre des dépendances externes comme PCRE, OpenSSL, etc., et vous devez également patcher manuellement la version correspondante d'OpenSSL. Sinon, il y aura un manque de fonctionnalités lors de la gestion des sessions SSL. Par exemple, les API Lua comme ngx.sleep qui provoquent un yield ne peuvent pas être utilisées. Si vous souhaitez en savoir plus sur cette partie, vous pouvez vous référer à la documentation officielle pour plus d'informations détaillées.

OpenResty maintient ces correctifs dans le script de package OpenSSL lui-même. Lorsqu'OpenResty met à jour la version d'OpenSSL, il doit régénérer le correctif correspondant et effectuer un test de régression complet.

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

En même temps, nous pouvons jeter un œil au script de package d'OpenResty dans CentOS pour voir s'il y a d'autres points cachés :

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

Comme vous pouvez le voir ici, OpenResty maintient sa propre version d'OpenSSL ainsi que ses propres versions de zlib et PCRE. Cependant, les deux derniers ont ajusté les paramètres de compilation et n'ont pas conservé leurs correctifs.

Ainsi, compte tenu de ces facteurs, je ne recommande pas de compiler OpenResty à partir des codes sources, sauf si vous connaissez déjà les détails.

Il devrait être clair pour vous pourquoi l'installation à partir des sources n'est pas recommandée. En répondant à la première question, nous avons également répondu à la deuxième question : pourquoi ne pouvons-nous pas installer directement depuis les dépôts officiels du système d'exploitation mais devons-nous d'abord configurer un autre dépôt ?

C'est parce que les dépôts officiels ne veulent pas accepter les packages OpenSSL, PCRE et zlib maintenus par des tiers pour éviter de causer de la confusion pour les autres utilisateurs qui ne savent pas lequel choisir. D'autre part, OpenResty a besoin de versions spécifiques des bibliothèques OpenSSL et PCRE pour fonctionner normalement, et les versions par défaut du système sont relativement anciennes.

CLI OpenResty

Après avoir installé OpenResty, la CLI OpenResty resty est déjà installée par défaut. C'est un script Perl, et comme nous l'avons mentionné précédemment, les outils de l'écosystème OpenResty sont tous écrits en Perl, ce qui est déterminé par la préférence technique de l'auteur d'OpenResty.

$ which resty
/usr/local/bin/resty

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

La CLI resty est très puissante, et nous pouvons utiliser resty -h ou lire la documentation officielle pour une liste complète des fonctionnalités. Ensuite, je vais présenter deux fonctionnalités intéressantes.

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

56

L'exemple ci-dessus montre une configuration Nginx avec le code Lua, qui accomplit la configuration et l'interrogation d'un dictionnaire de mémoire partagée. Le dogs 1m est une configuration Nginx qui déclare un espace de mémoire partagée nommé dogs avec une taille de 1m. La mémoire partagée est utilisée comme un dictionnaire dans le code Lua.

De plus, les paramètres --http-include et --main-include sont utilisés pour configurer le fichier de configuration NGINX, donc nous pourrions réécrire l'exemple ci-dessus comme suit :

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

Les outils de débogage standard dans le monde OpenResty, comme gdb, valgrind, sysetmtap et Mozilla rr, peuvent également être utilisés avec resty pour faciliter le développement et les tests normaux. Ils correspondent à différentes commandes de resty, donc l'implémentation interne est simple, juste une couche supplémentaire d'appels de ligne de commande. Prenons valgrind comme exemple.

$ 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

Ils ne sont pas seulement applicables au monde OpenResty, mais sont également des outils généraux pour le côté serveur, alors apprenons-les étape par étape.

Un "hello world" plus formel

Le premier programme OpenResty que nous avons écrit au début utilisait la commande resty sans le processus master et sans écouter sur des ports spécifiques. Ensuite, implémentons un autre programme hello world.

Nous avons besoin d'au moins trois étapes pour le compléter.

  1. Créer un répertoire de travail.
  2. Modifier le fichier de configuration NGINX pour y intégrer le code Lua.
  3. Démarrer le service OpenResty.

Commençons par créer un répertoire de travail.

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

Voici un nginx.conf minimaliste avec la directive content_by_lua d'OpenResty dans le répertoire racine, qui intègre la méthode ngx.say.

events {
    worker_connections 1024;
}

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

Assurez-vous d'abord qu'openresty a été ajouté à la variable d'environnement PATH ; puis, démarrez le service OpenResty :

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

Si aucune erreur ne s'est produite, le service OpenResty a été démarré avec succès. Nous pouvons y accéder avec la commande cURL pour voir les résultats retournés.

$ 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

Félicitations ! Le Hello World formel dans OpenResty est terminé !

Résumé

Passons en revue ce que nous avons appris aujourd'hui. D'abord, nous avons démarré l'installation d'OpenResty et la CLI avec une simple ligne de code "hello, world", et enfin, nous avons démarré le processus OpenResty et exécuté un véritable programme backend.

Parmi eux, resty est un outil en ligne de commande que nous utiliserons fréquemment à l'avenir. Par conséquent, le code de démonstration dans le cours est exécuté avec lui, plutôt que de démarrer le service OpenResty en arrière-plan.

Plus important encore, de nombreux détails culturels et techniques sont cachés derrière OpenResty, et c'est comme un iceberg flottant sur la mer. À travers ce cours, j'espère vous montrer un OpenResty plus complet, pas seulement ses API exposées.