コンテナリソース要求と上限をどこで固めるか

KubernetesのCPU・メモリrequestsとlimitsを正しく設計しないと、Nodeの過負荷や予期しないOOMKillが発生し、本番品質が安定しない。判断の核心は「何を優先し、どの層で制約を持たせるか」という設計の問題にある。LimitRangeによるNamespace内のデフォルト・上限設定、ResourceQuotaによるNamespace間の配分制御、QoS classの選択、VPAの適用範囲という4層の設計を順に固めることが、リソース管理の安定した基盤となる。

requests/limitsの乖離が引き起こす問題と判断軸

設定漏れ・過少設定が生む典型的な障害パターン

requestsを未設定のままにしたコンテナはBestEffort扱いとなり、Nodeのメモリ圧迫時に真っ先にevictされる。CPU requestsの過少設定も問題で、Schedulerが実際の消費量を把握できないため、1つのNodeに過剰な数のPodがスケジューリングされてCPUスロットリングが頻発しやすい。これは「設定値を省略した」という開発側の小さな判断が、本番のレスポンスタイム劣化として現れる典型的な落とし穴だ。OOMKillによるコンテナ再起動は、設定漏れがメモリ側に起きたときの代表的な症状として押さえておく必要がある。

過大設定が引き起こす別の問題

逆にlimitsを過大設定すると、Schedulerが実際には余裕があるNodeを「空きなし」と判断し、PodがPending状態のまま滞留するケースが生じる。30台規模のクラスターでも、全PodのrequestsがNodeのCapacityを超過していれば新規Podは一切スケジューリングされない。「予約超過」と「実使用量乖離」のギャップが、クラスター全体のリソース効率を低下させる。過大設定は過少設定と同様にクラスターの安定を損ない、問題の原因として見落とされやすい点でより厄介な場合がある。

判断軸の整理 — どの層で何を制約するか

設計判断の軸は「誰が設定値に責任を持つか」という所有者の問題と、「何を上限として保護するか」というリソース保護の問題に分解できる。開発チームがManifestを管理する構成なら、デフォルト値はLimitRangeで担保し、Namespace全体の消費上限はResourceQuotaで持つという役割分担が機能しやすい。個別コンテナの設定精度を上げたい場合はVPAを組み合わせる。この3層の設計を先に固めてから各コンテナの数値設定に入ることが、設計の順序として重要になる。

Namespace単位でLimitRangeを使って制約する設計

LimitRangeが解決する「デフォルト値の欠如」問題

LimitRangeはNamespace内のコンテナ・Pod・PVCに対してデフォルト値・最小値・最大値を一括で課す仕組みだ。開発チームがrequests/limitsを未記載のまま適用したManifestも、LimitRangeが自動的にdefaultとdefaultRequestを補完する。これにより「設定漏れのBestEffort Pod」が本番Namespaceに混入する事故を防げる。設定漏れを個別レビューで防ぐより、構造で防ぐほうが運用として堅牢であり、LimitRangeはその設計上の受け皿として機能する。

環境ごとのNamespace分割とLimitRange設計

一般的な構成として、production・staging・developmentを別Namespaceで分割し、それぞれ異なるLimitRangeを適用する方法がある。productionではCPU limitsをrequestsの1.5倍以内に抑え、stagingでは2倍まで許容するなど、環境の性質に合わせた制約の差をLimitRangeで吸収できる。3環境以上を運用するチームでは、LimitRangeのManifestをKustomizeのoverlayで管理すると保守性が高まる。環境ごとの差分をoverlayに集約することで、変更の影響範囲を追跡しやすくなる。

LimitRangeの落とし穴 — デフォルト値の意図しない適用

よくあるつまずきとして、LimitRangeのdefaultを設定した後にrequestsだけを明示的に記載してlimitsを省いたコンテナには、defaultLimitsが自動適用される。しかしdefaultLimitsがrequestsを下回る値に設定されているとKubernetesはValidation Errorを返す。LimitRangeのdefaultとdefaultRequestの整合性は、設定時に必ず検証が必要な点として設計の段階で確認しておく。この挙動を把握していないと、Manifestのapply時に意図せずエラーが出て原因を追いにくい状況に陥りやすい。

ResourceQuotaをNamespace間で配分する判断

ResourceQuotaで守る「Namespace間の公平性」

複数チームが同一クラスターを共有するマルチテナント構成では、1チームが大量のリソースを確保して他チームのPodがスケジューリングできなくなるリスクがある。ResourceQuotaはNamespace単位でCPU/メモリのrequests・limitsの合計に上限を課し、この問題を設計で封じる。LimitRangeがコンテナ単位の制約であるのに対し、ResourceQuotaはNamespace全体の消費量の天井という役割分担を意識することが重要だ。この2層を混同すると、設定が重複したり片方しか機能しない状態に気づかずに運用を続けることになる。

ResourceQuota設計の判断ポイント

ResourceQuotaの数値を決める際は、対象Namespaceの想定ワークロード数とそのrequests/limitsの合計から逆算する方法が基本になる。最大20 Podを想定し、各PodのCPU requestsが250mなら最低でも5 CPU requestsを確保する計算となり、余裕率として20〜30%を加算するのが一般的だ。ResourceQuotaの数値が小さすぎると、Deploymentのローリングアップデート時にSurge PodとTerminating Podが同時に存在してQuotaを超過し、アップデートが途中で停止するという落とし穴がある。ローリングアップデートの挙動を考慮した余白を最初から設計に含めておく。

Quotaの改廃判断をどう運用するか

ResourceQuotaは一度設定すると変更コストが生じるため、初期値の根拠を記録しておくことが重要だ。PrometheusなどでNamespaceごとのrequests/limits使用率を定期的に計測し、使用率が80%を超える状態が続く場合は拡張を検討する目安とするルール化が運用を安定させる。逆に使用率が20%を下回り続けるNamespaceは、統合や縮小の判断材料となる。閾値に基づく定期レビューを組み込むことで、場当たり的なQuota変更を防ぎやすくなる。

QoS classをGuaranteed/Burstable/BestEffortで使い分けるか

3つのQoS classとNodeのリソース圧迫時の挙動

KubernetesはPodのrequests/limits設定から自動的にQoS classを決定する。requests=limitsのコンテナのみで構成されるPodはGuaranteed、requestsはあるが一部でlimitsと不一致のPodはBurstable、requests未設定はBestEffortとなる。Nodeのメモリ圧迫時にOOM Killerが動作する順序はBestEffort→Burstable→Guaranteedとなり、この順序がワークロードの安定性設計に直結する。QoS classは設定者が明示的に指定するものではなく、requests/limitsの組み合わせから自動的に決まるという点を設計の前提として押さえておく。

どのワークロードにGuaranteedを割り当てるか

すべてのPodをGuaranteedにすればevictリスクは最小化できるが、リソース効率は下がる。一般的な判断基準は、本番のstatefulなワークロード(データベースやキャッシュ層)はGuaranteed、バッチジョブや開発環境はBestEffortまたはBurstableに留めるという分類だ。Guaranteed Podが増えるとNodeのリソース予約量が増加し、実際の空きがあってもスケジューリング不能になるため、クラスター全体のGuaranteed率は設計時に意識する必要がある。Guaranteedの適用範囲を絞ることが、全体のリソース効率と可用性のバランスをとる設計の鍵になる。

BestEffortをあえて使う判断

開発Namespaceや検証ジョブでrequestsを意図的に省略してBestEffortにする選択は、リソース効率の観点から有効な設計判断となる場合がある。ただしLimitRangeが適用されているNamespaceではBestEffortにならない点に注意が必要だ。開発環境でBestEffortを許容したい場合は、LimitRangeを適用するNamespaceと適用しないNamespaceを明示的に分ける設計が前提となる。環境ごとの意図を構造で表現しておくことで、意図せずBestEffortが本番に混入するリスクを防げる。

VPA導入の判断 — 自動調整に任せる範囲の見極め

VPAが自動調整する仕組みと向き不向き

VPA(Vertical Pod Autoscaler)は稼働中のPodの実績CPU/メモリ消費量からrecommendationを算出し、requests/limitsを自動更新する。ただしVPAがPodのSpecを書き換える際にはPodの再起動が伴うため、Webサーバーのように常時稼働が前提のワークロードとは相性が悪い。HPAと同一Podに両方を適用するとCPU requestsの変更がHPAのスケール判断を乱すため、HPAでCPUスケールを行う場合はVPAのCPU推薦をOffにする設計が基本となる。この組み合わせの制約は、VPA導入検討の段階で必ず確認する。

VPAをOff/Initial/Autoのどのモードで使うか

VPAにはUpdateMode: Off(推薦値の表示のみ)・Initial(Pod初回起動時のみ適用)・Auto(随時再起動して適用)の3モードがある。本番環境でAutoを適用すると予期しないタイミングでPodが再起動するリスクがあるため、まずOffモードで2〜4週間の推薦値を観察し、自チームのワークロードに適合するか確認してからInitialまたはAutoへの昇格を判断する進め方が安全だ。推薦値の安定性を観察してから自動化の範囲を拡大するというステップを踏むことで、本番への影響を段階的に管理できる。

VPA導入の判断基準 — 運用工数との比較

VPAの導入判断は「手動でrequests/limitsを調整し続ける工数」と「VPAの運用・監視コスト」の比較で行う。Podの種類が50を超えるクラスターでは手動調整の追跡が困難になり、VPAのOffモードを活用した推薦値の定期確認だけでも工数削減の効果が出やすい。一方でPodの種類が10以下であれば、VPAなしで定期的な見直しサイクルを設ける運用で十分対応できるケースが多い。VPA自体も追加コンポーネントとして管理対象になるため、規模に見合った導入判断を行う。

設定値の採取根拠をモニタリングからどう拾うか

採取すべき指標とその解釈

requests/limitsの根拠数値を引き出すには、CPU throttling率とメモリの実使用量ピーク値が主要な指標となる。CPUスロットリングが頻発している場合はlimitsの引き上げまたはHPAの導入を、メモリのrequestsが実使用量の2倍以上になっている場合は過剰予約の解消を検討する。PrometheusのコンテナメトリクスやGrafanaのKubernetes Dashboardでこれらを可視化し、週次または月次でレビューするサイクルを設けることが、設定値を根拠に基づいて管理する土台になる。指標の観察なしに設定値を「なんとなく」決めると、過少・過大の両方向に問題が蓄積しやすい。

percentileを使った設定値の決め方

requestsの設定値はp50(中央値)の実使用量を、limitsはp99の実使用量に余裕率を加えた値を使うアプローチが一般的だ。スパイク型のワークロードではp99がp50の3〜5倍に達するケースもあり、この差が大きいほどBurstableで吸収するかHPAでPod数を増やすかの判断が必要になる。p50とp99の差が2倍未満に収まるワークロードはGuaranteedで固定する設計が安定しやすい。percentileから設定値を決めることで、「感覚値」から「観測値」への移行が設計の再現性を高める。

設定値の見直しサイクルをどう回すか

初期設定値はデプロイ後1〜2週間の観測期間を経て最初の見直しを行う。その後は月次でCPUスロットリング率とメモリOOM件数を確認し、スロットリング率5%超・OOM月2件以上といった閾値を超えた場合に設定変更を検討するルールを設けると、個人の判断に依存しない運用サイクルを組める。変更履歴はManifestのコメントではなく、ADR(Architecture Decision Record)またはRunbookに残すことで、後続メンバーが判断の根拠を追跡できるようになる。設定値の管理をドキュメント化することは、チームの運用知識を属人化させないための設計判断でもある。

ユースケース別requests/limits設定値比較表

想定例として、代表的なワークロード種別ごとのrequests/limits設計方針を整理する。数値はあくまでも設計の出発点となる目安であり、実際の採取はモニタリングのpercentileから行う。

ワークロード種別 requests目安 limits目安 QoS class VPA適用
本番Webアプリ(常時稼働) CPU: 250m / Mem: 256Mi CPU: 500m / Mem: 512Mi Burstable Offモードで観察のみ
DBサイドカー・キャッシュ層 CPU: 500m / Mem: 512Mi CPU: 500m / Mem: 512Mi Guaranteed 不適用
バッチ・定期ジョブ CPU: 100m / Mem: 128Mi CPU: 1000m / Mem: 1Gi Burstable Initialモード可
開発・検証用ワークロード 未設定またはCPU: 50m LimitRangeに委任 BestEffort / Burstable 不適用
HPA管理下のAPIサーバー CPU: 200m / Mem: 256Mi CPU: 800m / Mem: 512Mi Burstable CPUはOff・メモリのみAuto可

設計フェーズで確認すべき判断ポイントを以下にまとめる。

  • LimitRangeのdefaultとdefaultRequestの整合性を検証し、requestsがdefaultLimitsを超えていないか確認したか
  • ResourceQuotaの数値をローリングアップデート時のSurge Pod分まで含めて算出したか
  • HPAと共存するPodにVPAのCPU推薦をOffに設定しているか
  • Guaranteedを割り当てるワークロードとBurstable/BestEffortで許容するワークロードを環境ごとに分類したか
  • requestsのp50根拠・limitsのp99根拠をモニタリングデータから採取したか
  • ResourceQuotaの使用率80%超/20%未満を判断基準として運用ルールに組み込んでいるか
  • 設定値の変更履歴をADRまたはRunbookで管理し、後続メンバーが根拠を追跡できる体制になっているか

▶ 手を動かして本番まで到達する

その設計判断を、RHEL10の本番環境で手を動かして固めませんか

ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。

最大6名の少人数で、構築実務者の到達点まで引き上げます。座学で終わらせず、本番相当の環境で判断を検証する2日間です。

コンテナのrequests/limits設計を実装で確かめる上級Linuxハンズオンへ →

Linuxセミナー上級編(RHEL10)|最大6名の少人数ハンズオン