Création de modules dynamiques pour Nginx

image


Récemment, nous avons construit un module dynamique pour Nginx, et quand tout était prêt, il s'est avéré que notre module n'était pas compatible avec Nginx, qui était déjà installé sur le serveur. Nous n'avons pas pu trouver de solution toute faite au problème et nous avons commencé à le combattre par nous-mêmes. Nous avons passé beaucoup de temps, mais nous avons acquis une nouvelle expérience et, surtout, une solution de travail. Que je voudrais partager.


Commençons par une description du processus d'assemblage de module dynamique en utilisant l'exemple https://github.com/vozlt/nginx-module-vts . Et puis nous montrerons quelle erreur se produit et que faire avec.


Données d'entrée:
OS Debian 9
Nginx v1.10.3 du référentiel Debian standard. Sortie nginx -V :


 nginx version: nginx/1.10.3 built with OpenSSL 1.1.0k 28 May 2019 (running with OpenSSL 1.1.1c 28 May 2019) TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/ nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path =/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module - -with-http_stub_status_module --with-http_realip_mod ule --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module= dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-auth-pam --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-dav-ext-module --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-echo --add-dynamic-module=/build/nginx-DhOtPd/nginx-1.10.3/debian/modules/nginx-upstream-fair --add-dynamic-module=/build/nginx-DhOtPd/nginx -1.10.3/debian/modules/ngx_http_substitutions_filter_module 

La sortie de cette commande contient les informations nécessaires à l'assemblage des modules dynamiques, à savoir tout ce qui est écrit après configure arguments: et avant le premier - --add-dynamic-module , c'est-à-dire:


 --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/ nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path =/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_mod ule --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module= dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module 

Nous procédons donc à l'assemblage du module:


  • Pour l'assemblage, il est pratique d'utiliser un conteneur docker afin de ne pas encombrer le système principal, de prendre l'image debian: 9 comme base, pour la commodité de copier le module fini du conteneur, vous pouvez spécifier le volume. La commande pour démarrer le conteneur dans ce cas ressemblera à ceci:

 docker run --rm -it -v /tmp/nginx_module:/nginx_module debian:9 bash 

  • Après avoir démarré le conteneur, installez les packages nécessaires. Veuillez noter que les packages sont sélectionnés en fonction de la sortie de la commande nginx -V, vous n'aurez donc pas besoin de certaines bibliothèques. Dans tous les cas, le script configure vous avertira de l'absence de dépendances:

 apt update apt install git make gcc autoconf wget libpcre3-dev libpcre++-dev zlib1g-dev libxml2-dev libxslt-dev libgd-dev libgeoip-dev 

Le paquet libssl-dev est absent de cette liste, car le nginx installé sur le serveur est construit avec la version 1.1.0k d'OpenSSL, et au moment de la rédaction, lors de l'installation du paquet libssl-dev à partir du référentiel, la version d'OpenSSL était déjà 1.1.0l. Par conséquent, le code source OpenSSL pour la version correcte doit être téléchargé séparément.



 cd /usr/local/src/ wget http://nginx.org/download/nginx-1.10.3.tar.gz wget https://www.openssl.org/source/old/1.1.0/openssl-1.1.0k.tar.gz git clone git://github.com/vozlt/nginx-module-vts.git tar xvfz nginx-1.10.3.tar.gz tar xzvf openssl-1.1.0k.tar.gz cd nginx-1.10.3 

  • Vous êtes maintenant prêt à exécuter le script de configuration. En tant que paramètres de script, nous indiquons tous les paramètres de la sortie de la commande nginx -V, dont j'ai parlé au début de l'article. Nous ajoutons également le paramètre --add-dynamic-module pour construire le module nginx-module-vts et spécifions le chemin d'accès au répertoire avec les fichiers source OpenSSL via le paramètre --with-openssl. La commande finale ressemblera à ceci:

 ./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-DhOtPd/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --with-openssl=../openssl-1.1.0k/ --add-dynamic-module=../nginx-module-vts/ 

  • Une fois le script de configure terminé, nous commençons l'assemblage des modules; nous n'avons pas besoin de collecter tous les nginx :

 make modules 

Notez que cette commande n'est disponible qu'avec la version 1.9.13 de nginx .


  • Une fois le processus d'assemblage terminé, copiez le fichier so résultant sur le volume , qui a été monté au démarrage du conteneur:

 cp objs/ngx_http_vhost_traffic_status_module.so /nginx_module/ 

  • Ensuite, nous plaçons le fichier sur le serveur cible, dans ce cas, le répertoire avec les modules se trouve sur le chemin /usr/share/nginx/modules . Afin d'activer le module dans nginx nous créons le fichier /etc/nginx/modules-enabled/mod-http-vhost-traffic-status.conf avec le contenu suivant:

 load_module modules/ngx_http_vhost_traffic_status_module.so; 

Et créez un lien symbolique vers ce fichier dans le répertoire /etc/nginx/modules-enabled .


Après le travail effectué, nous appelons la commande nginx -t et ... nous obtenons l'erreur:


 nginx: [emerg] module "/usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so" is not binary compatible in /etc/nginx/modules-enabled/50-mod-http-vhost-traffic-status.conf:1 

Et ici, généralement, il y a une certaine perplexité, car la version source et la version nginx installées sur le serveur sont les mêmes, les versions OpenSSL aussi, les paramètres du script configure sont également entièrement copiés. Alors, quel est le problème?


Pour comprendre ce problème, j'ai dû comprendre comment nginx vérifie si le module dynamique lui convient. Le code qui se trouve dans les sources nginx dans le src/core/ngx_module.h ( https://github.com/nginx/nginx/blob/master/src/core/ngx_module.h ) est responsable de cette vérification. Ce fichier contient un certain nombre de contrôles, dans ce cas 34, au cours desquels nginx définit des variables de la forme NGX_MODULE_SIGNATURE_0 (1,2,3, etc.)
valeurs 1 ou 0. Vient ensuite la variable NGX_MODULE_SIGNATURE
qui recueille les résultats de tous les contrôles sur une seule ligne. Par conséquent, le problème est que la chaîne de signature du nouveau module ne correspond pas à la chaîne de signature du nginx existant. Pour vérifier les valeurs des chaînes de signature, vous pouvez utiliser les commandes suivantes:


  • La ligne de signature du module qui a été construit:

 strings /usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so| fgrep '8,4,8' 8,4,8,000011111101011111111111110110111 

  • Ligne de signature du fichier binaire nginx installé sur le serveur:

 strings /usr/sbin/nginx| fgrep '8,4,8' 8,4,8,000011111101011111111111110111111 

En comparant ces lignes à l'œil nu, il est clair que dans la ligne de signature du module, la quatrième variable de la fin s'est avérée être 0, tandis que nginx a 1. Pour comprendre exactement ce qui manque dans le module, vous devez vous référer au src/core/ngx_module.h et trouver la quatrième variable à partir de la fin, elle ressemble à ceci:


 #if (NGX_HTTP_REALIP) #define NGX_MODULE_SIGNATURE_29 "1" #else #define NGX_MODULE_SIGNATURE_29 "0" #endif #if (NGX_HTTP_HEADERS) #define NGX_MODULE_SIGNATURE_30 "1" #else #define NGX_MODULE_SIGNATURE_30 "0" #endif #if (NGX_HTTP_DAV) #define NGX_MODULE_SIGNATURE_31 "1" #else #define NGX_MODULE_SIGNATURE_31 "0" #endif #if (NGX_HTTP_CACHE) #define NGX_MODULE_SIGNATURE_32 "1" #else #define NGX_MODULE_SIGNATURE_32 "0" #endif #if (NGX_HTTP_UPSTREAM_ZONE) #define NGX_MODULE_SIGNATURE_33 "1" #else #define NGX_MODULE_SIGNATURE_33 "0" #endif #define NGX_MODULE_SIGNATURE 

Nous nous intéressons à la variable NGX_HTTP_HEADERS , lors de la construction de nginx elle était de 1 et lors de la construction du module 0. Pour que le module puisse NGX_HTTP_HEADERS avec NGX_HTTP_HEADERS vous devez ajuster le fichier de configuration dans le répertoire avec le code source du module en ajoutant la ligne have=NGX_HTTP_HEADERS . auto/have have=NGX_HTTP_HEADERS . auto/have au début du fichier de config. Voici le début du fichier de configuration après avoir apporté les modifications:


 ngx_addon_name=ngx_http_vhost_traffic_status_module have=NGX_STAT_STUB . auto/have have=NGX_HTTP_HEADERS . auto/have ... 

Ensuite, make clean , puis redémarrez la configure et la make modules . Après avoir assemblé le module, nous vérifions sa chaîne de signature et voyons maintenant qu'il correspond à la chaîne nginx :


 $ strings /usr/sbin/nginx| fgrep '8,4,8' 8,4,8,000011111101011111111111110111111 $ strings /usr/share/nginx/modules/ngx_http_vhost_traffic_status_module.so | fgrep '8,4,8' 8,4,8,000011111101011111111111110111111 

Après cela, le module se connecte sans aucun problème et vous pouvez collecter des statistiques avancées avec nginx .


Dans votre cas, la ligne de signature sera peut-être différente, ainsi que les variables responsables de chaque position de cette ligne. Cependant, vous pouvez maintenant comprendre ce qui ne va pas exactement avec l'assemblage du module et résoudre le problème.


J'espère que cet article fait gagner du temps à quelqu'un, car j'ai personnellement rencontré à plusieurs reprises le problème que le module ne correspondait pas à nginx , en conséquence, en règle générale, j'ai résolu cela grâce à l'assemblage complet de nginx avec le bon module.


Lisez également d'autres articles sur notre blog:


Source: https://habr.com/ru/post/fr473578/


All Articles