こんにちは、滝澤です。 1年ぶりのnginxのエントリーです。 1年前と同じくnginxの動的モジュールのお話をします。
nginx-1.9.11以降では動的モジュール(Dynamic Modules)がサポートされています。このことについては昨年の記事「nginx-1.9.11で動的モジュールをサポート」で紹介しました。
nginxの動的モジュールの機能が実装されてから約1年経ちますので、2017年2月時点での最新状況について確認してみました。 状況が進展していたので最新状況について紹介します。
動的モジュールについての概要は昨年の記事「nginx-1.9.11で動的モジュールをサポート」に書きましたので合わせて読んでいただければと思います。
なお、執筆時点(2017年2月22日)での最新バージョンはnginx-1.11.10です。
動的モジュールとして利用できるモジュール
nginx-1.11.10において利用できる動的モジュールには次のものがあります。
- XSLT (ngx_http_xslt_module)
- Image Filter (ngx_http_image_filter_module)
- GeoIP (ngx_http_geoip_module)
- Perl (ngx_http_perl_module) (1.9.13以降)
- Mail (ngx_mail_module)
- Stream (ngx_stream_module)
- Stream GeoIP (ngx_stream_geoip_module) (1.11.3以降)
PerlモジュールとStream GeoIPモジュールが動的モジュールとして利用できるようになりました。
また、標準のnginxには同梱されていませんが、nginScriptも動的モジュールに対応しています。
- nginScript (ngx_http_js_module)
- Stream nginScript (ngx_stream_js_module)
公式バイナリパッケージ
nginxの公式サイトでは、動的モジュールに対応したLinuxディストリビューション用のバイナリパッケージが提供されています。
nginx-1.11.10においては、次の動的モジュールのパッケージが提供されています。
パッケージ名 | モジュール名 |
---|---|
nginx-module-xslt | ngx_http_xslt_filter_module |
nginx-module-image-filter | ngx_http_image_filter_module |
nginx-module-geoip | ngx_http_geoip_module, ngx_stream_geoip_module |
nginx-module-perl | ngx_http_perl_module |
nginx-module-njs | ngx_http_js_module, ngx_stream_js_module |
StreamモジュールとMailモジュールについては、nginxバイナリに静的にビルドされて組み込まれています。
なお、nginxバイナリと動的モジュールの両方とも、後述するconfigure時のオプション「--with-compat」付きでビルドされています。
nginxバイナリとモジュールのsignatureが異なると動作しない
動的モジュールが実装された当初から「nginxバイナリとモジュールのsignatureが異なると動作しない」という制約があります。
このことについては昨年の記事「nginx-1.9.11で動的モジュールをサポート」において次のように説明しました。
nginxバイナリと異なる環境でビルドされた動的モジュールを組み合わせて動かすことはできません。 これにより困ることの例としては、公式サイトやディストリビューションからnginxのRPMパッケージをインストールした環境に、その環境でビルドした動的モジュールを利用することができません。
nginxのビルド時に、ビルド環境のライブラリとAPIの有無およびビルドオプションからsignatureの文字列が生成され、nginxバイナリおよび各モジュールのバイナリに埋め込まれます。
nginxはモジュールの追加時にモジュールのsignatureがnginxバイナリが持っているものと同じかを確認します。
そのため、nginxバイナリと異なる環境でビルドされたモジュールを組み合わせて動かすことは基本的にはできません。 ただし、ビルド環境のライブラリとAPIの有無およびビルドオプションがすべて同じであればsignatureも同じになるため、この場合は動作します。
この制約そのものは本記事の執筆時点でのnginx-1.11.10においても変更はありません。
しかし、同じOSの環境であれば同じsignatureになるようなconfigure時のオプション「--with-compat」がnginx-1.11.5から追加されました。
--with-compat dynamic modules compatibility
これにより、ビルドした環境が同じOSであれば、別のサーバでビルドされたモジュールを持ってきても、そのまま使えるようになりました。
ただし、本記事の最後のセクションで述べますが、同じOSでもビルド環境のOSのAPIの有無が異なる場合や、configure時にデフォルトで有効なオプションを無効化している場合は、signatureが異なってしまう可能性があり、そのまま使えない恐れはあります。
「--with-compat」オプションを有効にしたビルドの例
CentOS 7の環境で公式パッケージをインストールしているときに、サードパーティの動的モジュールを「--with-compat」オプションを有効にしてビルドして追加する例を紹介します。
まず、パッケージでインストールしたnginxのバージョンと同じバージョンのnginxのソースコードを入手し、展開します。
$ rpm -q nginx nginx-1.11.10-1.el7.ngx.x86_64 $ curl http://nginx.org/download/nginx-1.11.10.tar.gz -o nginx-1.11.10.tar.gz $ tar xvzf nginx-1.11.10.tar.gz
利用するサードパーティの動的モジュールを入手して展開します。
$ curl http://example.org/download/foo-module.tar.gz -o foo-module.tar.gz $ tar xvzf foo-module.tar.gz
nginxのソースコードを展開したディレクトリに移動します。
$ cd nginx-1.11.10
configureを「--with-compat」オプションと「--add-dynamic-module」にモジュールのパスを指定したものを付けて実行します。
$ ./configure --with-compat --add-dynamic-module=/path/to/foo-module 中略 configuring additional dynamic modules adding module in /path/to/foo-module + foo_module was configured 中略
モジュールをコンパイルします。
$ make modules
ビルドした動的モジュールをモジュール用ディレクトリにコピーします。
$ sudo cp objs/foo-module.so /etc/nginx/modules/
モジュールをロードする設定をnginx.confのevents{}の設定より前に追加します。
load_module modules/foo_module.so;
nginxを構文チェックを行った後に、リロードします。
$ sudo nginx -t $ sudo systemctl reload nginx
以上で動的モジュールの追加が完了となります。
参考までに、nginxバイナリと追加インストールした動的モジュールのsignatureの文字列が同じであるかを比べてみましょう。
signatureの文字列はnginxバイナリおよびモジュールに含まれています。そのファイルに対してstringsコマンドを実行し、その出力に対する正規表現「^.,.,.,
」で見つけることができます。
$ strings /usr/sbin/nginx | grep '^.,.,.,' 8,4,8,0011111111010111001111111111111111 $ strings /etc/nginx/modules/foo-module.so | grep '^.,.,.,' 8,4,8,0011111111010111001111111111111111
このように、筆者のテスト環境では同じになることを確認しました。
signatureの詳細
最後にsignatureの詳細について説明します。
signatureはソースコードファイル src/core/ngx_module.h に次のように定義されています。
#define NGX_MODULE_SIGNATURE_0 \ ngx_value(NGX_PTR_SIZE) "," \ ngx_value(NGX_SIG_ATOMIC_T_SIZE) "," \ ngx_value(NGX_TIME_T_SIZE) "," #if (NGX_HAVE_KQUEUE) #define NGX_MODULE_SIGNATURE_1 "1" #else #define NGX_MODULE_SIGNATURE_1 "0" #endif 中略 #if (NGX_COMPAT) #define NGX_MODULE_SIGNATURE_34 "1" #else #define NGX_MODULE_SIGNATURE_34 "0" #endif #define NGX_MODULE_SIGNATURE \ NGX_MODULE_SIGNATURE_0 NGX_MODULE_SIGNATURE_1 NGX_MODULE_SIGNATURE_2 \ 中略 NGX_MODULE_SIGNATURE_33 NGX_MODULE_SIGNATURE_34
これを表にまとめると次のようになります。
定義名 | 値あるいは条件 | デフォルト | NGX_COMPAT 有効時に有効化 | 公式パッケージ (CentOS7) |
---|---|---|---|---|
NGX_MODULE_SIGNATURE_0 | ngx_value(NGX_PTR_SIZE) | - | 8 | |
, | , | , | ||
ngx_value(NGX_SIG_ATOMIC_T_SIZE) | - | 4 | ||
, | , | , | ||
ngx_value(NGX_TIME_T_SIZE) | - | 8 | ||
, | , | , | ||
NGX_MODULE_SIGNATURE_1 | NGX_HAVE_KQUEUE | - | 0 | |
NGX_MODULE_SIGNATURE_2 | NGX_HAVE_IOCP | - | 0 | |
NGX_MODULE_SIGNATURE_3 | NGX_HAVE_FILE_AIO || NGX_COMPAT | - | 1 | |
NGX_MODULE_SIGNATURE_4 | NGX_HAVE_AIO_SENDFILE || NGX_COMPAT | - | 1 | |
NGX_MODULE_SIGNATURE_5 | NGX_HAVE_EVENTFD | - | 1 | |
NGX_MODULE_SIGNATURE_6 | NGX_HAVE_EPOLL | - | 1 | |
NGX_MODULE_SIGNATURE_7 | NGX_HAVE_KEEPALIVE_TUNABLE | - | 1 | |
NGX_MODULE_SIGNATURE_8 | NGX_HAVE_INET6 | - | 1 | |
NGX_MODULE_SIGNATURE_9 | 1 | 1 | 1 | |
NGX_MODULE_SIGNATURE_10 | 1 | 1 | 1 | |
NGX_MODULE_SIGNATURE_11 | NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER | - | 0 | |
NGX_MODULE_SIGNATURE_12 | 1 | 1 | 1 | |
NGX_MODULE_SIGNATURE_13 | NGX_HAVE_SETFIB | - | 0 | |
NGX_MODULE_SIGNATURE_14 | NGX_HAVE_TCP_FASTOPEN | - | 1 | |
NGX_MODULE_SIGNATURE_15 | NGX_HAVE_UNIX_DOMAIN | - | 1 | |
NGX_MODULE_SIGNATURE_16 | NGX_HAVE_VARIADIC_MACROS | - | 1 | |
NGX_MODULE_SIGNATURE_17 | 0 | 0 | 0 | |
NGX_MODULE_SIGNATURE_18 | 0 | 0 | 0 | |
NGX_MODULE_SIGNATURE_19 | NGX_HAVE_OPENAT | - | 1 | |
NGX_MODULE_SIGNATURE_20 | NGX_HAVE_ATOMIC_OPS | - | 1 | |
NGX_MODULE_SIGNATURE_21 | NGX_HAVE_POSIX_SEM | - | 1 | |
NGX_MODULE_SIGNATURE_22 | NGX_THREADS || NGX_COMPAT | 0 | 1 | |
NGX_MODULE_SIGNATURE_23 | NGX_PCRE | (1)*1 | 1 | |
NGX_MODULE_SIGNATURE_24 | NGX_HTTP_SSL || NGX_COMPAT | 0 | 1 | |
NGX_MODULE_SIGNATURE_25 | 1 | 1 | 1 | |
NGX_MODULE_SIGNATURE_26 | NGX_HTTP_GZIP | 1 | ✓ | 1 |
NGX_MODULE_SIGNATURE_27 | 1 | 1 | 1 | |
NGX_MODULE_SIGNATURE_28 | NGX_HTTP_X_FORWARDED_FOR | (1)*2 | ✓ | 1 |
NGX_MODULE_SIGNATURE_29 | NGX_HTTP_REALIP | 0 | ✓ | 1 |
NGX_MODULE_SIGNATURE_30 | NGX_HTTP_HEADERS | 1 | ✓ | 1 |
NGX_MODULE_SIGNATURE_31 | NGX_HTTP_DAV | 0 | ✓ | 1 |
NGX_MODULE_SIGNATURE_32 | NGX_HTTP_CACHE | 1 | 1 | |
NGX_MODULE_SIGNATURE_33 | NGX_HTTP_UPSTREAM_ZONE | 1 | ✓ | 1 |
NGX_MODULE_SIGNATURE_34 | NGX_COMPAT | 0 | ✓ | 1 |
- *1) "NGX_PCRE"はconfigure時に"--with-pcre"オプションで有効にしたときか、http_rewrite_moduleが有効であるときに有効になります。http_rewrite_moduleはデフォルトで有効であるため、configure時に明示的に無効にしない限り有効になります。
- *2) "NGX_HTTP_X_FORWARDED_FOR"はhttp_realip_module, http_geoip_module, http_geo_module, http_proxy_moduleのいずれかが有効であるときには有効になります。http_geo_moduleとhttp_proxy_moduleはデフォルトで有効であるため、configure時に明示的に無効にしない限り有効になります。
0番から21番の定義値はOSの環境(OSのAPIの有無)により決定します。そのため、同じOSの環境であれば同じ値になるはずです。
22番以降の定義値はconfigure時のオプションにより決定します。 configure時のオプション「--with-compat」を有効にすると、内部的には"NGX_COMPAT"が有効になります。このとき、他のモジュールが有効化されたり、定義値の値が1になったりします。 その結果として、22番以降の値はすべて1になります。
以上より、configure時のオプション「--with-compat」を有効にすると、同じOSの環境であればsignatureの値は同じ値になることがわかります。
ただし、同じOSでもビルド環境のOSのAPIの有無が異なる場合や、configure時にデフォルトで有効なオプションを無効化している場合は、signatureが異なってしまう可能性があります。
参考文献
- nginx-1.9.11で動的モジュールをサポート (株式会社ハートビーツ)
- nginx: Linux packages - Dynamic Modules (nginx公式サイト)
- Compiling Dynamic Modules for NGINX Plus (NGINX, Inc.)