👌

コンテナ環境でNext.js(next/image)を動かす際の注意点

2022/02/18に公開

先日, Next.jsで「ISR・SSGをしない」という選択肢 という記事を書きました.

この記事では,ISR・SSGを諦めてSSRに寄せる構成のメリットについて触れており,awsを使用し,ECSの前にCloudFrontを置く構成を紹介しています.

しかし,next/imageのデフォルトローダーで使用される画像最適化プログラムは,キャッシュの保存にファイルシステムを使用するため,一部コンテナ環境で動作させるには注意が必要です.

本記事では,next/imageの概要とキャッシュ機能の動作について触れます.
また,コンテナ環境で動作させる際に問題になる点と,その問題を回避する方法について書きます.

next/imageの概要

next/imageはNext.js組み込みの機能で,画像読み込みの際に遅延ロードや適切なサイズへの変形等の最適化処理を提供します.

next/image が提供するReactコンポーネントを通してこれらの最適化処理を使用することができます.

このコンポーネントは下記のように使用します.

import Image from "next/image";
<Image src="img.png" height={500} />

この時, Image コンポーネントはプロパティで指定された値をもとに,下記のようなURLを組み立て, img タグに渡します.

/_next/image?url=[img url]&w=[img width]&q=[img quality]

上記URLはNext.js組み込みの画像変形用のエンドポイントで,指定されたURLから画像を取得し,その画像を変形して返します.また,処理した画像はキャッシュに保存しておき,次回以降はキャッシュから返すようになっています.

キャッシュ機能の動作

画像の取得や変形は packages/next/server/image-optimizer.ts で実装されており,キャッシュの実装もここで確認できます.

先述したように,キャッシュの保存先としてファイルシステムが使用されていますが,その実装を差し替えることはできないようになっています.

キャッシュ機能をコンテナ環境で動作させる場合の問題点

ファイルシステムをキャッシュストアにすることに問題があります.

例えば,GAE(スタンダード環境)ではファイルの読み取り・書き込みにCloud Storageが推奨されていますし,Fargateでも容量は制限されています

ECSやGAEなどのマネージドなコンテナ動作環境では,ファイルの保存にはオブジェクトストレージを用いることが一般的であることを考えると納得のいく制限ではありますね.

さらに,先述したキャッシュの実装ではキャッシュサイズの上限を指定するような機能はないようです.そのため,そのままではディスク容量枯渇の懸念があります.

問題を回避する方法

EFSを使う

AWSでは,EFSをコンテナにマウントして使用することが可能です.

ローダーを変更する

また,Next.jsローダーと呼ばれる概念で画像をリクエストする先を変更することが可能で,例えばcloudinaryやimgixを使用することも可能で,独自の実装を用意することも可能です.
ローダーを差し替えた場合,Next.js組み込みの機能は使用されなくなるので,先述したようなキャッシュ機能に関連する懸念点も解消されます.

unoptimizedプロパティを使う

unoptimized プロパティ を使うと,画像最適化機能を無効にすることができます.この場合画像の変形処理やキャッシュは行われません.

画像のリサイズ処理を別のタイミングで行うなどのケースで,読み込み時に画像の変形が必要ない場合は,この解決方法も有効だと思います.

(おまけ) Serverless Next.jsってどうしてんの?

S3をキャッシュストアとして使うような独自実装を持っています.
Amplifyとかもたぶんこれです.

https://github.com/serverless-nextjs/serverless-next.js/blob/master/packages/libs/lambda-at-edge/src/image-handler.ts

Discussion