検証などで Stub 的にちょっと JSON の固定レスポンスを返したりするために Nginx のコンテナを利用するシーンが多々あるのですが、ただ JSON を返すだけでは一瞬で返ってしまい、レスポンスタイムなどが現実的でなかったりします。そこで、Nginx で sleep のようなものが設定できるモジュールを公式のコンテナイメージに動的モジュールとして利用できるようにしたので tips としてメモっておきます。

sleep のようなものが設定できる Nginx モジュール

あまりじっくり探す時間もなかったので Qiita の記事 をそのまま参考にさせていただきました。以下の 2つがあるようです。

いろいろ検索した範囲では lua-nginx-module の方が情報が多かったですが、ぱっと見分かりやすそうだった echo-nginx-module の方を使ってみることにしました。

Nginx 公式イメージに動的モジュールとして追加する

まずはモジュールを公式イメージの環境に合わせてコンパイルする必要があるので以下のような手順でイメージをビルドしていきます。

  1. 公式イメージで multi-stage build
  2. 公式イメージの Nginx と同じバージョンのソースコードをダウンロード
  3. echo-nginx-module のソースもダウンロード
  4. --add-dynamic-module オプションで echo-nginx-module を追加して Nginx を make modules
  5. 作成されたモジュールを最終的なイメージにコピー

Dockerfile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
FROM nginx:alpine AS build

ENV ECHO_NGINX_MODULE_VERSION 0.63

RUN NGINX_VERSION=`nginx -v 2>&1 | cut -d '/' -f 2` \
  && cd /tmp \
  && wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz -O nginx-${NGINX_VERSION}.tar.gz \
  && wget https://github.com/openresty/echo-nginx-module/archive/refs/tags/v${ECHO_NGINX_MODULE_VERSION}.tar.gz -O echo-nginx-module-${ECHO_NGINX_MODULE_VERSION}.tar.gz \
  && apk add --no-cache --virtual dependency gcc libc-dev make openssl-dev pcre-dev zlib-dev linux-headers \
  && tar zxf nginx-${NGINX_VERSION}.tar.gz \
  && tar zxf echo-nginx-module-${ECHO_NGINX_MODULE_VERSION}.tar.gz  \
  && cd nginx-${NGINX_VERSION} \
  && CONFARGS=$(nginx -V 2>&1 | sed -n -e 's/^configure arguments: //p') \
  && sh -c "./configure --with-compat ${CONFARGS} --add-dynamic-module=../echo-nginx-module-${ECHO_NGINX_MODULE_VERSION}" \
  && make modules \
  && apk del dependency \
  && rm -rf /var/cache/apk/*


FROM nginx:alpine

COPY --from=build /tmp/nginx-${NGINX_VERSION}/objs/ngx_http_echo_module.so /etc/nginx/modules
RUN sed -i '1s/^/load_module \/etc\/nginx\/modules\/ngx_http_echo_module.so;\n/' /etc/nginx/nginx.conf
  • 13行目 : モジュールの ./configure 時には公式イメージで指定されたオプションと同じものを指定する必要があります。そのオプションは nginx -V で出力できるので、引っ張り出して変数に入れてあげます
  • 14行目 : Dynamic Module として扱うので --add-dynamic-module=.... で指定します
  • 15行目 : make modules とすることでモジュールのコンパイルだけできます

./configure 時に公式イメージで指定されたオプションと同じものを指定しなくてもコンパイルはできてしまいます。が、Nginx の起動時に以下のようなエラーが出てしまいます。

2022/12/26 10:19:25 [emerg] 7#7: module "/etc/nginx/modules/ngx_http_echo_module.so" is not binary compatible in /etc/nginx/nginx.conf:1
nginx: [emerg] module "/etc/nginx/modules/ngx_http_echo_module.so" is not binary compatible in /etc/nginx/nginx.conf:1

(おまけ)echo-nginx-module の使い方

使いこなせないぐらい多機能なので…詳しくはドキュメントを参照いただくとして、簡単な使い方だけご紹介(主要部分の抜粋です)。

load_module /etc/nginx/modules/ngx_http_echo_module.so;

http {
  server {
    location /api/something {
      echo_sleep 1.5;        # Non-blocking
      echo_exec /200.json;
    }

    location /ok {
      echo_blocking_sleep 2; # Blocking
      echo "ok";
    }
  }
}
  • /api/something にアクセスがあったら 1.5秒待って /200.json ファイルの内容を返します
  • /ok にアクセスがあったら 2秒待って “ok” が返ります。blocking 指定しているのでワーカープロセスがブロックされます(本番環境では使わないように、とのこと)

まとめ

Nginx の公式コンテナイメージで動的モジュールを使う方法をやってみました。以下がポイントになるでしょうか。多分他のモジュールでも同様にできるのではないかと思います。

  • Docker Multi-stage Build を活用する
  • 公式イメージで指定した configure オプションと同じものを指定する

最後に・・・

この投稿は個人的なものであり、所属組織を代表するものではありません。ご了承ください。