- 第14回スコープ・学習目標・今ここマップ
- Namespace 概念 — マルチテナント分離の基本単位
- ResourceQuota の仕組み — Namespace 全体の予算管理
- やってみよう①: dev / prod Namespace 作成 + 基本確認
- LimitRange の仕組み — Pod / Container のデフォルト値と制約
- やってみよう②: dev に ResourceQuota + LimitRange 適用 + nginx Pod デプロイ
- ResourceQuota と LimitRange の相互作用 — 設計上の落とし穴
- やってみよう③: Quota 超過エラーの観察と修正手順
- ep14 完了後のクリーンアップ — dev / prod Namespace 削除
- CKAD 試験頻出パターン — Quota 設計と Quota 違反のトラブルシュート
- 本番でのマルチテナント設計(発展)— RBAC・NetworkPolicy・Quota の組合せ
- 現場ヒヤリハット
- ep14 完了後の模擬アプリ状態と第4部完走 + ep15 への橋渡し
- 理解度チェック・第14回まとめ・次回予告・シリーズ一覧
第14回スコープ・学習目標・今ここマップ
動作確認バージョン: K8s v1.35 / kubectl v1.35.0 / kind v0.31.0 / kindest/node:v1.35.0 / Docker CE 29.4.3 / containerd 2.2.3 / AlmaLinux 10.1(kernel 6.12.0-124.55.3.el10_1)(2026-05-13 時点・k8s-ops 実機検証済・SP_vol1-pre-23 起点)
本回は Kubernetes 実践教科書 第1巻(CKAD 対応・全 19 回)の第14回です。第4部「ワークロード戦略」の最終回(3/3)として、これまで default Namespace 内で完結していた fanclub-api 環境に対し、Namespace 分離・ResourceQuota・LimitRange の 3 機構を導入していきます。
CKAD ドメイン D4「Application Environment, Configuration and Security」(出題比率 25 %)の Competency「リソース要件・制限・クォータの定義と管理」と「Kubernetes Namespace の知識」を本回で網羅し、第4部の完走と第5部「セキュリティ基礎」(RBAC + NetworkPolicy)への橋渡しを完了します。
第13回からの継承状態確認(SP_vol1-pre-23 状態):
| 項目 | 状態 | 出典 |
|---|---|---|
| kind クラスタ | kind-control-plane Ready(v1.35.0) | Lead 実機観察 |
| Namespace 一覧 | default / kube-node-lease / kube-public / kube-system / local-path-storage(合計 5 個) | ep13 完了状態 |
| ResourceQuota | なし(全 Namespace で 0 件) | Lead 実機観察 |
| LimitRange | なし(全 Namespace で 0 件) | Lead 実機観察 |
| Allocated CPU | 1550m / 2000m(77 %) | Lead 実機観察 |
| fanclub-backend Deployment | replicas: 2 / 3 Probe 設定済 / RollingUpdate maxSurge:1 maxUnavailable:0 | ep12 完了状態 |
| fanclub-db StatefulSet | fanclub-db-0 Pod Running(PostgreSQL 18) | ep9 から継続 |
| node-logger DaemonSet | 1 Pod Running | ep11 から継続 |
| ConfigMap / Secret / SA | fanclub-config / fanclub-secret / fanclub-backend-sa(default ns) | ep10 から継続 |
| CronJob | fanclub-member-count(Suspend: True) | ep11 から継続 |
今ここマップ(第1巻 19 回中の現在位置):
第1部 コンテナとDocker
第1回〜第4回 [完了]
第2部 Kubernetes基礎
第5回〜第6回 [完了]
第3部 アプリリソース
第7回〜第11回 [完了]
第4部 ワークロード戦略(第12〜14回)
第12回: Deployment + 3 Probe + Rolling Update + Probe デバッグ実践 [完了]
第13回: Deployment 戦略補完(Blue/Green + Canary + Recreate) [完了]
★ 第14回: ResourceQuota + LimitRange + Multi-tenant Namespace ← 今ここ
第5部 セキュリティ基礎(第15〜16回)
第6部 パッケージ管理 + HTTPS公開(第17〜19回)
第14回を終えると、以下を習得した状態になります。
- Namespace の概念とマルチテナント分離の役割を説明できる。
kubectl create namespaceで新規 Namespace を作成し、kubectl config set-context --current --namespace=<name>でデフォルト Namespace を切り替えて CKAD 試験本番の時間短縮テクニックを使える - ResourceQuota の YAML 構造(
spec.hard.requests.cpu/requests.memory/limits.cpu/limits.memory/count/pods等)を理解し、Namespace 単位での CPU / Memory / Pod 数 / リソース種別カウントの上限を設定できる - LimitRange の YAML 構造(
type: Container/default/defaultRequest/max/min)を理解し、Pod / Container のデフォルト requests・limits とハード上限・下限を設定できる。default(limits のデフォルト)とdefaultRequest(requests のデフォルト)の違いを混同せずに使える - ResourceQuota と LimitRange の相互作用を理解できる。Quota が
requests.cpu等を制限する Namespace では Container の resources 明示が必須になる仕組みと、LimitRange の defaultRequest が回避策になる関係を実機エラー観察ベースで説明できる - CKAD 試験 D4「リソース要件・制限・クォータの定義と管理」Competency に対応できる。Quota 違反時の
Forbiddenエラーを読解して、LimitRange max 違反と ResourceQuota 違反を即座に判別できる
模擬アプリ進捗(第14回):第13回で Recreate / Blue/Green / Canary の 3 戦略を体験し、第4部のリリース戦略パートが完了しました。
本回の演習は「マルチテナント分離の仕組み」を学ぶことが目的で、fanclub-backend 本体には触れず、新規作成する dev / prod Namespace 上で nginx ベースの Pod を使って Quota と LimitRange の挙動を観察します。
fanclub-api を dev / prod にデプロイし直す形にすると DB 接続(fanclub-db の Namespace 越えアクセス)などの論点が混ざって複雑度が上がるため、本回は意図的に nginx で機構の挙動に集中します。
第14回完了後の模擬アプリ状態:演習で作成した dev / prod Namespace は H2「ep14 完了後のクリーンアップ」で kubectl delete namespace によって一括削除します。
default ns の fanclub-backend / fanclub-db / node-logger は ep13 完了状態のまま影響を受けず、ep15(RBAC + SecurityContext + Admission Controller + CRD 利用)にクリーンな状態で引き継ぎます。
Namespace 概念 — マルチテナント分離の基本単位
個別の演習に入る前に、本回の中心概念である Namespace を整理します。Namespace は K8s クラスタ内のリソースを論理的に分離する単位で、本シリーズで初出となります。
第7回〜ep13 までの演習はすべて default Namespace 内で完結していましたが、本回では dev / prod という名前で新規 Namespace を 2 つ作成し、ResourceQuota / LimitRange を Namespace スコープで適用していきます。
Namespace が解決する 5 つの問題
Namespace は単なる「リソース整理用のフォルダ」ではなく、K8s クラスタの主要な機構を Namespace 単位でスコープ化するための基盤です。具体的には以下 5 つの問題を解決します。
| 役割 | 説明 | 本シリーズの初出回 |
|---|---|---|
| リソース論理分離 | 同名 Pod / Service / Deployment を異なる Namespace に共存させられる。dev/fanclub-backend と prod/fanclub-backend を同時運用するパターン | 本回(ep14) |
| 名前競合回避 | チーム A の web Service とチーム B の web Service が同一クラスタで衝突しない | 本回(ep14) |
| Quota スコープ | ResourceQuota は Namespace スコープのリソース。CPU / Memory / Pod 数の上限を Namespace ごとに独立設定できる | 本回(ep14) |
| RBAC スコープ | Role / RoleBinding は Namespace スコープ。「dev では全権・prod では read-only」のような権限分離が可能 | 第15回 |
| NetworkPolicy スコープ | NetworkPolicy は Namespace スコープ。「dev Pod は dev 内のみ・prod Pod は prod 内のみ」のような通信制限が可能 | 第16回 |
本回で扱う ResourceQuota / LimitRange は上記 3 つ目の「Quota スコープ」に該当します。第15回・第16回で扱う RBAC / NetworkPolicy も Namespace スコープの機構で、本回で確立する dev / prod という Namespace 分離パターンが後続回の前提になります。
本回で Namespace の境界を実機で確認しておくと、第5部のセキュリティ機構が頭に入りやすくなります。
Namespace スコープリソース vs クラスタスコープリソース
K8s のリソースは「Namespace スコープ」と「クラスタスコープ」の 2 種類に分かれます。CKAD 試験では「次のうち Namespace スコープのリソースはどれか」を問う設問が定番のため、両者の区別を頭に入れておくと得点が安定します。
| Namespace スコープ | クラスタスコープ |
|---|---|
| Pod / ReplicaSet / Deployment / StatefulSet / DaemonSet | Node |
| Service / Endpoints / EndpointSlice | PersistentVolume |
| ConfigMap / Secret / ServiceAccount | StorageClass |
| Job / CronJob | Namespace 自身 |
| Role / RoleBinding(第15回) | ClusterRole / ClusterRoleBinding(第15回) |
| NetworkPolicy(第16回) | CustomResourceDefinition (CRD) |
| ResourceQuota / LimitRange(本回) | PriorityClass / IngressClass / GatewayClass |
| PersistentVolumeClaim | — |

記憶のコツは「ワークロード(Pod 系)と設定(ConfigMap / Secret 系)は Namespace スコープ、物理リソース(Node / PV / StorageClass)はクラスタスコープ」というルールです。
例外的に PVC は Namespace スコープで PV はクラスタスコープになっており、PVC が PV を claim する関係でブリッジするのが第9回で扱った設計でした。本回の ResourceQuota / LimitRange は「Namespace スコープのリソース」グループに属します。
既存の 5 つの Namespace の役割
本回の演習に入る前の kind クラスタには、すでに 5 つの Namespace が存在しています。それぞれの役割を整理しておくと、kubectl get namespaces の出力で迷わなくなります。
| Namespace | 役割 | 本シリーズでの扱い |
|---|---|---|
default | ユーザーワークロードのデフォルト配置先。-n を指定しないコマンドが対象とする Namespace | 第7回〜ep13 の全演習で使用 |
kube-system | K8s 自身のシステムワークロード(coredns / kube-proxy / kindnet / etcd / kube-apiserver / kube-controller-manager / kube-scheduler) | 第6回・第12回で観察・本回でも触れない |
kube-node-lease | Node のハートビート用 Lease オブジェクトを格納(K8s v1.14+ の高速 Node 障害検知に使用) | 触れない |
kube-public | クラスタ参加情報など全 Service Account から read-only で参照できる公開情報用 | 触れない |
local-path-storage | kind に同梱の local-path-provisioner(PV 自動プロビジョナ)が稼働する Namespace | 第9回で観察済 |
本回ではこの一覧に dev と prod を追加して合計 7 Namespace 構成にし、演習末尾の H2「ep14 完了後のクリーンアップ」で dev / prod を削除して元の 5 Namespace 構成に戻します。kube-system 以下の 4 つは K8s クラスタの基本機構の一部のため、削除すると K8s 自体が壊れます。
default は削除不可能なように API Server がガードしていますが、kube-system を誤って削除すると CoreDNS が消滅して DNS 解決が止まり、クラスタ全体が動作不能になるため触らないのが鉄則です。
Namespace 操作に関する kubectl コマンド早見表
本回で使う Namespace 関連のコマンドをまとめます。CKAD 試験では Namespace を作成する設問や Namespace を切り替えて作業する設問が頻出のため、これらを暗記レベルで打てるようにしておくと時間に余裕が生まれます。
| 操作 | コマンド | 備考 |
|---|---|---|
| Namespace 作成 | kubectl create namespace <name> | YAML 不要・速攻パターン |
| Namespace 一覧 | kubectl get namespaces または kubectl get ns | ns はエイリアス |
| Namespace 詳細 | kubectl describe namespace <name> | Quota / LimitRange も併せて表示される |
| Namespace 切替 | kubectl config set-context --current --namespace=<name> | 現在の context のデフォルト Namespace を変更 |
| 単発で別 Namespace 操作 | kubectl -n <name> <verb> <resource> | 例: kubectl -n dev get pods |
| 全 Namespace 横断検索 | kubectl get pods -A または --all-namespaces | クラスタ全体のリソース確認に |
| Namespace 削除 | kubectl delete namespace <name> | カスケードで Namespace スコープリソースを一括削除 |
CKAD 試験本番では、設問の冒頭で「In namespace foo, create a Pod …」と Namespace が指定されるパターンが頻出です。
毎回 -n foo を打鍵するより、最初に kubectl config set-context --current --namespace=foo でデフォルトを切り替えてしまう方が大幅に時間を節約できます。本回の演習①で実際に試してみます。
ResourceQuota の仕組み — Namespace 全体の予算管理
ResourceQuota は Namespace スコープのオブジェクトで、Namespace 内で消費される CPU / Memory / Pod 数 / その他リソース種別のカウント等に上限を設定するための機構です。
本番では「dev チームには 4 core / 8 GB の予算」「prod チームには 32 core / 64 GB の予算」のように、組織のリソース予算を Namespace 単位の Quota にマッピングするのが定石です。本セクションでは Quota の YAML 構造・主要フィールド・Quota 違反時の挙動を体系的に整理します。
ResourceQuota の YAML 構造(全量・標準形)
ResourceQuota の標準的な YAML を全量で示します。本演習②で実際に作成する dev-resource-quota.yaml はこの構造の一部を使った簡易版です。
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
requests.cpu: "500m"
requests.memory: "1Gi"
limits.cpu: "1"
limits.memory: "2Gi"
count/pods: "3"
count/configmaps: "5"
count/secrets: "5"
count/persistentvolumeclaims: "2"
requests.storage: "5Gi"
kind: ResourceQuota / apiVersion: v1 は K8s core API の所属です。metadata.namespace で「どの Namespace に Quota を適用するか」を明示するのが必須で、本演習では dev を指定します。
spec.hard 配下に「上限値の map」が並ぶ構造で、それぞれのキーが Quota 対象のリソース種別、値が上限値です。
本演習②では requests.cpu / requests.memory / limits.cpu / limits.memory / count/pods / count/configmaps / count/secrets の 7 項目のみ使用し、PVC や storage は省略します。
主要フィールド早見表
ResourceQuota の spec.hard 配下で使える主要キーを整理します。CKAD 試験では「次のうち Quota で制限できないものはどれか」のような選択問題が定番のため、キー名と意味を頭に入れておきます。
| キー | 意味 | 計上対象 |
|---|---|---|
requests.cpu | Namespace 内全 Container の resources.requests.cpu 合計の上限 | Pending + Running の Pod |
requests.memory | Namespace 内全 Container の resources.requests.memory 合計の上限 | Pending + Running の Pod |
limits.cpu | Namespace 内全 Container の resources.limits.cpu 合計の上限 | Pending + Running の Pod |
limits.memory | Namespace 内全 Container の resources.limits.memory 合計の上限 | Pending + Running の Pod |
count/pods | Pod 数の上限(Pending / Running を含む・Succeeded / Failed は除く) | Pod オブジェクト数 |
count/services | Service 数の上限 | Service オブジェクト数 |
count/configmaps | ConfigMap 数の上限 | ConfigMap オブジェクト数 |
count/secrets | Secret 数の上限 | Secret オブジェクト数 |
count/persistentvolumeclaims | PVC 数の上限 | PVC オブジェクト数 |
requests.storage | PVC が要求するストレージ容量合計の上限 | Bound + Pending の PVC |
count/deployments.apps | Deployment 数の上限(リソース種別とグループ名を . 区切りで指定) | Deployment オブジェクト数 |
count/<resource>.<group> | 任意の API リソース種別の数を制限する汎用フォーマット | 該当リソースのオブジェクト数 |
記憶のコツは「requests.X と limits.X は Pod の resources を合算した値、count/X はオブジェクト数」です。
両者は別の概念で、たとえば limits.cpu: 2 と count/pods: 5 を同時に設定すると「Pod 5 個まで AND CPU limits 合計 2 core まで」の AND 条件で制限がかかります。どちらか一方でも超過した時点で新規 Pod 作成が拒否されます。
Quota 違反時の挙動
Quota が上限に達した状態で新規 Pod / Service / その他リソースを作成しようとすると、API Server が Forbidden エラーで作成を拒否します。
kubectl create / kubectl apply / kubectl run のいずれを使っても、API Server レベルで弾かれるため Pod は Pending にもなりません。エラーメッセージ例は本回の演習③で実機観察します。
Deployment 経由でレプリカ数を増やすケースでは挙動が少し異なります。
Deployment 自体の作成は成功しますが、ReplicaSet Controller が Pod を起動しようとした時点で Quota 違反で拒否され、kubectl describe deployment の Events に failed quota: ... exceeded quota のログが大量に並びます。
Pod の数は kubectl get pods で見ると Quota 上限までしか起動していない状態になります。
本番でこのパターンに遭遇すると「Deployment を apply したのに replicas が増えない」と現象だけが見えて原因究明に時間がかかるため、Quota 設計の段階で count/pods と Deployment の spec.replicas の関係を整合させておくのが鉄則です。
1 つの Namespace に複数 Quota を並列定義するパターン
ResourceQuota は 1 Namespace に 1 個までという制約はなく、複数の Quota を並列定義できます。本番でよく使われるパターンは以下の 3 つです。
- QoS Class ごとの Quota:
spec.scopes: [BestEffort]の Quota で BestEffort Pod のみカウント。重要 Pod は Burstable / Guaranteed クラスにして無制限、雑多な検証 Pod は BestEffort で別 Quota の上限まで、のような棲み分けが可能 - PriorityClass ごとの Quota:
spec.scopeSelectorで PriorityClass を絞り込む Quota。優先度の高い Pod 群と通常 Pod 群で別 Quota を割り当てる - Terminating / NotTerminating の Quota:activeDeadlineSeconds を指定した Pod(Terminating 扱い)と永続稼働 Pod(NotTerminating 扱い)で別 Quota。バッチ系と常駐系を別枠管理する
これらは本回の演習範囲を超える応用論点のため、本演習では「1 Namespace × 1 Quota」のシンプル構成で進めます。CKAD 試験でも基本は 1 Quota の問題が出題され、scopes 系は CKA・CKS(第2巻・第3巻)の範囲に踏み込むトピックです。
やってみよう①: dev / prod Namespace 作成 + 基本確認
所要時間目安:約 15 分。dev / prod の 2 つの Namespace を作成し、一覧確認・詳細確認・Namespace 切り替えの基本コマンドを実機で体験します。所要時間の内訳は Namespace 作成 3 分・確認系コマンド 5 分・context 切り替えの試行 5 分・default ns に戻す手順 2 分です。
Step 1: dev / prod Namespace を作成する
目的:本回の演習で使う dev / prod Namespace を新規作成する。kubectl create namespace はワンライナーで完結する速攻パターンで、CKAD 試験本番でも YAML を書かずに済むことが多いです。
実行コマンド:
$ kubectl create namespace dev
$ kubectl create namespace prod
期待される実行結果:
namespace/dev created
namespace/prod created
kubectl create は冪等ではないため、すでに同名の Namespace が存在する状態でもう一度実行すると Error from server (AlreadyExists) エラーになります。
YAML から作成して冪等性を担保したい場合は kubectl apply -f <ns.yaml> または kubectl create namespace <name> --dry-run=client -o yaml | kubectl apply -f - のパターンを使います。本回の演習は試験本番の速攻スタイルに合わせて kubectl create を使います。
Step 2: Namespace 一覧を確認する
目的:dev / prod が新規追加されて合計 7 Namespace 構成になったことを確認する。
実行コマンド:
$ kubectl get namespaces
期待される実行結果:
NAME STATUS AGE
default Active 3d15h
dev Active 5s
kube-node-lease Active 3d15h
kube-public Active 3d15h
kube-system Active 3d15h
local-path-storage Active 3d15h
prod Active 3s
STATUS: Active は Namespace が稼働中であることを示します。kubectl delete namespace で削除リクエストを送ると Terminating ステータスに遷移し、Namespace 内のリソースがすべてカスケード削除されてから Active から消えます。
Terminating のまま長時間止まる場合は、後述の H2「ep14 完了後のクリーンアップ」で扱う finalizer 残留が原因です。
Step 3: dev Namespace の詳細を確認する
目的:作成直後の dev Namespace に対して describe を実行し、ResourceQuota と LimitRange が「まだ設定されていない」素の状態であることを確認する。後続の演習②で Quota / LimitRange を apply した後の出力と比較するための基準となります。
実行コマンド:
$ kubectl describe namespace dev
期待される実行結果:
Name: dev
Labels: kubernetes.io/metadata.name=dev
Annotations: <none>
Status: Active
No resource quota.
No LimitRange resource.
No resource quota. と No LimitRange resource. が表示されているのが、Quota / LimitRange 未設定の状態です。
Labels の kubernetes.io/metadata.name=dev は K8s v1.22+ で自動付与されるラベルで、NetworkPolicy(第16回)で「特定 Namespace のラベルで通信を許可する」というパターンで使用します。第16回の伏線としてここで存在を確認しておきます。
Step 4: kubectl のデフォルト Namespace を dev に切り替える
目的:CKAD 試験本番で時間を稼ぐ速攻テクニックである「context のデフォルト Namespace 切り替え」を試す。試験では設問の冒頭で「In namespace foo, …」と指定されることが多く、毎回 -n foo を打鍵するより最初に context のデフォルトを切り替える方が大幅に効率的です。
実行コマンド:
$ kubectl config set-context --current --namespace=dev
$ kubectl config view --minify | grep namespace
期待される実行結果:
Context "kind-kind" modified.
namespace: dev
これ以降、-n を指定しないすべての kubectl コマンドは dev Namespace を対象に動きます。試しに kubectl get pods(-n なし)を実行すると、dev には何も Pod がないので No resources found in dev namespace. という出力になります。
実行コマンド:
$ kubectl get pods
期待される実行結果:
No resources found in dev namespace.
出力末尾の in dev namespace. が、現在の context のデフォルト Namespace が dev になっていることを示しています。default ns に Pod がある状態でも、ここでは見えません。
dev 専念モードに入った状態で演習②に進むのも自然な流れですが、本回では Step 5 でいったん default ns に戻して、本シリーズの一貫したコマンドスタイル(-n dev を明示)で演習②以降を進めます。
Step 5: デフォルト Namespace を default に戻す
目的:本シリーズの一貫したコマンドスタイル(明示的に -n dev を付ける形)に戻すため、context のデフォルト Namespace を default に戻す。後続の演習②以降のコマンドは -n dev を明示する形で記述します。
実行コマンド:
$ kubectl config set-context --current --namespace=default
$ kubectl config view --minify | grep namespace
期待される実行結果:
Context "kind-kind" modified.
namespace: default
これで演習①は完了です。dev / prod Namespace が空の状態で 2 つ作成され、現在の context のデフォルトは default ns に戻っています。
CKAD 試験本番では Step 4 の set-context --current --namespace=<name> を試験開始直後に打鍵することで設問ごとの -n 打鍵を省略できる、というテクニックを覚えておいてください。
LimitRange の仕組み — Pod / Container のデフォルト値と制約
LimitRange は Namespace スコープの Admission 系オブジェクトで、Pod / Container / PVC の作成時に「resources 値の自動補完」と「max / min による強制制約」の 2 つの役割を果たします。
ResourceQuota が「Namespace 全体の予算」を管理するのに対し、LimitRange は「個別 Pod / Container のデフォルトと範囲」を管理する位置付けで、両者は補完関係にあります。
本セクションでは LimitRange の YAML 構造・主要フィールド・default と defaultRequest の混同予防を整理します。
LimitRange の YAML 構造(全量・標準形)
LimitRange の標準的な YAML を全量で示します。本演習②で実際に作成する dev-limit-range.yaml はこの構造の maxLimitRequestRatio を省略した版です。
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: dev
spec:
limits:
- type: Container
default:
cpu: "200m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "500m"
memory: "512Mi"
min:
cpu: "10m"
memory: "32Mi"
maxLimitRequestRatio:
cpu: "10"
spec.limits は配列で、1 つの LimitRange リソースの中に複数の type(Container / Pod / PersistentVolumeClaim)の制約を並べることができます。本演習では type: Container のみを使い、Container 単位のデフォルト requests / limits と max / min を設定します。
主要フィールド早見表
| フィールド | 意味 | 適用タイミング |
|---|---|---|
type | Container / Pod / PersistentVolumeClaim のいずれか | — |
default | resources.limits 未指定時の自動補完値 | Pod 作成時の Admission |
defaultRequest | resources.requests 未指定時の自動補完値 | Pod 作成時の Admission |
max | requests または limits の強制上限(超過時 Pod 作成 reject) | Pod 作成時の Admission |
min | requests または limits の強制下限(下回ると Pod 作成 reject) | Pod 作成時の Admission |
maxLimitRequestRatio | limits / requests の最大比率(オーバーコミット防止) | Pod 作成時の Admission |
これらは Pod 作成時の Admission Controller(具体的には LimitRanger という名前の Admission Plugin)が動作するタイミングで適用されます。すでに動いている Pod に対して後から LimitRange を変更しても影響は無く、新規に作成される Pod から適用されます。
本回の演習で「LimitRange apply → nginx Pod 作成 → resources が自動補完される」という流れを実機で確認します。
default と defaultRequest の使い分け(CKAD 頻出誤解)
LimitRange で最も混同されるのが default と defaultRequest の違いです。両者は別フィールドで、CKAD 試験で「LimitRange の default は resources.requests のデフォルト値である」という ○× 問題が出題されたら、答えは × です(正しくは limits のデフォルト)。
| LimitRange フィールド | 対応する Pod 側フィールド | 覚え方 |
|---|---|---|
default | resources.limits | 「default」=「limits のデフォルト」(言葉が短い方) |
defaultRequest | resources.requests | 「defaultRequest」=「requests のデフォルト」(明示的にフィールド名に Request が入っている) |
記憶のコツは「フィールド名に Request という単語が入っている方が requests 対応、入っていない方(短い方)が limits 対応」というルールです。
LimitRange 設計時に「requests のデフォルトを設定したいから default に値を書いた」というミスをすると、Pod の resources.limits が補完されるだけで requests は未補完のままになり、ResourceQuota(requests 系を制限する Quota)で Pod 作成が拒否される事故につながります。後述の H2「ResourceQuota と LimitRange の相互作用」でこの落とし穴を実機で再現します。
max を超える Pod 作成の reject 挙動
LimitRange の max を超える resources を持つ Pod を作成しようとすると、API Server レベルで Pod 作成が拒否されます。たとえば max.cpu: "500m" が設定されている Namespace で resources.requests.cpu: 600m の Pod を作成すると、以下のようなエラーが返ります。
Error from server (Forbidden): error when creating "pod.yaml": pods "nginx-too-big" is forbidden:
[maximum cpu usage per Container is 500m, but request is 600m]
このエラーメッセージは「maximum cpu usage per Container is 500m」という形式で、LimitRange の max.cpu が違反対象であることを明示します。
CKAD 試験では「次の Forbidden エラーの原因として最も適切なものはどれか」という設問が出題されることがあり、エラーメッセージのキーワード(maximum ... per Container なら LimitRange max 違反、exceeded quota なら ResourceQuota 違反)を即座に判別できる必要があります。
maxLimitRequestRatio について:LimitRange には maxLimitRequestRatio という「limits / requests の最大比率」を制約するフィールドがあります。
CPU 例で maxLimitRequestRatio.cpu: "10" を設定すると、limits.cpu / requests.cpu > 10 となる Pod の作成が拒否されます。オーバーコミット率を制限してホスト過負荷を予防する目的の機構です。
本演習では maxLimitRequestRatio は省略し、発展トピックとして言及のみに留めます。CKAD 試験範囲外ですが、第2巻(CKA)以降のリソース管理の応用論点として再登場します。
やってみよう②: dev に ResourceQuota + LimitRange 適用 + nginx Pod デプロイ
所要時間目安:約 25 分。dev Namespace に対して ResourceQuota と LimitRange の 2 つの YAML を apply し、その後 resources 未指定の nginx Pod を作成して LimitRange による自動補完を確認します。
Quota の Used 値が増加することも併せて観察し、Quota / LimitRange の相互作用を実機で確認します。所要時間の内訳は YAML 作成 5 分・apply と describe 確認 5 分・nginx Pod 作成 3 分・自動補完確認 5 分・Quota Used 確認 2 分・予備 5 分です。
kind single-node cluster の CPU 制約に関する注意:本演習の kind クラスタは k8s-ops VM 上の Docker 内で単一ノード(kind-control-plane)として稼働しており、Node Allocatable CPU は 2000m です。
default Namespace で fanclub-backend × 2 / fanclub-db-0 / node-logger / kube-system 関連 Pod が合計で約 1550m を占有しているため、dev / prod 用に確保できる CPU 余裕は約 450m に限られます。
本演習の ResourceQuota.spec.hard.requests.cpu を 500m に設定しているのはこの余裕の範囲に収めるための設計判断です。本番クラスタ(Workload Node 数台・各 4 vCPU 以上)では dev Namespace に CPU 4 core 程度の余裕を持たせる Quota 値が一般的です。
本演習の値はあくまで「kind 2 vCPU 環境でも動かせる教育用」の縮小版である点を念頭に進めてください。
Step 1: dev-resource-quota.yaml を作成する
目的:dev Namespace に適用する ResourceQuota の YAML を作成する。~/fanclub-manifests/ ディレクトリ配下に格納し、本シリーズの他の YAML と同じ配置ポリシーを保ちます。
ファイルパス:~/fanclub-manifests/dev-resource-quota.yaml
ファイル内容(全量):
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
requests.cpu: "500m"
requests.memory: "1Gi"
limits.cpu: "1"
limits.memory: "2Gi"
count/pods: "3"
count/configmaps: "5"
count/secrets: "5"
本演習の Quota 設計値の意図は次のとおりです。
requests.cpu: 500m は kind 2 vCPU 制約に対応した教育用の縮小値で、本演習で起動する nginx Pod 3 個(後述の演習③で 1 個 + 2 個 + さらに 1 個試行)の合計 requests.cpu が 100m × 3 = 300m となり、500m の枠内に収まる設計です。
count/pods: 3 は演習③で意図的に超過させて Forbidden エラーを観察するための上限です。
count/configmaps: 5 / count/secrets: 5 は dev Namespace に設定ファイルが無秩序に増えることを抑制する設計で、kube-root-ca.crt(K8s が Namespace 作成時に自動配置する ConfigMap)が 1 つすでに存在するため Used は 1 から始まります。
Step 2: dev-limit-range.yaml を作成する
目的:dev Namespace に適用する LimitRange の YAML を作成する。default / defaultRequest の自動補完と max / min の強制制約を併用し、本演習の Quota 設計と整合する範囲に設定します。
ファイルパス:~/fanclub-manifests/dev-limit-range.yaml
ファイル内容(全量):
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: dev
spec:
limits:
- type: Container
default:
cpu: "200m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "500m"
memory: "512Mi"
min:
cpu: "10m"
memory: "32Mi"
本演習の LimitRange 設計値の意図は次のとおりです。defaultRequest.cpu: 100m は ResourceQuota の requests.cpu: 500m 枠に Pod 5 個まで収まる値(500 / 100 = 5)で、count/pods: 3 の上限と整合します。
default.cpu: 200m は defaultRequest の 2 倍に設定しており、limits / requests のオーバーコミット比 = 2 で適切な範囲です。max.cpu: 500m は単一 Container が ResourceQuota 全体の requests.cpu: 500m を 1 個で食い潰すことを防ぐ上限です。
min.cpu: 10m は逆に「あまりにも小さい requests で大量の Pod を起動する」状況を予防する下限です。
Step 3: 2 つの YAML を apply する
目的:作成した ResourceQuota と LimitRange を dev Namespace に適用する。両者を併用することで、後続の Step で「resources 未指定の nginx Pod が LimitRange の defaultRequest / default で自動補完されて Quota にカウントされる」流れを観察できます。
実行コマンド:
$ kubectl apply -f ~/fanclub-manifests/dev-resource-quota.yaml
$ kubectl apply -f ~/fanclub-manifests/dev-limit-range.yaml
期待される実行結果:
resourcequota/dev-quota created
limitrange/dev-limits created
2 つのリソースが dev Namespace 内に作成されました。次の Step で kubectl describe namespace dev を実行すると、両者の設定が一括表示されることを確認します。
Step 4: kubectl describe namespace で Quota / LimitRange を確認する
目的:dev Namespace の詳細を表示し、ResourceQuota の Used / Hard と LimitRange の Min / Max / Default Request / Default Limit が併記されることを確認する。
kubectl describe namespace は Quota と LimitRange を一括表示する便利な確認コマンドで、CKAD 試験本番でも頻繁に使います。
実行コマンド:
$ kubectl describe namespace dev
期待される実行結果:
Name: dev
Labels: kubernetes.io/metadata.name=dev
Annotations: <none>
Status: Active
Resource Quotas
Name: dev-quota
Resource Used Hard
-------- --- ---
count/configmaps 1 5
count/pods 0 3
count/secrets 0 5
limits.cpu 0 1
limits.memory 0 2Gi
requests.cpu 0 500m
requests.memory 0 1Gi
Resource Limits
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu 10m 500m 100m 200m -
Container memory 32Mi 512Mi 128Mi 256Mi -
注目ポイントは 3 つあります。1 つ目は Resource Quotas セクションで count/configmaps の Used が 1 になっている点です。
これは K8s v1.21+ が Namespace 作成時に kube-root-ca.crt という ConfigMap を自動配置するためで、Pod が ServiceAccount トークンと一緒に CA 証明書を参照できるようにする仕組みです。
2 つ目は requests.cpu / requests.memory / limits.cpu / limits.memory の Used がすべて 0 である点で、まだ dev に Pod が無いことを反映しています。
3 つ目は Resource Limits セクションが Type: Container の行で表示され、Min / Max / Default Request / Default Limit / Max Limit/Request Ratio の 5 列構成になっている点です。今回の YAML では maxLimitRequestRatio を省略したので最後の列は - 表示です。
Step 5: resources 未指定の nginx Pod を dev に作成する
目的:意図的に resources を一切指定せずに nginx Pod を作成し、LimitRange の defaultRequest / default によって resources が自動補完されることを実機で確認する。本シリーズで初めて「LimitRange による自動補完」を体験する Step です。
実行コマンド:
$ kubectl run nginx-quota-test --image=nginx:1.27-alpine -n dev
期待される実行結果:
pod/nginx-quota-test created
kubectl run で resources を指定しないまま Pod が作成されました。K8s v1.21+ では kubectl run はデフォルトで --restart=Never 相当の単発 Pod を作成します。本演習の目的(LimitRange の自動補完観察)に最適なコマンドです。次の Step で実際に Pod spec を覗いて resources を確認します。
Step 6: Pod の resources を確認して自動補完を検証する
目的:作成された nginx-quota-test Pod の spec を覗いて、resources が空ではなく LimitRange の defaultRequest / default 値で補完されていることを確認する。確認方法は 2 通り示します(jsonpath + jq と yaml + grep)。読者の環境に jq がインストールされていない場合は後者を使ってください。
確認方法 A:-o jsonpath + jq で resources のみ抽出する
実行コマンド:
$ kubectl get pod nginx-quota-test -n dev -o jsonpath='{.spec.containers[0].resources}' | jq
期待される実行結果:
{
"limits": {
"cpu": "200m",
"memory": "256Mi"
},
"requests": {
"cpu": "100m",
"memory": "128Mi"
}
}
確認方法 B:-o yaml + grep -A で resources セクションを抽出する(jq が無い環境向け)
実行コマンド:
$ kubectl get pod nginx-quota-test -n dev -o yaml | grep -A 6 "resources:"
期待される実行結果:
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
どちらの確認方法でも、Pod の spec.containers[0].resources に limits.cpu: 200m / limits.memory: 256Mi / requests.cpu: 100m / requests.memory: 128Mi が入っていることが分かります。
これらは LimitRange で設定した default(limits 用)と defaultRequest(requests 用)の値そのものです。Pod 作成時に LimitRanger Admission Plugin が動作し、spec に resources が無いことを検知して LimitRange の値で補完したのです。
Pod の YAML には resources を一切書いていないのに、API Server 内では値が入っている点が LimitRange の効能の核心です。
Step 7: ResourceQuota の Used 増加を確認する
目的:nginx-quota-test Pod が ResourceQuota にカウントされ、Used 列の値が増えていることを確認する。count/pods / requests.cpu / requests.memory / limits.cpu / limits.memory の 5 項目が増加していれば、Quota の予算管理が正しく機能していることが実機で証明できます。
実行コマンド:
$ kubectl describe resourcequota dev-quota -n dev
期待される実行結果:
Name: dev-quota
Namespace: dev
Resource Used Hard
-------- ---- ----
count/configmaps 1 5
count/pods 1 3
count/secrets 0 5
limits.cpu 200m 1
limits.memory 256Mi 2Gi
requests.cpu 100m 500m
requests.memory 128Mi 1Gi
Step 4 と比較して、count/pods が 0 → 1 / requests.cpu が 0 → 100m / requests.memory が 0 → 128Mi / limits.cpu が 0 → 200m / limits.memory が 0 → 256Mi に変化しています。
この差分が ResourceQuota の効能の核心で、Namespace 単位で「あといくつまで Pod を起動できるか」「あと何 core まで CPU 要求を増やせるか」を一目で把握できるのが本機構の価値です。
Pod の resources を spec に書かなくても LimitRange 経由で値が入り、それが Quota にカウントされて Used 値が増える、という連動を実機で確認できました。
これで演習②は完了です。dev Namespace に Quota / LimitRange / nginx Pod が 1 個ずつ存在する状態で、次の H2「ResourceQuota と LimitRange の相互作用」で両機構の関係をさらに掘り下げ、続く演習③で Quota / LimitRange の上限を超えるリクエストを送って Forbidden エラーを観察します。
ResourceQuota と LimitRange の相互作用 — 設計上の落とし穴
ResourceQuota と LimitRange は別の機構ですが、両者を同時に使うときには「片方の設定が欠けると Pod 作成が一切できなくなる」という強い相互作用があります。
本セクションでは演習②で稼働中の状態から LimitRange を一時的に削除し、resources 未指定の Pod 作成が Forbidden で拒否される様子を実機で再現します。CKAD 試験頻出のハマりポイントで、本番運用でも事故が起きやすい箇所のため、原因と回避策をここで体に染み込ませます。
落とし穴の本質
ResourceQuota で requests.cpu / requests.memory / limits.cpu / limits.memory のいずれかを設定している Namespace では、その Namespace 内で作成される すべての Container に対応する resources の明示が必須になります。
明示しないと API Server が「この Pod を Quota にカウントできない」と判断し、Pod 作成を Forbidden で拒否します。具体的には以下のルールが効きます。
- Quota に
requests.cpuがある → Container にresources.requests.cpuが必須 - Quota に
requests.memoryがある → Container にresources.requests.memoryが必須 - Quota に
limits.cpuがある → Container にresources.limits.cpuが必須 - Quota に
limits.memoryがある → Container にresources.limits.memoryが必須
本演習②の Quota は 4 項目すべてを設定しているため、Container には resources の 4 値全てを明示する必要があります。Pod の YAML を書く側にとってこれは煩雑な要求ですが、回避策が LimitRange の default / defaultRequest です。
LimitRange が「resources 未指定の Pod に自動で値を補完する」仕組みのおかげで、ユーザーが Pod YAML に resources を書かなくても、Admission の段階で補完された値が API Server に届き、Quota にカウントされて Pod が作成されます。

検証フロー — LimitRange を削除して Quota だけ残した状態を作る
この相互作用を実機で確認するため、dev Namespace から LimitRange だけを一時的に削除し、Quota だけ残した状態で resources 未指定の Pod 作成を試みます。期待結果は「Forbidden で reject」です。観察後に LimitRange を再 apply して元に戻します。
Step 1: LimitRange を一時的に削除する
実行コマンド:
$ kubectl delete limitrange dev-limits -n dev
期待される実行結果:
limitrange "dev-limits" deleted from dev namespace
これで dev Namespace は「ResourceQuota だけ存在・LimitRange なし」の状態になりました。すでに稼働中の nginx-quota-test Pod は LimitRange 削除の影響を受けず、resources は補完済みの値(requests.cpu: 100m など)のまま稼働を続けます。
LimitRange が動作するのは「Pod 作成時の Admission」のみで、稼働中の Pod の spec を後から書き換えることはありません。
Step 2: resources 未指定の Pod 作成が reject されることを観察する
実行コマンド:
$ kubectl run nginx-no-resources --image=nginx:1.27-alpine -n dev
期待される実行結果:
Error from server (Forbidden): pods "nginx-no-resources" is forbidden: failed quota: dev-quota: must specify limits.cpu for: nginx-no-resources; limits.memory for: nginx-no-resources; requests.cpu for: nginx-no-resources; requests.memory for: nginx-no-resources
エラーメッセージは「failed quota: dev-quota: must specify limits.cpu for: nginx-no-resources; ...」の形式で、Quota の名前(dev-quota)と「どの resources フィールドが必須なのに不足しているか」を明示します。
本演習の Quota は 4 値全てを設定しているため、4 つすべてが must specify で要求されています。for: の後ろの nginx-no-resources は Container 名で、kubectl run はデフォルトで Pod 名と同じ Container 名を付与するため、ここでは Pod 名と一致しています。
これが LimitRange なしの ResourceQuota が引き起こす実害です。本番でこの状態に陥ると、Deployment の Pod 再起動が一斉に失敗し、replicas が縮小したまま復旧しないという深刻な事故になります(本回の H2「現場ヒヤリハット」で詳述)。
Step 3: LimitRange を再 apply して復旧する
実行コマンド:
$ kubectl apply -f ~/fanclub-manifests/dev-limit-range.yaml
期待される実行結果:
limitrange/dev-limits created
LimitRange が再作成され、これ以降に作成される Pod は resources が自動補完されます。続けて先ほど reject された nginx-no-resources を再度 kubectl run で作成しようとしても、今度は LimitRange が動作するため成功します。
ただし本演習③で Pod 数の上限テストを行う関係上、この再試行は省略します(演習③で Pod を 3 個まで増やす流れと整合させるため)。
本番設計のチェックリスト
この相互作用を踏まえて、本番で ResourceQuota を導入するときのチェックリストを 4 項目で整理します。
- ResourceQuota を有効化する Namespace では必ず LimitRange を併設する。Quota 単独導入は禁忌パターンと位置付け、CI/CD パイプラインで「Quota の YAML が PR に含まれるが LimitRange の YAML が含まれない」状況を検出する pre-commit hook または PR チェックを設置する
- LimitRange は
default(limits 用)とdefaultRequest(requests 用)の両方を必ず設定する。片方だけだと「片方の resources が空のまま Pod が作成されて Quota にカウントされる、もう片方は Quota にカウントできず reject」という中途半端な状態が起きる - LimitRange の
maxを設定して暴走 Pod を予防する。max不設定だと「Quota の枠を 1 Pod で食い潰す」アンチパターンが防げない - Quota 違反の Pod 作成失敗を CI/CD と監視で検知する仕組みを作る。Pod 作成失敗イベントを Prometheus メトリクス(kube-state-metrics の
kube_resourcequota系)から拾い、Used/Hard 比率が 90 % を超えたら Slack 通知する設計が定石。第2巻以降で扱う kube-prometheus-stack で実装する
このチェックリストの 4 項目を本番運用前のリリース判定に組み込んでおくと、Quota 関連の事故をほぼ予防できます。CKAD 試験範囲では 1 〜 3 番目の項目までが頻出で、4 番目(監視連携)は CKA / 第2巻以降のスコープです。
やってみよう③: Quota 超過エラーの観察と修正手順
所要時間目安:約 20 分。本演習では 2 種類の Forbidden エラーを意図的に発生させ、エラーメッセージから「どの機構の違反か」を読み解く練習をします。具体的には ① LimitRange の max.cpu 違反、② ResourceQuota の count/pods 違反、の 2 種類を実機観察し、その後の修正手順を 3 パターン比較します。
所要時間の内訳は LimitRange max 違反試行 5 分・Pod 数違反試行 5 分・Used/Hard 確認 3 分・修正手順比較 5 分・演習③クリーンアップ 2 分です。
Step 1: LimitRange max 違反の観察(limits.cpu: 700m の Pod を作成)
目的:LimitRange の max.cpu: 500m を超える limits.cpu: 700m の Pod を作成しようとして、Forbidden エラーで reject されることを観察する。
エラーメッセージのキーワード「maximum cpu usage per Container is 500m」を頭に入れることで、CKAD 試験で類似のエラーを見たときに即座に LimitRange max 違反だと判別できるようになります。
kubectl run の --overrides オプションを使って Pod spec を JSON で上書きし、resources.requests.cpu: 600m + resources.limits.cpu: 700m を設定して試行します。requests と limits の両方を明示する点に注意してください。
requests だけ大きくして limits を省略すると、LimitRange の default.cpu: 200m が limits に自動補完されてしまい、「requests 600m が limits 200m を超えている」という別の invalid 判定(max 違反到達前)が先に出てしまうためです(参考: The Pod ... is invalid: spec.containers[0].resources.requests: Invalid value: "600m": must be less than or equal to cpu limit of 200m という整合性エラーが LimitRange max のチェック前に発生します)。
実行コマンド:
$ kubectl run nginx-too-big --image=nginx:1.27-alpine -n dev --overrides='{"spec":{"containers":[{"name":"nginx","image":"nginx:1.27-alpine","resources":{"requests":{"cpu":"600m"},"limits":{"cpu":"700m"}}}]}}'
期待される実行結果:
Error from server (Forbidden): pods "nginx-too-big" is forbidden: maximum cpu usage per Container is 500m, but limit is 700m
エラーメッセージの「maximum cpu usage per Container is 500m, but limit is 700m」が、LimitRange の max.cpu 違反を直接示しています。
「maximum ... per Container is X」というキーワードが LimitRange の指標で、後述の Step 2 で観察する「exceeded quota: dev-quota」(ResourceQuota の指標)とは別物です。両者の違いを意識して読むのが試験対応のコツです。
Step 2: ResourceQuota count/pods 違反の観察(4 個目の Pod を作成)
目的:ResourceQuota の count/pods: 3 を超える 4 個目の Pod を作成しようとして、Forbidden エラーで reject されることを観察する。dev Namespace には演習②で作成した nginx-quota-test がすでに 1 個ある状態のため、まず追加で 2 個(合計 3 個)まで起動し、4 個目の試行で reject させます。
実行コマンド:
$ kubectl run nginx-2 --image=nginx:1.27-alpine -n dev
$ kubectl run nginx-3 --image=nginx:1.27-alpine -n dev
$ kubectl run nginx-4 --image=nginx:1.27-alpine -n dev
期待される実行結果:
pod/nginx-2 created
pod/nginx-3 created
Error from server (Forbidden): pods "nginx-4" is forbidden: exceeded quota: dev-quota, requested: count/pods=1, used: count/pods=3, limited: count/pods=3
nginx-2 と nginx-3 は LimitRange の defaultRequest(cpu: 100m / memory: 128Mi)で補完されて Quota の枠内に収まり、無事作成されました。4 個目の nginx-4 で Quota の count/pods: 3 上限に到達して reject されています。
エラーメッセージの「exceeded quota: dev-quota, requested: count/pods=1, used: count/pods=3, limited: count/pods=3」が ResourceQuota 違反を直接示すフォーマットです。
requested(追加で要求された量)、used(現在の使用量)、limited(Quota の上限)の 3 値が出力されるのが特徴で、Step 1 の LimitRange max 違反のメッセージと明確に区別できます。
Step 3: kubectl describe namespace で Used / Hard を確認する
目的:dev Namespace の現在の Quota 使用状況を確認し、count/pods が上限値に到達していることを Used / Hard 列で視覚的に確認する。本番で「Pod が突然作れなくなった」状況に遭遇したときの一次調査コマンドとして使えるパターンです。
実行コマンド:
$ kubectl describe namespace dev
期待される実行結果(抜粋):
Resource Quotas
Name: dev-quota
Resource Used Hard
-------- --- ---
count/configmaps 1 5
count/pods 3 3
count/secrets 0 5
limits.cpu 600m 1
limits.memory 768Mi 2Gi
requests.cpu 300m 500m
requests.memory 384Mi 1Gi
Resource Limits
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu 10m 500m 100m 200m -
Container memory 32Mi 512Mi 128Mi 256Mi -
count/pods が 3 / 3 で上限到達していることが Used / Hard 列で一目瞭然です。
requests.cpu は 3 Pod 分の 100m × 3 = 300m / 500m / limits.cpu は 200m × 3 = 600m / 1 / requests.memory は 128Mi × 3 = 384Mi / 1Gi / limits.memory は 256Mi × 3 = 768Mi / 2Gi、と各値が LimitRange の defaultRequest / default の値そのまま × Pod 数で計算されていることも確認できます。
CKAD 試験で「Namespace の Quota 使用状況を確認するコマンドはどれか」と問われたら、答えは kubectl describe namespace <name> または kubectl describe resourcequota -n <name> です。
Step 4: 修正手順 3 パターンの比較
目的:Quota / LimitRange 違反で Pod 作成ができない状況の修正手順を 3 パターン整理し、それぞれの適用ケースを判別する判断基準を確立する。本番でこの状況に遭遇したときに「どの修正パターンを選ぶべきか」を即決できるようにしておくのが運用上の備えになります。
| 修正パターン | 具体的なコマンド | 適用ケース | 注意点 |
|---|---|---|---|
| ① 既存 Pod を削除して枠を空ける | kubectl delete pod <name> -n <ns> | テスト Pod や不要な Pod が残存しているとき・最小の影響範囲で済む | 本番 Pod を削除すると一時的にサービス影響が出る |
| ② ResourceQuota の Hard 値を増やす | Quota YAML の count/pods 等を増やして kubectl apply | プロジェクト規模拡大・本番運用での恒久的な拡張 | クラスタ全体のリソース余裕を確認してから実施・無制限な拡大はマルチテナント分離の意味を失わせる |
| ③ LimitRange の max を緩和する | LimitRange YAML の max.cpu 等を増やして kubectl apply | 単発の大型 Pod(バッチ処理・ML 学習等)が必要なとき | Pod 1 個で Quota 全体を食い潰す可能性が出るため、Quota 設計との整合を必ず確認 |
本演習では ① のパターンを採用して、不要な nginx-2 / nginx-3 を削除して dev Namespace を Pod 1 個の状態に戻します。② のパターンは「本番運用のキャパシティプランニング」と密接に関連するため、CKAD 試験よりも CKA / 第2巻以降の Quota 拡張運用で頻出のシナリオです。
③ のパターンは「単発バッチ処理向け Namespace で max を緩く設定し直す」のような限定的なユースケースで使います。
Step 5: 演習③のクリーンアップ — 追加で起動した nginx Pod を削除する
目的:dev Namespace に残存している nginx-quota-test / nginx-2 / nginx-3 の 3 個の nginx Pod を削除し、次の H2 のクリーンアップ(Namespace ごと削除)に備える。本 Step は演習③単独のクリーンアップで、次の H2 で dev / prod 両方の Namespace を削除します。
実行コマンド:
$ kubectl delete pod nginx-quota-test nginx-2 nginx-3 -n dev
期待される実行結果:
pod "nginx-quota-test" deleted from dev namespace
pod "nginx-2" deleted from dev namespace
pod "nginx-3" deleted from dev namespace
kubectl v1.35.0 では Pod 削除の出力に from <ns> namespace が付与されます。次に kubectl describe resourcequota dev-quota -n dev で Used が 0 に戻っていることを確認します。
実行コマンド:
$ kubectl describe resourcequota dev-quota -n dev
期待される実行結果:
Name: dev-quota
Namespace: dev
Resource Used Hard
-------- ---- ----
count/configmaps 1 5
count/pods 0 3
count/secrets 0 5
limits.cpu 0 1
limits.memory 0 2Gi
requests.cpu 0 500m
requests.memory 0 1Gi
Pod 3 個を削除したことで count/pods が 3 → 0 に戻り、requests.cpu / requests.memory / limits.cpu / limits.memory も 0 に戻りました。
count/configmaps の 1 は kube-root-ca.crt(K8s 自動生成)が残っているためで、Namespace 削除まで残存します。これで演習③は完了です。
ep14 完了後のクリーンアップ — dev / prod Namespace 削除
3 つの演習が完了したので、本回で作成した dev / prod Namespace を一括削除して、ep15 にクリーンな状態を引き継ぎます。Namespace 削除は K8s の中でも特殊な操作で、対象 Namespace 内の すべての Namespace スコープリソースが自動的にカスケード削除されます。
本回では Quota / LimitRange / Pod / ConfigMap などが対象になりますが、Pod を個別に kubectl delete pod しなくても Namespace 削除だけで一括で消える便利な機構です。
dev / prod Namespace を一括削除する
目的:本回の演習で作成した dev / prod Namespace を 1 コマンドで削除する。Namespace スコープリソース(Pod / Quota / LimitRange / ConfigMap / Secret / Service / SA / RoleBinding 等)はすべてカスケードで削除されます。
クラスタスコープリソース(Node / PV / StorageClass 等)と default Namespace のリソースは影響を受けません。
実行コマンド:
$ kubectl delete namespace dev prod
期待される実行結果:
namespace "dev" deleted
namespace "prod" deleted
削除コマンドの完了までには数秒〜十数秒かかります。これは Namespace 内の各リソースを finalizer 経由で順次削除しているためで、Namespace のステータスは内部的に Active → Terminating → 削除完了の遷移を経ます。
通常はコマンドが返ってきた時点で削除が完了していますが、まれに finalizer が外れずに Terminating のまま止まる事象があります。その場合のリカバリは第2巻(CKA)以降で扱う応用論点になりますが、本演習で発生する可能性は低いため一旦考慮対象外とします。
削除後の Namespace 一覧を確認する
目的:dev / prod が削除され、ep13 完了時点と同じ 5 Namespace 構成に戻っていることを確認する。
実行コマンド:
$ kubectl get namespaces
期待される実行結果:
NAME STATUS AGE
default Active 3d15h
kube-node-lease Active 3d15h
kube-public Active 3d15h
kube-system Active 3d15h
local-path-storage Active 3d15h
5 Namespace 構成(default + kube-* × 3 + local-path-storage)に戻りました。dev / prod は完全に消滅しています。
default Namespace の既存リソースが無影響であることを確認する
目的:dev / prod 削除が default Namespace に影響を与えていないことを確認する。fanclub-backend / fanclub-db / node-logger / Service / ConfigMap / Secret / SA / CronJob はすべて ep13 完了状態のまま稼働しているはずです。
実行コマンド:
$ kubectl get all -n default
期待される実行結果:
NAME READY STATUS RESTARTS AGE
pod/fanclub-backend-deployment-86cf676cf7-abc12 1/1 Running 0 1h
pod/fanclub-backend-deployment-86cf676cf7-def34 1/1 Running 0 1h
pod/fanclub-db-0 1/1 Running 0 3d
pod/node-logger-xkz9p 1/1 Running 0 2d
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/fanclub-backend ClusterIP 10.96.150.60 <none> 80/TCP 3d
service/fanclub-db ClusterIP 10.96.220.110 <none> 5432/TCP 3d
service/fanclub-db-headless ClusterIP None <none> 5432/TCP 3d
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d
NAME DESIRED CURRENT READY AGE
daemonset.apps/node-logger 1 1 1 2d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/fanclub-backend-deployment 2/2 2 2 1h
NAME DESIRED CURRENT READY AGE
replicaset.apps/fanclub-backend-deployment-86cf676cf7 2 2 2 1h
NAME STATEFULSET POD AGE
fanclub-db-0 fanclub-db db 3d
すべて ep13 完了状態のまま稼働中です。fanclub-backend Deployment は replicas: 2 / RollingUpdate maxSurge:1 maxUnavailable:0 / 3 Probe 設定済の状態を維持しています。
fanclub-db StatefulSet も fanclub-db-0 が単独で Running です。node-logger DaemonSet も 1 Pod Running です。これで本回のクリーンアップは完了で、ep15 への引き継ぎ準備が整いました。
CKAD 試験頻出パターン — Quota 設計と Quota 違反のトラブルシュート
本回で扱った 3 機構(Namespace / ResourceQuota / LimitRange)に対応する CKAD 試験での頻出パターンを整理します。
CKAD D4 のうち本回でカバーする「リソース要件・制限・クォータの定義と管理」と「Kubernetes Namespace の知識」の Competency は、選択問題よりも Performance-based 形式(実機で kubectl を操作する形式)で出題されることが多いため、コマンドを暗記レベルで打てるかどうかが得点を左右します。
CKAD 試験頻出パターン 4 選
| # | 問題文のキーワード | 解答パターン | 核心コマンド |
|---|---|---|---|
| 1 | 「Namespace に CPU/Memory 上限を設定せよ」 | ResourceQuota を作成して apply | kubectl create quota <name> --hard=requests.cpu=1,requests.memory=2Gi,pods=10 -n <ns> |
| 2 | 「Pod のデフォルト resources を設定せよ」 | LimitRange を YAML から apply(kubectl create には対応コマンドが無い) | kubectl apply -f limitrange.yaml |
| 3 | 「Quota 違反エラーの原因を特定せよ」 | describe + events で原因把握 | kubectl describe namespace <ns> + kubectl get events -n <ns> |
| 4 | 「Namespace を切り替えて作業せよ」 | context のデフォルト Namespace を変更 | kubectl config set-context --current --namespace=<ns> |
特に重要なのは #1 の kubectl create quota のワンライナーです。試験本番で「Namespace に Quota を設定せよ」と書かれていたら、YAML を書かずに kubectl create quota で即決できると数分の節約になります。
--hard オプションの中身は = 区切り + カンマ区切りで複数項目を並べられ、pods=10 のような短縮表記(count/pods=10 の代わり)も受け付けます。
kubectl 速攻コマンド早見表(本回まとめ)
| 操作 | コマンド |
|---|---|
| Namespace 作成 | kubectl create namespace <name> |
| Namespace 切替 | kubectl config set-context --current --namespace=<name> |
| 現在の Namespace 確認 | kubectl config view --minify | grep namespace |
| ResourceQuota 速攻作成 | kubectl create quota <name> --hard=requests.cpu=1,requests.memory=2Gi,pods=10 -n <ns> |
| Quota / LimitRange 一括確認 | kubectl describe namespace <ns> |
| ResourceQuota 単体確認 | kubectl describe resourcequota -n <ns> |
| LimitRange 単体確認 | kubectl describe limitrange -n <ns> |
| Quota 違反の Events 確認 | kubectl get events -n <ns> --field-selector type=Warning |
| LimitRange YAML 雛形生成 | kubectl explain limitrange.spec.limits でフィールド確認後に手書き |
| Namespace 一括削除 | kubectl delete namespace <name> |
LimitRange だけは kubectl create 系のコマンドが用意されておらず、YAML から apply する必要があります。
試験本番で時間が無いときは、kubectl explain limitrange.spec.limits でフィールド一覧を確認しつつ、最小構成(type / defaultRequest / default のみ)の YAML を手早く書く練習をしておくのが安全策です。
試験中の落とし穴 3 選
- 落とし穴 ①:LimitRange なしの ResourceQuota — Quota だけ設定すると Pod の resources 明示が必須になり、resources 未指定の Pod 作成が一斉に Forbidden で失敗する。CKAD 試験で「Quota だけ設定して Pod が作れない原因を特定せよ」という設問が出題されたら、答えは「LimitRange の defaultRequest / default が未設定」が一定の確率で正解になる。本回 H2「ResourceQuota と LimitRange の相互作用」で実機再現済の論点
- 落とし穴 ②:default と defaultRequest の混同 — LimitRange の
defaultはlimitsのデフォルト、defaultRequestはrequestsのデフォルト。試験本番で逆に書くと、Quota のrequests.cpu制限がある Namespace で Pod が reject される事態になる。フィールド名に「Request」が入っている方が requests 対応と覚えるのが鉄則 - 落とし穴 ③:Namespace スコープと cluster スコープの混同 — ResourceQuota / LimitRange は Namespace スコープ。試験で「クラスタ全体に X の制限を」という設問があれば ResourceQuota では実現できない。各 Namespace ごとに別個に Quota を作る必要がある。LimitRange も同様で「クラスタ全体のデフォルト requests」を設定する K8s 標準機構は存在せず、各 Namespace で個別設定が必要
3 つの落とし穴を意識して本回の演習を一度通すと、CKAD 試験本番でも同種の罠を回避できます。本回の演習②と演習③で実機エラー観察まで体験した経験は、試験で類似の Forbidden エラーを見たときに「あのときのエラーと同じパターンだ」と即座に思い出すための土台になります。
本番でのマルチテナント設計(発展)— RBAC・NetworkPolicy・Quota の組合せ
本回は CKAD 試験対応の最小構成で dev / prod の 2 Namespace 構成で演習を進めましたが、実際の本番運用ではもう少し複雑な設計になります。本セクションでは「本番ではここまで考える」という発展トピックを整理しておきます。
CKAD 試験範囲を一部超える論点ですが、現場で配属された直後に Quota 設計を任される場合の参考に使ってください。第2巻(CKA)以降で本格的に扱うトピックの予告編にもなっています。
dev / staging / prod の 3 環境設計
本演習は dev / prod の 2 環境構成で進めましたが、本番運用では dev / staging / prod の 3 環境分離が標準パターンです。各環境ごとに Namespace を分け、Quota / RBAC / NetworkPolicy をすべて独立して設定します。
Quota 値の目安は以下のとおりです(あくまで一例で、実際の値は組織の規模・ワークロード特性・クラスタの物理リソースで変動します)。
| Namespace | 用途 | requests.cpu 目安 | requests.memory 目安 | count/pods 目安 |
|---|---|---|---|---|
dev | 開発者の試行錯誤・PR ごとのプレビュー環境 | 4 | 8Gi | 30 |
staging | 本番相当の検証・パフォーマンステスト | 8 | 16Gi | 50 |
prod | 本番ワークロード・ユーザートラフィック処理 | 32 | 64Gi | 200 |
dev は試行錯誤の場として比較的小さい Quota を割り当て、staging は本番相当のリソースで負荷試験ができる規模、prod は本番ワークロードに十分なリソース、という階段状の予算配分にするのが定石です。
本演習の kind 2 vCPU 環境では dev に 500m(0.5 core)しか割けませんが、本番クラスタ(Workload Node 3 台 × 各 16 core = 48 core 相当)なら dev に 4 core を割いても全体の 8 % で済むので余裕があります。
RBAC(第15回で扱う)との連携
マルチテナント設計の柱の 1 つが RBAC(Role-Based Access Control)です。本回で確立した Namespace 境界を、第15回で扱う Role / RoleBinding で「誰がどの Namespace で何ができるか」の権限分離に発展させます。典型的なロール設計は以下のとおりです。
- 開発者ロール:dev Namespace で
create/update/deleteの全権、prod Namespace ではget/list/watchの read-only - リリース担当ロール:staging / prod Namespace で Deployment / Service の
create/update、Secret はgetのみ - 監視ロール:全 Namespace で
get/list/watchのみ(Prometheus / Grafana の Service Account に紐づける) - クラスタ管理者ロール:ClusterRole で全 Namespace の全権 + クラスタスコープリソース(Node / PV / StorageClass)の管理
これらのロール設計は第15回で詳しく扱います。本回で「dev / prod という Namespace 境界を作る」基礎を確立したことで、第15回で扱う Role / RoleBinding が「Namespace 内に閉じた権限」として理解しやすくなります。
NetworkPolicy(第16回で扱う)との連携
もう 1 つの柱が NetworkPolicy で、Namespace 間のネットワーク通信を制御します。本回で扱った Namespace スコープのリソース概念がここでも効いてきます。典型的な NetworkPolicy 設計は以下のとおりです。
- dev → dev のみ許可:dev Namespace の Pod は dev 内部の Pod とのみ通信可能・prod の Pod へのアクセスは禁止
- prod → prod 内通信 + 外部 API 許可:prod Pod は prod 内通信に加え、外部の決済 API などへの egress を許可
- Default deny + 個別 allow:デフォルトで全通信を deny し、必要な通信パスだけ allow ルールで開けるホワイトリスト方式が本番のデファクト
- kube-system 経由の DNS:CoreDNS(kube-system Namespace)への 53 番ポート通信は全 Namespace で許可しないと名前解決が止まる
NetworkPolicy は第16回で実機演習します。本回で扱った kubernetes.io/metadata.name=<name> ラベル(Namespace 自動付与ラベル)が NetworkPolicy の namespaceSelector で使われるパターンも第16回で扱います。
Cluster Autoscaler / VPA / HPA との関係
ResourceQuota と相互作用する K8s の自動化機構が 3 つあります。本回の演習範囲を超える発展トピックですが、本番運用設計で考慮すべき論点として整理しておきます。
- Cluster Autoscaler:Pod が Pending(Node 不足)になると Worker Node を自動増設する機構。ResourceQuota の
requests.cpu上限まで Node を増設できるが、Quota 上限に達すると追加 Pod 起動が止まる。Quota 設計時に Node 増設の余地を含めて計算する必要がある - VPA(Vertical Pod Autoscaler):Pod の実測リソース使用量から
resources.requests/limitsを自動調整する機構。LimitRange のmaxに当たると VPA の推奨値が天井に張り付いて自動調整が破綻するため、LimitRange max は VPA の予想最大値より大きく設定する - HPA(Horizontal Pod Autoscaler):CPU 使用率などの指標で Pod の replicas を自動増減する機構。
count/podsの Quota 上限に当たると新 Pod を作れず HPA がストールする(本回ヒヤリハット ② で扱う論点)。maxReplicasとcount/podsの整合は必須
これらの自動化機構は第2巻(CKA)以降で本格的に扱います。本回で「ResourceQuota の上限が新規 Pod 作成を直接ブロックする」仕組みを実機で確認したことが、後続シリーズで自動化機構を扱うときの基礎理解になります。
マルチテナント設計と自動スケーリングは表裏一体の論点で、Quota 設計の段階から HPA / Cluster Autoscaler の最大値を見通しておく設計力が、第2巻以降で問われます。
現場ヒヤリハット
本セクションでは ResourceQuota / LimitRange 周辺で本番運用中に実際に起きやすい事故を 2 件取り上げ、根本原因・解決策・本番ガードレールの 3 点セットで整理します。CKAD 試験範囲を一部超える論点も含みますが、本回で扱った機構が「設計を誤ると本番サービスをダウンさせる」性質を持つことを認識しておくのが重要です。
ヒヤリハット ①: LimitRange なしの ResourceQuota 適用で全 Pod 作成不能
背景:本番運用中の Namespace に「FinOps の予算統制」を理由として後から ResourceQuota を導入した。
Quota の YAML には requests.cpu: 10 / requests.memory: 32Gi / limits.cpu: 20 / limits.memory: 64Gi の 4 項目を設定し、想定リソース使用量に対して余裕を持たせた値で apply した。LimitRange は別チームで管理する予定として、Quota 単独で先に適用した。
事故:Quota apply 直後は既存稼働中の Pod に影響は無く、運用チームは「無事に Quota が入った」と判断した。数時間後、本番 Deployment の 1 つで Pod 再起動が発生した(OOMKill による自動再起動)。
新 Pod を ReplicaSet Controller が作成しようとしたところ、resources 明示が無い Pod だったため Quota 違反で Forbidden 拒否され、Pod が起動しなかった。
kubectl describe deployment の Events に「failed quota: ... must specify requests.cpu for: app; ...」が大量出力。
同時刻に運用中だった他の Deployment も、デプロイトリガーや Node メンテナンスで Pod 再作成が発生すると次々に同じエラーで失敗し、本番のリリースパイプラインが全停止した。
根本原因:LimitRange 未設定の状態で ResourceQuota(requests.cpu / requests.memory / limits.cpu / limits.memory を含む)を適用すると、その Namespace 内の すべての Container で resources の 4 値の明示が必須になる。
既存の Pod は「resources 未明示でも稼働できていた」が、新規 Pod 作成(再起動含む)の瞬間に Quota 違反で reject される。既存 Pod の挙動から「Quota 適用後も問題ない」と誤判断した運用チームの認識ギャップが事故の引き金となった。
解決策:まず緊急対応として、すでに作成済の Quota の requests.cpu / requests.memory / limits.cpu / limits.memory 4 項目を一時的に削除し、count/pods のみで上限を残す形に変更(Pod 数制限だけなら resources 明示は不要)。これでパイプライン復旧。
並行して LimitRange を別 PR で作成し、default / defaultRequest を本番ワークロードの実測中央値で設定。LimitRange が安定稼働を確認した後、Quota の 4 項目を再度元に戻して FinOps 統制を再開した。
本番ガードレール:
- ResourceQuota の
requests.X/limits.X系を導入する場合は、必ず LimitRange と同じ PR / 同じデプロイ単位で apply する。Quota と LimitRange の YAML を別ディレクトリに置く運用は禁止する - CI/CD パイプラインで「ResourceQuota の YAML が PR に含まれるが LimitRange の YAML が含まれない」状況を検出する pre-commit hook を設置する。OPA Gatekeeper / Kyverno(第3巻 CKS で扱う)でクラスタ側 Admission として強制する選択肢もある
- 本番ワークロードのすべての Deployment / StatefulSet / DaemonSet には
resources.requests/resources.limitsの 4 値をすべて明示する。LimitRange 補完は緊急時のフェイルセーフであり、ベストプラクティスは「LimitRange に頼らず明示する」 - Quota apply 後 24 時間は dashboard で Pod 作成失敗イベントを監視する。
kube_resourcequotaメトリクスを Prometheus で監視し、Used / Hard 比率が 90 % を超えたら Slack 通知する
ヒヤリハット ②: count/pods 低設定で HPA が新 Pod を作れない
背景:prod Namespace に ResourceQuota を導入し、count/pods: 10 を上限として設定した。当時の本番 Deployment は replicas: 3 で安定稼働しており、10 という Pod 数は十分に余裕がある値と判断された。
その後、トラフィック増加に備えて HPA(Horizontal Pod Autoscaler)を導入し、maxReplicas: 15 でスケールアウト設定を入れた。HPA の最大値と Quota の count/pods の整合チェックは実施しなかった。
事故:マーケティングキャンペーン開始によりトラフィックが平常時の 5 倍に急増。HPA が CPU 使用率上昇を検知し、Deployment の replicas を 3 → 5 → 8 → 10 と段階的に増やしていった。
しかし replicas 10 で Quota の count/pods: 10 上限に到達し、11 個目以降の Pod 作成が Forbidden で reject。HPA は maxReplicas: 15 を目指して何度もリトライするが Pod は増えず、トラフィック過多で既存 10 Pod が CPU 100 % 飽和。
レスポンスタイムが悪化し、ロードバランサのヘルスチェックで Pod が NotReady 判定され、503 エラーが多発した。
根本原因:HPA の maxReplicas: 15 と ResourceQuota の count/pods: 10 の整合が取れていなかった。HPA は「Quota の上限を考慮せずに replicas を増やそうとする」設計のため、Quota が壁になって新 Pod が作れない状況でも HPA は警告を出さずに silent failure する。
kubectl describe hpa の Events に Pod 作成失敗ログは残るが、運用チームが普段監視している HPA メトリクス(kube_hpa_status_current_replicas 等)には異常として表れにくい。
解決策:緊急対応として ResourceQuota の count/pods を 10 → 30 に増やして apply。HPA が即座に Pod を 15 まで増やし、5 分以内にレスポンスタイムが平常時に戻った。事後の改善として、HPA の maxReplicas 設定値と Quota の count/pods の整合をチェックする自動化を導入。
具体的には HPA YAML の maxReplicas 値を取得し、対応する Namespace の Quota の count/pods が maxReplicas × 1.5 以上であることを検証する pre-commit hook と CI チェックを設置した。
本番ガードレール:
- HPA の
maxReplicasを変更する PR では、同じ PR で対応 Namespace の Quota も見直す。両者の YAML を別ディレクトリに置く運用は禁止する - Quota の
count/podsは HPA のmaxReplicas × 1.5以上を目安に設定し、複数 Deployment が同じ Namespace で HPA する場合は合計値で計算する - HPA + Quota の組合せでは
kubectl get events -n <ns> --field-selector reason=FailedCreateを監視に組み込む。Pod 作成失敗イベントが連続発生したら Slack 通知 - OPA Gatekeeper / Kyverno で「HPA YAML を作成・更新したら対応 Quota が満たされているか自動検証する」Admission ポリシーを実装する。第3巻 CKS で扱う Policy as Code パターン
- 本番への HPA 導入時は負荷試験で Quota 整合をテストする。staging Namespace で同等の負荷をかけ、Quota の
count/podsに当たらないことを事前確認する
2 件のヒヤリハットに共通するのは「ResourceQuota は単独で導入すると本番事故を引き起こす」という性質です。LimitRange とのセット導入、HPA との整合チェック、監視メトリクスの設置、の 3 点が本番運用で Quota を扱う上での必須条件になります。
CKAD 試験範囲では「Quota / LimitRange の設定と動作確認」が中心ですが、本番に出てからは「Quota が引き起こす副作用の予防」がメインの仕事になる、というのが本セクションの実務的な肝です。
ep14 完了後の模擬アプリ状態と第4部完走 + ep15 への橋渡し
本回で第4部「ワークロード戦略」(ep12〜ep14)の 3 回が完走しました。
ep12 の Deployment + 3 Probe + Rolling Update で本番常駐サービスの基盤を、ep13 の Recreate + Blue/Green + Canary でデプロイ戦略の引き出しを、本回(ep14)の ResourceQuota + LimitRange + Multi-tenant Namespace でリソース制限とテナント分離の枠組みを揃えました。
第3部までで揃えたリソース基盤を「本番運用品質」に引き上げる第4部の役割が完了し、次の第5部「セキュリティ基礎」へのバトンタッチに入ります。
ep14 完了後のクラスタ状態
| リソース | 状態 |
|---|---|
| kind クラスタ | kind-control-plane Ready(v1.35.0) |
| Namespace 一覧 | default / kube-node-lease / kube-public / kube-system / local-path-storage(合計 5 個・ep13 完了時と同一) |
| dev / prod Namespace | 削除済(本回 H2「ep14 完了後のクリーンアップ」でカスケード削除) |
| fanclub-backend Deployment | replicas: 2 / 3 Probe 設定済 / RollingUpdate maxSurge:1 maxUnavailable:0(ep12 完了状態を継続) |
| fanclub-backend Service | ClusterIP 10.96.150.60:80 / selector: app: fanclub-backend |
| fanclub-db StatefulSet | fanclub-db-0 Pod Running(PostgreSQL 18) |
| fanclub-db / fanclub-db-headless Service | 継続 |
| postgres-data-fanclub-db-0 PVC | Bound(継続) |
ConfigMap fanclub-config | 4 キー継続(DB_HOST / DB_PORT / DB_NAME / JAVA_OPTS) |
Secret fanclub-secret | 2 キー継続(DB_USER / DB_PASSWORD) |
ServiceAccount fanclub-backend-sa | 継続(automountServiceAccountToken: false) |
DaemonSet node-logger | 1 Pod Running 継続 |
CronJob fanclub-member-count | Suspend: True 継続 |
| members テーブル | 2 行 + score カラム継続 |
default Namespace のすべてのリソースが ep13 完了状態のまま維持されています。本回で作成した dev / prod Namespace は H2「ep14 完了後のクリーンアップ」で削除済で、ep13 までの「default 単独運用」状態にクリーンに戻っています。
ep15 では default Namespace 内の fanclub-backend / fanclub-db を対象に RBAC + SecurityContext の演習に入ります。
CKAD D4 部分網羅の達成
本回(第14回)で CKAD ドメイン D4「Application Environment, Configuration and Security」(出題比率 25 %)のうち、「リソース要件・制限・クォータの定義と管理」と「Kubernetes Namespace の知識」の 2 つの Competency を網羅しました。
D4 の残りの Competency(SecurityContext / ServiceAccount / Admission Controller / CRD)は第15回で扱い、D4 全体の完全網羅は第15回完了時点で達成します。
| CKAD D4 Competency | 習得した回 |
|---|---|
| Define and manage resource requirements, limits and quotas | 第14回(本回) |
| Demonstrate knowledge of Kubernetes Namespaces | 第14回(本回) |
| Provide and manage application configuration via ConfigMaps / Secrets | 第10回(習得済) |
| Define application environment via Pod environment variables and configuration | 第10回(習得済) |
| Understand SecurityContext / Admission Controllers / CRDs | 第15回(次回) |
fanclub-api をどう作ってきたか
第7回: Pod (Backend) 起動
第8回: Service で外部接続性
第9回: StatefulSet (DB) で 3 層構成完成
第10回: ConfigMap / Secret / SA で設定外部化
第11回: Job / CronJob / DaemonSet でバッチ系・デーモン系を追加
第12回: Deployment + 3 Probe で本番常駐サービス化
第13回: Blue/Green + Canary + Recreate の戦略体験
第14回: ★ ResourceQuota + LimitRange + Multi-tenant Namespace ← 今ここ
- dev / prod Namespace を作成して機構を学習
- Quota 違反エラーを実機観察して原因判別力を養成
- 演習後は dev / prod を削除して default 単独運用に戻す
- 第4部「ワークロード戦略」完走
第3部「アプリリソース」(ep7〜ep11)でリソース基盤を整え、第4部「ワークロード戦略」(ep12〜ep14)で本番運用品質に引き上げました。第5部以降はセキュリティ・パッケージ管理・HTTPS 公開の応用に進みます。
第4部全体(ep12〜ep14)の総括
第4部「ワークロード戦略」の 3 回は、第3部までで揃えたリソース基盤を本番運用品質に引き上げるパートでした。各回の到達点を振り返ります。
- ep12:Deployment + 3 Probe + Rolling Update + Probe デバッグ実践 — 自己回復・ヘルスチェック・ゼロダウンタイム更新の基盤を確立。CKAD D2「Application Deployment」の中核を網羅
- ep13:Recreate + Blue/Green + Canary の戦略補完 — リリース戦略の引き出しを 3 戦略追加し、ep12 と合わせて K8s 標準 4 戦略を網羅。CKAD D2 完全網羅を達成
- ep14(本回):ResourceQuota + LimitRange + Multi-tenant Namespace — リソース制限とテナント分離の枠組みを確立。CKAD D4 の中核 2 Competency を網羅
第4部完走の意味は「K8s 上で本番ワークロードを安全に稼働させる基本動作が一通り揃った」ことです。
Deployment で常駐サービスを動かし、Probe で異常を検知し、Rolling Update / Blue/Green / Canary で更新フローを使い分け、ResourceQuota / LimitRange で予算統制を効かせ、Namespace でテナントを分離できる、という基本的な運用品質の枠組みが整いました。
第5部以降は「これらをセキュアにする」「パッケージ管理で再現性を上げる」「外部から HTTPS で公開する」という応用に踏み込みます。
ep15 への橋渡し
第15回では「RBAC + SecurityContext + Admission Controller + CRD 利用」を扱います。本回で確立した Namespace 境界が、第15回の RBAC(Role / RoleBinding が Namespace スコープ)の前提になります。
dev / prod のような Namespace 分離の上で「dev では開発者が全権、prod では read-only」のような権限分離を実装するのが第15回のコア演習です。
- RBAC(Role-Based Access Control):Role / RoleBinding(Namespace スコープ)と ClusterRole / ClusterRoleBinding(クラスタスコープ)の 4 リソースで権限を設計する。fanclub-backend-sa(ep10 で作成)に最小権限を付与する演習を実施
- SecurityContext:Pod / Container の権限を絞る機構。
runAsNonRoot: true/readOnlyRootFilesystem: true/capabilities.drop: [ALL]等の本番ベストプラクティスを fanclub-backend Deployment に適用 - Admission Controller 概念:API Server のリクエスト処理パイプラインに割り込む機構(本回の LimitRanger も Admission Plugin の 1 つ)。MutatingAdmissionWebhook / ValidatingAdmissionWebhook の概要を扱う
- CRD 利用:cert-manager(第18回)が提供する Certificate / Issuer CRD を例に、CRD の存在確認と簡単な操作を扱う
本回の演習で「Namespace 単位の Quota」を実機で体験した経験は、第15回の「Namespace 単位の RBAC」を理解する直接の土台になります。Namespace スコープのリソースという概念が体に染み込んでいると、Role / RoleBinding が「Namespace 内に閉じた権限」として頭に入ります。
理解度チェック・第14回まとめ・次回予告・シリーズ一覧
理解度チェック(○×形式・9 問)
問 1:Namespace は同名 Pod を異なる Namespace に共存させることができる。
問 2:ResourceQuota は Pod の resources.limits の合計に上限を設定できる。
問 3:LimitRange の default は resources.requests のデフォルト値である。
問 4:LimitRange を設定せずに requests.cpu を含む ResourceQuota を有効化すると、Pod の resources 未指定時に Pod 作成が拒否される。
問 5:ResourceQuota はクラスタスコープのリソースである。
問 6:kubectl describe namespace <name> で ResourceQuota と LimitRange の現在の Used / Hard が両方確認できる。
問 7:ResourceQuota の count/pods が 3 の場合、4 個目の Pod 作成は API Server で reject される。
問 8:kubectl delete namespace <name> を実行すると、その Namespace 内の Pod / Service / Deployment は自動的にカスケード削除される。
問 9:HPA の maxReplicas と ResourceQuota の count/pods は独立した機構で、相互に干渉しない。
解答:
| 問 | 解答 | 解説 |
|---|---|---|
| 問 1 | ○ | Namespace は名前競合を回避するための論理分離単位。dev/fanclub-backend と prod/fanclub-backend が同一クラスタで共存できる |
| 問 2 | ○ | ResourceQuota の spec.hard.limits.cpu / limits.memory で Pod の resources.limits 合計に上限を設定可能。requests.X 系も同様 |
| 問 3 | × | default は resources.limits のデフォルト値で、resources.requests のデフォルト値は defaultRequest。フィールド名に「Request」が入っている方が requests 対応と覚える |
| 問 4 | ○ | ResourceQuota が requests.cpu を制限する Namespace では、すべての Container で resources.requests.cpu の明示が必須になる。LimitRange の defaultRequest.cpu を設定すると自動補完されて回避できる |
| 問 5 | × | ResourceQuota は Namespace スコープ。metadata.namespace で適用先の Namespace を指定する。CKAD 試験で頻出の混同パターン |
| 問 6 | ○ | kubectl describe namespace は Resource Quotas セクションと Resource Limits セクションを両方表示する。Quota 違反のトラブルシュート時の一次調査コマンド |
| 問 7 | ○ | count/pods: 3 上限到達後の Pod 作成リクエストは API Server で Forbidden 拒否される。エラーメッセージは「exceeded quota: ... requested: count/pods=1, used: count/pods=3, limited: count/pods=3」 |
| 問 8 | ○ | Namespace 削除は Namespace スコープリソース(Pod / Service / Deployment / Quota / LimitRange / ConfigMap / Secret / SA / RoleBinding 等)をすべてカスケード削除する。クラスタスコープリソース(Node / PV)と他 Namespace のリソースには影響しない |
| 問 9 | × | HPA の maxReplicas が Quota の count/pods を超える設定だと、HPA がスケールアウトしようとして Quota 違反で reject され、HPA がストールする。本回ヒヤリハット ② で扱った論点。両者の整合チェックは必須 |
第14回まとめ
第14回では以下を実施しました。
- Namespace の概念とマルチテナント分離の役割を整理し、Namespace スコープリソース(Pod / Service / Deployment / ResourceQuota / LimitRange 等)とクラスタスコープリソース(Node / PV / StorageClass 等)の対比表を確立した。
kubectl create namespace/kubectl get namespaces/kubectl describe namespace/kubectl config set-context --current --namespace=<name>のコマンド体系を演習①で実機体験し、CKAD 試験本番で時間を稼ぐ Namespace 切り替えテクニックを定着させた - ResourceQuota の YAML 構造と主要フィールド(
requests.cpu/requests.memory/limits.cpu/limits.memory/count/pods/count/configmaps/count/secrets/count/persistentvolumeclaims/requests.storage等)を整理し、Quota 違反時の Forbidden エラー挙動を理解した。1 Namespace に複数 Quota を並列定義する応用パターン(QoS Class / PriorityClass / Terminating スコープ別)も併せて言及した - LimitRange の YAML 構造と主要フィールド(
type/default/defaultRequest/max/min/maxLimitRequestRatio)を整理し、default(limits のデフォルト)とdefaultRequest(requests のデフォルト)の混同予防を強調した。maxLimitRequestRatioは本演習では省略・発展トピックとして言及のみとした - 演習②で dev Namespace に
dev-resource-quota.yaml(requests.cpu: 500m / requests.memory: 1Gi / count/pods: 3)とdev-limit-range.yaml(Container default: 200m/256Mi / defaultRequest: 100m/128Mi / max: 500m/512Mi / min: 10m/32Mi)を apply し、resources 未指定の nginx Pod を作成して LimitRange の自動補完を実機確認した。kubectl get pod -o jsonpath+jqとkubectl get pod -o yaml | grep -A 6の 2 通りの確認方法で resources がrequests: cpu=100m / memory=128Mi、limits: cpu=200m / memory=256Miに補完されることを確認した。ResourceQuota の Used 値がcount/pods: 0 → 1/requests.cpu: 0 → 100m/limits.cpu: 0 → 200mと連動することも確認した - ResourceQuota と LimitRange の相互作用を整理し、LimitRange を一時的に削除して resources 未指定の Pod 作成が「
failed quota: dev-quota: must specify requests.cpu for: nginx; ...」で reject されることを実機再現した。本番設計のチェックリスト 4 項目(Quota と LimitRange のセット導入 / default と defaultRequest の両方設定 / max の上限設定 / 監視メトリクス整備)を確立した - 演習③で 2 種類の Forbidden エラーを意図的に発生させ、エラーメッセージのキーワードから違反元を判別する練習をした。LimitRange max 違反は「
maximum cpu usage per Container is 500m, but request is 600m」、ResourceQuota count/pods 違反は「exceeded quota: dev-quota, requested: count/pods=1, used: count/pods=3, limited: count/pods=3」というメッセージフォーマットの違いを覚えた。修正手順 3 パターン(既存 Pod 削除・Quota 緩和・LimitRange 緩和)の適用ケースを比較した - 現場ヒヤリハットを 2 件扱った。LimitRange 未設定の ResourceQuota 導入で本番 Deployment が全滅した事例、Quota の
count/pods低設定で HPA がストールしてトラフィック過多で 503 多発した事例を、根本原因・解決策・本番ガードレールまで整理した。Quota は単独導入禁止 / HPA との整合チェック必須 / Used/Hard 監視メトリクスの設置、を本番運用の方針として確立した
次回予告
第15回 RBAC + SecurityContext + Admission Controller 概念 + CRD 利用では、本回まで Namespace 境界で扱った fanclub-api 環境にセキュリティの観点を加えます。
RBAC(Role / RoleBinding / ClusterRole / ClusterRoleBinding)でユーザーと Service Account の権限を Namespace 単位で設計し、fanclub-backend-sa(ep10 で作成)に最小権限を付与する演習を実施します。
Pod / Container 単位の SecurityContext(runAsNonRoot / readOnlyRootFilesystem / capabilities)を fanclub-backend Deployment に適用し、Admission Controller の概念(本回の LimitRanger も Admission Plugin の 1 つ)を整理します。
cert-manager(第18回で使用)の Certificate / Issuer を例に CRD の存在確認と利用方法も扱います。
CKAD ドメイン D4「Application Environment, Configuration and Security」(出題比率 25 %)の残りの Competency を本回で完全網羅し、第5部「セキュリティ基礎」の最初の到達点となります。
シリーズ一覧
第1部:コンテナと Docker
- 第1回 コンテナ技術概念 + Docker 環境準備
- 第2回 Docker 基本操作
- 第3回 Dockerfile + マルチステージビルド + JDK 25 / Payara Micro イメージビルド
- 第4回 コンテナレジストリ + イメージタグ戦略 + Trivy スキャン
第2部:Kubernetes 基礎
第3部:アプリリソース
- 第7回 Pod + Multi-container パターン
- 第8回 Service とネットワーキング
- 第9回 ストレージ(PVC + StatefulSet)+ PostgreSQL DB 追加
- 第10回 ConfigMap + Secret + ServiceAccount 基礎
- 第11回 Job + CronJob + DaemonSet
第4部:ワークロード戦略
- 第12回 Deployment + 3 Probe + Rolling Update + Probe デバッグ実践
- 第13回 Deployment 戦略補完(Blue/Green + Canary + Recreate)
- 第14回 ResourceQuota + LimitRange + Multi-tenant Namespace ← 今ここ
