ブログ | NGINX

NGINX と NGINX Plus は、頭を悩ませることなくレスポンシブな画像を実現します

NGINX-F5 水平黒タイプ RGB の一部
リアム・クリリー サムネイル
リアム・クリリー
2016 年 9 月 29 日公開
NGINX Plus Image-Filter モジュールを使用してレスポンシブな画像を作成し、よりレスポンシブな Web デザインを実現する方法に関する記事の雑誌ラックの画像。
写真: フィル・ローダー

Image‑Filter モジュールと srcset タグを使用して、画像を即座にサイズ変更する

レスポンシブ Web デザインは、現代の Web サイトや Web アプリケーションの標準となり、さまざまなデバイス間で一貫したエクスペリエンスを提供すると同時に、各デバイスの表示を最適化します。 ただし、最近のデバイスは画面サイズだけでなくピクセル密度も異なります。 HTML5 imgタグには、サーバーが複数のバリエーションを提供する場合にブラウザが最も適切なアセットを選択できるようにするさまざまな機能が用意されています。 ウェブサイトが同じ画像の複数の異なるサイズを展開する場合、ウェブブラウザは現在の環境に最適なサイズを選択できます。

したがって、レスポンシブ イメージを使用すると、Web ブラウザーはデザイナーの意図に近いレンダリングを生成できるようになります。 これによりユーザー エクスペリエンスは向上しますが、デフォルトのイメージに加えて多数のイメージ アセットのバリエーションを作成して展開する必要があるため、開発チームと運用チームには追加の負担がかかります。

このブログ記事では、NGINX および NGINX Plus のImage‑Filter モジュールを使用して、無数のイメージアセットのバリエーションを作成および管理する手間をかけずにレスポンシブなイメージを配信する方法を紹介します。代わりに、NGINX または NGINX Plus がオンザフライでサイズを変更する各イメージの単一の「ソース」バージョンをデプロイできます。 この記事の情報は、NGINX Open Source と NGINX Plus の両方に適用されます ( Image‑Filter モジュールのインストールの個別の手順を除く)。簡潔にするために、全体を通じて NGINX Plus について言及します。

srcset属性

レスポンシブな画像を配信するための主なツールは、HTML5 imgタグのsrcset属性です。 これを使用して、さまざまなピクセル密度とビューポート サイズの画像アセット バリアントの数を指定できます。 ビューポートとは、デスクトップ上のウィンドウやモバイル デバイス上の全画面アプリなど、Web ブラウザーで使用できる表示スペースの総称です。

次の例では、 src属性はsrcset属性をサポートしていないブラウザのデフォルト画像を定義し、 srcset属性は 2 つのバリアントを指定します。1 つは標準ピクセル密度のディスプレイ用 ( 1x )、もう 1 つは Apple Retina™ ディスプレイや一部の 4K モニターなどの 2 倍ピクセル密度のディスプレイ用 ( 2x ) です。

< img src= "/images/mylogo-default.png" srcset= "/images/mylogo-density1.png 1x、/images/mylogo-density2.png 2x" >

次のより洗練された例では、ビューポートの幅に応じて、表示する画像アセットのバリアントの数を定義します。 sizes属性は、ビューポートの幅が10emより大きい場合はブラウザがビューポートの半分に画像をレンダリングし、それ以外の場合はビューポート全体を使用することを指定します。 ブラウザは、画像に使用できるスペースの量を判断し、使用可能なスペースに最適な画像アセットバリアントを選択します。通常、次の幅 ( wサフィックス) に「切り上げ」、スペースを正確に埋めるように内部的に画像のサイズを変更します。

< img src= "/images/racecar-default.jpg" sizes= "(最小幅: 10em) 50vw、100vw" srcset= "/images/racecar-100px.jpg 100w、/images/racecar-225px.jpg 225w、/images/racecar-450px.jpg 450w、/images/racecar-675px.jpg 675w" >

さまざまな画像アセットのバリエーションを指定してレスポンシブな画像を配信するこのアプローチは、コーディングが簡単で非常に効果的です。 ただし、イメージバリアント自体の作成と管理に関しては課題があります。 制作前に大量のイメージのサイズ変更を行い、サーバー上に大量のファイルを展開する必要があります。 各バリアントの最適な数とサイズを微調整するには時間がかかり、各画像アセット バリアントがアクセス可能であるかどうかをテストすることが困難になります。

srcset属性やレスポンシブ画像のその他のテクニックの詳細については、こちらの優れたブログ投稿をご覧ください。

画像フィルターモジュールのインストール

Image‑Filter モジュールを取得する手順は、NGINX Plus と NGINX で異なります。

NGINX Plus 用のイメージフィルターモジュールのインストール

Image‑Filter モジュールは、NGINX Plus サブスクライバー向けの無料の動的モジュールとして利用できます。

  1. NGINX Plus リポジトリからモジュール自体をインストールして入手します。

    Ubuntu および Debian システムの場合:

    $ sudo apt-get で nginx-plus-module-image-filter をインストールします

    RedHat、CentOS、Oracle Linux システムの場合:

    $ sudo yum インストール nginx-plus-module-image-filter
  2. モジュールを有効にするには、 nginx.conf構成ファイルの最上位 (「main」) コンテキスト (つまり、 httpまたはstreamコンテキストではない) にload_moduleディレクティブを含めます。

    モジュールモジュール/ngx_http_image_filter_module.so をロードします。
  3. NGINX Plus をリロードして、実行中のインスタンスに Image‑Filter モジュールをロードします。

    $ sudo nginx -s リロード>

NGINXオープンソース用イメージフィルターモジュールのインストール

Image‑Filter モジュールをインストールする最も簡単な方法は、公式の NGINX リポジトリから入手することです。 次の手順に従って、システムが公式 NGINX リポジトリにアクセスするように構成し、オペレーティング システムのパッケージ マネージャーを使用してインストールします。

Ubuntu および Debian システムの場合:

$ sudo apt-get install nginx-module-image-filter

Red Hat、CentOS、Oracle Linux システムの場合:

$ sudo yum インストール nginx-module-image-filter

インストールが完了したら、 「NGINX Plus 用イメージ フィルター モジュールのインストール」の手順 2 と 3 に従って、NGINX を設定してリロードします。

Image‑Filter モジュールをソースからコンパイルし、静的にコンパイルされたモジュールまたは動的モジュールとしてロードすることもできます。 詳細については、 NGINX Plus 管理者ガイドを参照してください。

画像サイズとピクセル密度の一致

Image‑Filter モジュールを使用すると、各イメージの単一の「ソース」バージョンを作成してデプロイし、NGINX Plus でそのイメージをオンザフライでサイズ変更して、ブラウザーから要求されたサイズのバリエーションを提供できます。 手動でサイズを変更したり、Web サーバーに画像を展開したりすることなく、HTML ソース内でレスポンシブ Web ページと画像を完全に微調整できます。

このサンプル HTML ファイルでは、ピクセル密度の異なるデバイス用に 4 つの画像バリアントを定義します。

< html > < head > < title >レスポンシブ ロゴ title >  head > < body > < h2 >ピクセル密度に基づくロゴの選択 h2 > < img src= "/img400/mylogo.png" srcset= "/img400/mylogo.png 1x, /img800/mylogo.png 2x, /img1200/mylogo.png 3x, /img1600/mylogo.png 4x" >  body >  html >

/img400/img800/img1200/img1600ディレクトリは実際には存在しません。 代わりに、次の NGINX Plus 構成は、 /imgで始まるアセットのリクエストを照合し、元のファイル名 (たとえば、前述の HTML のmylogo.png ) でイメージのサイズを変更するリクエストに変換します。

サーバー { listen 80;
root /var/www/public_html;

location ~ ^/img([0-9]+)(?:/(.*))?$ {
alias /var/www/source_images/$2;
image_filter_buffer 10M;
image_filter resize $1 -;
}
}

サーバーブロックは、NGINX Plus が受信 HTTP リクエストを処理する方法を定義します。 listenディレクティブは、NGINX Plus に、HTTP トラフィックのデフォルトであるポート 80 でリッスンするように指示します。 ルートディレクティブは、この Web サイトのディスク上の場所を指定します。 この単純な例では、NGINX Plus でホストされている静的 Web サイトを使用していますが、NGINX Plus が動的コンテンツのリバース プロキシや FastCGI などのアプリケーション コネクタとして機能することも一般的です。これらすべてのユース ケースでは、ここで説明するように、ソース イメージを NGINX Plus サーバーにデプロイすることで、Image‑Filter モジュールを活用できます。

ロケーションブロックは正規表現を使用して、 /imgで始まり、その後に 1 つ以上の数字が続くディレクトリに保存されているアセットのリクエストを照合します。 数字は変数$1としてキャプチャされ、それに続くファイル名は変数$2としてキャプチャされます。 次に、エイリアスディレクティブを使用して、ソース イメージを含むディスク上のディレクトリからこの要求に応えます。 このディレクトリはルートパスの下にはないため、クライアントはソース イメージを直接要求できないことに注意してください。

ソース イメージは非常に大きく、幅が数千ピクセルになる可能性があるため、Image‑Filter モジュールがイメージを読み込んでサイズを変更するのに十分なメモリを割り当てるようにする必要があります。 この例では、 image_filter_bufferディレクティブを使用して、最大 10 MB のサイズの画像ファイルをサポートします。

最後に、 image_filterディレクティブは、Image‑Filter モジュールに、 /imgディレクトリ名のサフィックスからキャプチャされた幅にソース イメージのサイズを変更するように指示します。 ダッシュ (‑) は、NGINX Plus にソース イメージのアスペクト比を維持するように指示します。

生産現場での使用に関する考慮事項

「画像サイズとピクセル密度の一致」で説明されている構成では、画像のリクエストに使用されるディレクトリ名に応じて、画像の任意のサイズのバリエーションを配信できます。 ただし、実稼働環境では、リクエストごとに Web サーバーが画像のサイズを変更するのを待つ必要はありません。 これは全体的なレイテンシには良くなく、CPU オーバーヘッドも大幅に増加する可能性があります。

最も効果的な解決策は、サイズ変更された画像バリアントをキャッシュして、各バリアントの後続のリクエストが Image‑Filter モジュールを経由せずにキャッシュから提供されるようにすることです。 NGINX Plus 構成では、イメージのサイズ変更を実行する別の仮想サーバーを定義し、要求されたイメージ サイズがキャッシュにまだ存在しない場合にのみ、そのサーバーに要求をプロキシすることで、これを実現できます。 これをレスポンシブイメージサーバーと呼びます。

フロントエンド Web サーバーとレスポンシブ イメージ サーバー用の「location」ブロックを備えた NGINX Plus の運用構成。 より応答性の高い Web デザインを実現するために、Web サーバーは、Image-Filter モジュールを使用してイメージ サーバーによって作成されたサイズのバリエーションをキャッシュします。
図1. フロントエンド Web サーバーでキャッシュを有効にしたレスポンシブ イメージ サーバーの運用構成

また、任意のリクエストによる画像サイズ変更操作を許可することによるセキュリティ上の影響も考慮する必要があります。 キャッシュを構成しても、攻撃者が/img1001/mylogo.png/img1002/mylogo.png/img1003/mylogo.pngなどの一意の画像アセットバリアントに高速でリクエストを送信した場合には役に立ちません。 このような攻撃は、リクエストの量が比較的少ない場合でも、CPU 使用率が過度に高くなるため、サービス拒否 (DoS) を引き起こす可能性があります。 この問題に対処するために、レスポンシブ イメージ サーバーにレート制限を適用しますが、キャッシュされたバリアントを含むフロントエンド サーバーにはレート制限を適用しません。 次の構成は、イメージ フィルター モジュールにキャッシュとレート制限を適用することで、 「イメージ サイズとピクセル密度の一致」の構成を拡張します。

proxy_cache_path /var/www/imgcache levels=1 keys_zone=resized:1m max_size=256m;
server {
listen 80;
root /var/www/public_html;

location ~ ^/img([0-9]+)(?:/(.*))?$ {
proxy_pass http://127.0.0.1:9001;
proxy_cache resized;
proxy_cache_valid 180m;
}
}

limit_req_zone "1" zone=2persec:32k rate=2r/s;

server {
listen 9001;
allow 127.0.0.1;
deny all;
limit_req zone=2persec burst=10;

場所 ~ ^/img([0-9]+)(?:/(.*))?$ {
alias /var/www/source_images/$2;
image_filter_buffer 10M;
image_filter resize $1 -;
}
}

まず、 proxy_cache_pathディレクティブを使用してキャッシュされた画像の場所を定義します。 keys_zoneパラメータは、キャッシュ インデックスの共有メモリ ゾーン ( resizedと呼ばれる) を定義し、1 MB を割り当てます。これは、約 8,000 個のサイズ変更されたイメージに十分なサイズです。 max_sizeパラメータは、NGINX Plus が新しいキャッシュ項目のためのスペースを確保するために、キャッシュから最も最近リクエストされていないイメージを削除し始めるポイントを定義します。

フロントエンド Web サーバー (ポート 80 でリッスンしているサーバー) のlocationディレクティブは、 proxy_passディレクティブを使用して、 /imgで始まるリクエストを内部でホストされているレスポンシブ イメージ サーバー (127.0.0.1:9001) に送信します。 proxy_cacheディレクティブは、レスポンシブ イメージ サーバーからの応答を保存するために使用するキャッシュの名前 ( resized ) を指定することにより、この場所のキャッシュを有効にします。 proxy_cache_validディレクティブは、サイズ変更された画像が少なくとも 180 分間キャッシュに保持されること (キャッシュがmax_sizeを超え、最も最近要求されたものでない限り)、および応答画像サーバーからの誤った応答がキャッシュされないことを保証します。

キャッシュの詳細な説明については、 「NGINX および NGINX Plus を使用したキャッシュのガイド」を参照してください。

レスポンシブ イメージ サーバー自体を定義する前に、 limit_req_zoneディレクティブを使用してレート制限を指定します。 ディレクティブ自体はレート制限を強制しません。1 秒あたり 2 リクエストのレート制限を定義し、サーバーブロックにlimit_reqディレクティブを含めることで、レスポンシブ イメージ サーバーに適用されます (次の段落を参照)。 通常、レート制限はリクエストの属性に対してキー設定されますが、この場合は、制限がすべてのリクエスト元に適用されるように、静的キー値「1」を指定します。 キーの基数は 1 に固定されているため、共有メモリ ゾーンのサイズを可能な限り小さい値である 3 KB に設定します。

レスポンシブ イメージ サーバーのサーバーブロックはポート 9001 でリッスンします。 ローカルホスト (フロントエンド Web サーバー) のみがレスポンシブ イメージ サーバーに接続できるように指定するためにallowディレクティブとdenyディレクティブを含めます。 次に、 limit_reqディレクティブを追加して、以前に定義したレート制限を適用します。バーストパラメータは、レート制限を適用する前に 10 件の同時リクエストを許可します。 レート制限が有効になると、超過リクエストは制限内で処理できるようになるまで遅延されます。

ロケーションブロックは、画像サイズとピクセル密度の一致のブロックと同じですが、要求された画像がキャッシュ内に存在せず、レート制限を超えていない場合にのみ実行されます。

この基本構成では、単一の NGINX Plus インスタンスがフロントエンド Web サーバーとレスポンシブ イメージ サーバーの両方として機能します。 画像処理は計算負荷が非常に高くなる可能性があり、非常に高いワークロードにつながり、NGINX Plus が DoS 攻撃の対象になる可能性があります。 すべてのワーカープロセスがイメージのサイズ変更リクエストでビジー状態になっているためにフロントエンド Web サーバーが新しいリクエストをすぐに受け入れることができない状況を回避するには、イメージ処理専用の別の NGINX Plus インスタンスを実行することをお勧めします。 これにより、フロントエンド Web サーバーのワーカー プロセスが、画像処理を実行するワーカー プロセスから分離されます。 同じホスト上で NGINX Plus の別のインスタンスを実行するには、コマンドラインで別の設定ファイルを指定します。

$ sudo nginx -c /etc/nginx/resize-server.conf

レスポンシブイメージの活用

レスポンシブ画像の動作を確認する最も効果的な方法は、ビューポートのサイズが変化すると、ブラウザがどのsrcset画像バリアントを使用するかを決定する様子を観察することです。 以下はシンプルな画像ギャラリーの HTML ソースです。 デモンストレーションの目的で、画像ごとにサイズのバリエーションが若干異なり、ブラウザーが別のバリエーションを選択できる「ブレークポイント」が多数作成されることに注意してください。

<!DOCTYPE html>
<html>
<>
<タイトル>レスポンシブ画像ギャラリー</タイトル>
</>
<>
 
<h2>レスポンシブ画像ギャラリー</h2>

<画像 ソース=「/img100/1-ドミノ.jpg」 サイズ="(最小幅: 20em) 40vw, 100vw" srcset= "/img110/1-dominos.jpg 110w, /img210/1-dominos.jpg 210w, /img310/1-dominos.jpg 310w, /img410/1-dominos.jpg 410w, /img510/1-dominos.jpg 510w, /img610/1-dominos.jpg 610w" > < img src= "/img100/2-sign.jpg" sizes= "(最小幅: 20em) 40vw、100vw" srcset= "/img120/2-sign.jpg 120w、/img220/2-sign.jpg 220w、/img330/2-sign.jpg 330w、/img420/2-sign.jpg 420w、/img520/2-sign.jpg 520w、/img620/2-sign.jpg 620w" > < img src= "/img100/3-thruppence.jpg" sizes= "(最小幅: 20em) 40vw, 100vw" srcset= "/img130/3-thruppence.jpg 130w, /img230/3-thruppence.jpg 230w, /img330/3-thruppence.jpg 330w, /img440/3-thruppence.jpg 440w, /img550/3-thruppence.jpg 550w, /img660/3-thruppence.jpg 660w" > < img src= "/img100/4-aces.jpg" sizes= "(最小幅: 20em) 40vw、100vw" srcset= "/img140/4-aces.jpg 140w、/img240/4-aces.jpg 240w、/img340/4-aces.jpg 340w、/img440/4-aces.jpg 440w、/img540/4-aces.jpg 540w、/img640/4-aces.jpg 640w" >  body >  html >

以下のスクリーンショットは、Chrome ブラウザでインスペクタ[ネットワーク]タブを開いたときのこの Web ページの内容を示しています。 名前列には、サーバーから要求された各画像バリアントのパスが表示されます。これにより、Web サーバーのログを確認しなくても、選択されたサイズを確認できます。

図 2 の狭いビューポートでは、ブラウザーは幅 220 ~ 310 ピクセルの画像を選択しました ( [名前] 列の/imgディレクトリ名の数値サフィックスは、これらの値の範囲内です)。

図2. ビューポートが狭い場合のレスポンシブ画像ギャラリー

図 3 でブラウザ ウィンドウを広げると、ブラウザは幅 440 ~ 540 ピクセルの画像 (リストの最後の 4 つの画像) を選択します。 これらのイメージのイニシエーター列の値はOtherです。

図3. ビューポートが広い場合のレスポンシブ画像ギャラリー

結論

NGINX Plus と Image‑Filter モジュールを使用すると、現在のブラウザの状況に最適な画像サイズを提供できます。 また、制作前の画像のサイズ変更、バッチ処理、ディスク上の何百もの画像アセットのバリエーションの管理を行うことなく、これを実現できます。 NGINX Plus が完璧なアプリケーション配信を実現するのに役立つもう 1 つの方法です。

NGINX Plus でレスポンシブ イメージをぜひお試しください。今すぐ30 日間の無料トライアルを開始するか、弊社にお問い合わせの上、ユースケースについてご相談ください


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"