prodnote.dev本番ノート

Index/13

サーバーの外で next build を測った — ピーク517MiB、スワップは0のまま

前の記事ではサーバーの中でビルドを測りました。今度は反対側、外でビルドする側をこのサイト自身で測っています。ピークRSSは517MiB、スワップは0のまま29秒で終わりました。ただし機械もアプリも違うので、速い遅いの比較にはなりません。

Published
Tags
Next.jsCloudflare PagesVPS個人開発

PR本記事にはアフィリエイトリンクを含みます

明るい室内で立ったまま、壁にある受け渡し口の台へ箱を1つ置いているところ。箱は縁の線だけが色つきで、奥は壁で仕切られていて見えない。手前の作業台には何も載っていない。

ビルドだけ、外で

Contents

前の記事で、2GBのVPSの中で next build を回し、1秒ごとにメモリを記録しました。ビルドは通りましたが、その途中でスワップが140MiB増えていました。

あの記事には、測っていない側があります。ビルドをサーバーの外でやったらどうなるか、です。本文では「もう1つの道」として名前を出しておきながら、そちらは一度も測っていませんでした。

測りました。対象はこのサイト(prodnote)自身です。

先に、結果だけ

機械              開発機。WSL2 Ubuntu / メモリ 7,942 MiB / 4コア
対象              prodnote(Next.js 15.5 の静的エクスポート・記事12本)
コマンド           .next を消してから npm run build

終了コード          0
所要時間           29.22秒
ピークRSS          529,748 KB(= 517 MiB)
CPU使用率          191%
available         7,474 → 6,903 MiB   ビルド中の最小値。571MiB 減った
スワップ            0 → 0 MiB          増えていない
Major page faults  24
サンプル            1秒間隔で30点

ビルド後のサイズ     .next 94MB / out 5.7MB / node_modules 598MB

スワップは動きませんでした。前の記事でいちばん引っかかっていた数字が、こちらでは 0 のままです。

何を、どう測ったか

記事12 と同じ scripts/measure-build.sh に包みました。中でビルドを実行しながら、1秒ごとに free の値を書き出すだけのスクリプトです。方法を揃えたのは、数字の出どころを同じにしておきたかったからです。

サンプルは30点しかありません。ビルドが29秒で終わるので、1秒間隔ではこれ以上取れません。記事12 は205点でした。ここは記録の細かさが違います。

.next を先に消したのは、前の記事の --no-cache と同じ理由です。残っているものに当たると、測っているのがビルドなのかキャッシュの読み出しなのか分からなくなります。

ただし node_modules は消していません。598MB がそのまま置いてある状態からの計測です。記事12 のほうは npm ci から走っているので、ここは条件が違います。

この2つは比べられません

条件が3つ違います。

prodnote(今回)記事12(サーバーの中)
機械開発機 8GB / 4コアVPS 2GB / 3コア
アプリ静的エクスポートフロントエンドのビルド(6コンテナが動いている箱の中で)
工程node_modules は既にある--no-cachenpm ci から

29.22秒と3分26秒を並べて「外のほうが速い」と読むことはできません。別の機械で、別のものを、別の工程で測った2つの数字です。

比べられるのは、測り方の限界のほうでした。

記事12 で取れなかった数字が、今回は取れた

前の記事には、失敗の記録が1つ入っています。ピークRSSを取ろうとして、7,168 KB という値が出てきた件です。

記事12   ピークRSS 7,168 KB    docker CLI 自身の値
今回     ピークRSS 529,748 KB  = 517 MiB

/usr/bin/time -v は、包んだプロセスとその子プロセスまでを見ます。ところが docker build の実体は Docker のビルドエンジンが別に走らせるので、time から見える範囲の外に出てしまいます。返ってきていたのは、命令を出した側のコマンドが使ったメモリでした。

今回は npm run build を直接包みました。ビルドはその子プロセスとして走るので、time が届きます。517MiB という数字は、こうして初めて手に入りました。

同じことを測ろうとして、片方は届いて片方は届きませんでした。道具の届く範囲は、包み方で変わります。

足すとどうなるか(ここからは推定です)

ここから先は実測ではありません。2つの数字を並べただけの計算です。

記事12 の実測   VPSのビルド中に available が 578MiB 減り、470MiB まで落ちた
今回の実測      prodnote のビルドは、ピークで 517MiB を載せた
単純に足すと    1,095 MiB
              ビルド前の available は 1,048 MiB だった

足すと超えます。ただ、これは同居させて測った結果ではありません。

⚠️ 機械が違い、アプリが違い、工程も違う数字を足しています。そのうえ、足している2つは別々の指標です。 片方は available の減り方で、もう片方はピークRSSです。

この2つが別物であることは、今回の記録が自分で示しています。available は571MiB 減りましたが、ピークRSSは517MiB でした。54MiB ずれています。 available の減り方はシステム全体の増減で、プロセス1つが載せた量そのものを表す数字ではありません(available が見積もりであることは前の記事に書きました)。54MiB の内訳までは、この記録では切り分けていません。

実際に同じ箱へ入れれば、ページキャッシュの取り合いや、ビルドの重い区間が重なるかどうかで結果は変わります。「収まらない」とは書けません。 単純に足すとこうなる、というところまでです。

確かめる方法はあります。あのVPSに prodnote を置いて、両方のビルドを同時に走らせればいい。やっていません。稼働中のサイトが載っている箱なので、そこで実験はしないことにしました。

そもそも、このサイトには本番サーバーが無い

ここまで「サーバーの外でビルドする」と書いてきましたが、prodnote の場合、外に出したのはビルドだけではありません。

記事を書いて GitHub に push すると、Cloudflare Pages がビルドと配信をやります。私が持っているサーバーは、この工程のどこにも出てきません。ビルドが1バイトも乗らないのではなく、乗る先が無いのです。

公式のドキュメントには、無料プランの制限がこう書かれています(2026年9月2日に確認)。

Free: Builds 1 build at a time / Builds per month 500 Builds will timeout after 20 minutes.

Cloudflare Docs — Pages Limits

同時に1つ、月に500回、20分でタイムアウトします。記事を書いて push する頻度なら、月500回は当たりません。

⚠️ ビルド機のメモリとCPUがいくつなのかは、公式ドキュメントの中で見つけられませんでした。 書かれていないと言い切るつもりはありません。私が探した範囲で見つからなかった、というだけです。

向こうの機械の数字も見ました。前の記事を公開したときのデプロイ(2026年8月30日)の内訳です。

工程時間
initialize3秒
clone repo2秒
build59秒
deploy9秒
合計1分13秒

ビルドは59秒でした。 20分のタイムアウトに対して、5%ほどです。

⚠️ 手元の29秒と並べて「向こうが遅い」とは読まないでください。 Cloudflare は毎回まっさらな clone から始めるので、この59秒の中では依存パッケージの取得も走っているはずです。⚠️ ログの内訳までは見ていません。手元は node_modules が既にある状態で測りました。工程が違います。

また、59秒は記事12本のときの数字です。記事が増えれば伸びます。

記事01 でやめた判断の、材料が1つ増えた

このサイトを作ったとき、最初は稼働中のVPSに同居させるつもりでした。やめた理由を1本目の記事にこう書いています。

2GB のうち既存の Postgres + Django + Next.js + nginx で大半を使っている

当時これは、動かしている感触からの判断でした。メモリを測ったわけでも、ビルドを走らせて比べたわけでもありません。

今回の517MiB と、記事12 の578MiB が、あとから材料として出てきた形になります。⚠️ 前者はピークRSS、後者は available の減り方で、種類の違う数字です。ただ、これで当時の判断が正しかったと証明されたわけではありません。同居させて測っていない以上、証明にはなりようがない。やめたので、やめなかった場合が観測できない。 そういう種類の判断でした。

言えるのは、当時は根拠なしに避けたつもりだったものに、数字が2つ付いたということだけです。

ビルドの置き場所は、プランより先に決まる

記事12 の最後に、こう書きました。

決めるときに先に見るのは、プランの数字よりも「どこでビルドするか」だと思います。

今回測ってみて、その順番は変えなくていいと思っています。理由は速さではなく、測れる場所が変わるからです。

サーバーの中でビルドすると、そのビルドは稼働しているアプリと同じメモリを取り合います。記事12 でスワップが140MiB増えたのは、取り合った結果です。外に出すと、その取り合いが消えます。消えたぶん、サーバー側で見るべき数字は稼働時のメモリだけになります。

代わりに、別の制限が付いてきます。Cloudflare Pages なら月500回と20分。そして、見るたびに中身が変わるページは静的に書き出せません。この線引きは記事02の後半に書いたとおりで、データベースの有無ではなく、中身がいつ決まるかで分かれます。

置き場所を決めないままプランを選ぶと、必要なメモリの見積もりが立たない。今回の計測は、そのことを裏返しから確かめただけだとも言えます。

私の環境にあって、あなたの環境に無いかもしれないもの

同じ数字にならない条件を並べておきます。

  • 開発機のメモリが 7,942MiB あり、ビルド前の available は 7,474MiB でした。スワップに逃がす場面が来ていません。手元のPCが2GBや4GBなら、この記録は参考になりません
  • node_modules が 598MB、既に展開済みの状態から始めています。まっさらな npm ci からだと、これより時間もメモリも要ります
  • 記事が12本です。記事数が増えれば書き出すページも増えます
  • 画像は別のコマンドで先に作ってあり、next.config.ts でも最適化を切っています(images: { unoptimized: true })。ビルドの中で画像を変換する構成なら、そのぶんが乗ります
  • 型チェックと ESLint は切っていません。next build の中で走るので、29秒にはその時間も入っています
  • 記事本文は react-markdown でビルド時に HTML にしています。Markdown の処理系が違えば、ここの重さも違います
  • CSS は Tailwind CSS と PostCSS で、ビルドの中で生成しています。CSSの作り方が違えば、この時間も違います
  • データベースを使っていません。ビルド中に外部へ問い合わせる処理がゼロです
  • Web フォントを読み込んでいません。フォントのサブセット化を挟む構成なら、その分が乗ります
  • Node のヒープ上限を掛けていません。NODE_OPTIONS の指定はこのリポジトリのどこにもありません
  • WSL2 の上の Ubuntu です。Windows のファイルシステムをまたぐ構成だと、ディスクI/Oの条件が変わります

測っていないこと、書けないこと

  • 同居させた場合の実測。 上に書いたとおりです。足し算までしかしていません
  • Cloudflare Pages のビルド機のスペック。 公式ドキュメントで見つけられませんでした。⚠️ 「無い」ではなく「見つけられなかった」です。 ビルド時間のほうは1回ぶんを見ました(59秒)が、何回か回して振れ幅を見たわけではありません
  • 他社のホスティング。 使っていないので数字がありません。仕様の比較もしていません
  • ⚠️ 開発機の Node のバージョンは、計測中に記録し忘れました。 測り終えたあとに確認して v20.20.2(npm 10.8.2)でした。環境は計測の前後で変えていないので同じはずですが、計測の記録として取ったものではありません。バージョン差が出る計測なら、押さえておくべき項目でした
  • 複数回の計測。 1回きりです。29秒の処理なので繰り返せるはずで、やっていないのはこちらの手落ちです
  • npm run build の内訳。 30点のサンプルはありますが、どの工程でピークが来たかまでは切り分けていません

まとめ

  • サーバーの外(開発機)で prodnote をコールドビルドし、29.22秒・終了コード 0・ピークRSS 517MiB。スワップは 0 のまま動かなかった
  • 記事12 で取り逃がしたピークRSSが、今回は取れた。docker buildtime で包むと届かず、npm run build を直接包むと届く
  • ⚠️ 記事12 の数字とは、機械もアプリも工程も違う。速い遅いの比較には使えない
  • 2つを足すと 1,095MiB でビルド前の available を超えるが、これは推定。同居させて測っていない
  • このサイトには本番サーバーが無い。向こうのビルドは59秒で、20分の制限に対して5%ほど。⚠️ ビルド機のスペックは公式で見つけられなかった