ข้ามไปยังเนื้อหา

Namespace และ Resource Quota

Namespace แบ่ง object และชื่อของ cluster เดียวให้หลาย user, ทีม หรือโปรเจกต์ใช้ร่วมกัน แต่ไม่ได้แบ่ง network ให้ด้วย ต้องใช้ NetworkPolicy ถึงจะทำได้

Namespace scope ชื่อ ของ object Deployment web ใน namespace team-a กับ Deployment web ใน namespace team-b เป็นคนละ object กันโดยสิ้นเชิง แค่บังเอิญชื่อเหมือนกัน Namespace ยังเป็นหน่วยที่ RBAC (จะพูดถึงใน module ถัดไป) มักถูก scope ไว้ ทำให้สิทธิ์ของแต่ละทีมจำกัดอยู่แค่ namespace ที่ทีมนั้นดูแล ไม่ใช่ทั้ง cluster

สิ่งที่ Namespace ไม่ได้ ให้คือ network isolation โดย default Pod ใน team-a ยังส่ง traffic ไปหา Pod ใน team-b ได้อยู่ดี Namespace เป็นขอบเขตเรื่องชื่อและการจัดระเบียบ ไม่ใช่ขอบเขตเรื่อง network ถ้าอยากบล็อก traffic นั้นต้องใช้ NetworkPolicy ซึ่งอยู่ใน module Networking

apiVersion: v1
kind: Namespace
metadata:
name: team-a
Terminal window
kubectl create namespace team-a
kubectl config set-context --current --namespace=team-a

บาง object เป็น cluster-scoped คืออยู่นอก namespace ไหนเลย เพราะอธิบายแนวคิดระดับ cluster ไม่ใช่สิ่งที่ทีมใดทีมหนึ่งเป็นเจ้าของ Node, PersistentVolume และ ClusterRole ล้วนเป็น cluster-scoped ส่วน object ที่ใช้กันบ่อย ๆ อย่าง Pod, Deployment, Service, ConfigMap, PersistentVolumeClaim เป็น namespaced

Terminal window
# List objects that live outside any namespace
kubectl api-resources --namespaced=false

ResourceQuota จำกัดการใช้ resource รวมทั้งหมดของ namespace หนึ่งตัว คือ CPU กับ memory requests/limits รวมของทุก Pod ใน namespace นั้น และ/หรือจำนวน object รวม เช่น จำนวน Pod, Service หรือ PersistentVolumeClaim สูงสุด

apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "50"
persistentvolumeclaims: "10"

ResourceQuota จำกัดทั้ง namespace รวมกัน แต่ไม่ได้พูดถึง Pod ตัวใดตัวหนึ่งเลย ถ้าไม่มีขอบเขตระดับ object เดียว Pod ที่ไม่ถูกจำกัดตัวเดียวสามารถขอ CPU กับ memory มากพอจะกิน ResourceQuota ทั้ง namespace ไปคนเดียว ทำให้ Pod อื่นในทีมเดียวกันขาดแคลนไปด้วย LimitRange ปิดช่องว่างนี้ด้วยการตั้งค่า default, ขั้นต่ำ และขั้นสูงของ requests/limits สำหรับ Pod และ container แต่ละตัวที่ถูกสร้างใน namespace นั้น

apiVersion: v1
kind: LimitRange
metadata:
name: team-a-limits
namespace: team-a
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 250m
memory: 256Mi
max:
cpu: "2"
memory: 2Gi
min:
cpu: 100m
memory: 128Mi

หมายเหตุ environment: kind cluster ของโมดูลนี้เองผ่านช่วงที่ CPU ขาดแคลนอย่างหนักจากเครื่องที่ใช้ร่วมกันซึ่งรัน kind cluster ของหลาย agent พร้อมกัน (uptime แสดง load average ค้างที่ 20–30 และตรวจตรงด้วย docker exec ... cat /proc/loadavg พบว่า load average ระดับ kernel ของเครื่องจริงวัดได้เกิน 1490 ในจุดหนึ่ง ยืนยันแล้วว่าเป็นปัญหาระดับเครื่องทั้งเครื่องเพราะ cluster verify-k8s ที่ใช้ร่วมกันแยกต่างหาก ก็ fail เหมือนกันในช่วงเวลาเดียวกัน) การพิสูจน์ทั้งหมดด้านล่างถูกจับไว้หลัง cluster กลับมาใช้ได้ปกติ — output ของ kubectl ด้านล่างทุกอันมาจาก run จริง

k8s/namespaces-and-resource-quotas/quota-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
name: quota-demo
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: quota-demo
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
pods: "3"
---
apiVersion: v1
kind: LimitRange
metadata:
name: team-limits
namespace: quota-demo
spec:
limits:
- type: Container
max:
cpu: "1"
min:
cpu: 100m
# k8s/namespaces-and-resource-quotas/quota-exceed-pod.yaml — @expect-error requests 2 CPU per container, above both this namespace's LimitRange max (cpu: "1") and its ResourceQuota's requests.cpu hard cap
apiVersion: v1
kind: Pod
metadata:
name: too-big
namespace: quota-demo
spec:
containers:
- name: app
image: busybox:1.38
command: ['sh', '-c', 'sleep 3600']
resources:
requests:
cpu: '2'
memory: 4Gi
limits:
cpu: '2'
memory: 4Gi
$ kubectl apply -f quota-exceed-pod.yaml
Error from server (Forbidden): error when creating "quota-exceed-pod.yaml": pods "too-big" is forbidden: maximum cpu usage per Container is 1, but limit is 2

rejection จริงมาจาก LimitRange ของ namespace ก่อนเลย ไม่ใช่ ResourceQuota — LimitRange ตรวจ request/limit ของแต่ละ container เทียบกับ max/min ของตัวเองแยกต่างหาก และ 2 CPU ชน max: cpu: "1" ก่อนที่การคำนวณรวมของ ResourceQuota จะเกี่ยวข้องด้วยซ้ำ พอจะเห็น rejection ของ ResourceQuota เองจริง ๆ request ต้องผ่าน LimitRange ได้ (cpu อยู่ในขอบเขต 1) แต่ยังเกิน hard cap ของ ResourceQuota ใน resource อื่น:

$ kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: too-much-mem
namespace: quota-demo
spec:
containers:
- name: app
image: busybox:1.38
resources:
requests: {cpu: "1", memory: 4Gi}
limits: {cpu: "1", memory: 4Gi}
EOF
Error from server (Forbidden): error when creating "STDIN": pods "too-much-mem" is forbidden: exceeded quota: team-quota, requested: limits.memory=4Gi,requests.memory=4Gi, used: limits.memory=0,requests.memory=0, limited: limits.memory=2Gi,requests.memory=1Gi

นั่นคือข้อความ exceeded quota: จริง ๆ — Forbidden เต็ม ๆ ตอน admission ไม่ใช่ throttle หรือเข้าคิว พร้อมตัวเลข requested/used/limited จริงของ resource ที่ชนพอดี สอง rejection จริงที่ต่างกันจาก namespace เดียวกัน: LimitRange จับ container เดี่ยวที่เกินขอบเขตก่อน ResourceQuota จับการรวมที่ Pod ที่ผ่าน LimitRange แล้วยังดันเกิน hard cap ของ namespace อยู่ดี

ResourceQuota ตัวเดียวกันด้านบนยังจำกัด pods: "3" ด้วย — เป็น count-based limit ที่แยกจากการคำนวณ CPU/memory เลย:

$ kubectl apply -f pod-count-1.yaml -f pod-count-2.yaml -f pod-count-3.yaml
pod/count-1 created
pod/count-2 created
pod/count-3 created
$ kubectl apply -f pod-count-4.yaml
Error from server (Forbidden): error when creating "pod-count-4.yaml": pods "count-4" is forbidden: exceeded quota: team-quota, requested: pods=1, used: pods=3, limited: pods=3

Pod ตัวที่ 4 แต่ละตัวขอแค่ 100m/64Mi เท่านั้น อยู่ในขอบเขตอื่นทุกอย่างสบาย ๆ ถูก reject ล้วน ๆ ด้วยจำนวน — quota แบบนับจำนวน object บล็อกการ scale-up ที่ถูกต้องได้แรงพอ ๆ กับ quota แบบจำนวน resource เลย แค่ด้วยเหตุผลคนละอย่าง

# k8s/namespaces-and-resource-quotas/quota-norequest-pod.yaml — @expect-error no resources.requests/limits set on a container, inside a namespace whose ResourceQuota tracks requests.cpu/requests.memory/limits.cpu/limits.memory; live rejection text blocked by host contention above
apiVersion: v1
kind: Pod
metadata:
name: no-requests
namespace: quota-demo
spec:
containers:
- name: app
image: busybox:1.38
command: ['sh', '-c', 'sleep 3600']
$ kubectl apply -f quota-norequest-pod.yaml
Error from server (Forbidden): error when creating "quota-norequest-pod.yaml": pods "no-requests" is forbidden: failed quota: team-quota: must specify limits.memory for: app; requests.memory for: app

นี่คือผลจริงที่แม่นยำและน่าแปลกใจนิดหน่อย: error ระบุแค่ memory เท่านั้น ไม่มี cpu เลย เหตุผลคือการ default ของ LimitRange พิสูจน์ตรง ๆ ด้วยการ apply Pod แบบไม่มี resources ตัวเดียวกันเป๊ะ ใน namespace แยกที่มี LimitRange เดียวกันแต่ไม่มี ResourceQuota แล้วตรวจดูว่าอะไรถูกใส่เข้าไปจริง:

$ kubectl get pod no-res -o jsonpath='{.spec.containers[0].resources}'
{"limits":{"cpu":"1"},"requests":{"cpu":"1"}}

ตาม กฎการเติม default ของ LimitRange ของ Kubernetes พอ LimitRange ตั้ง max ไว้แต่ไม่ได้ตั้ง default ชัดเจน API server จะใช้ max เองเป็น default ของ limit (และเมื่อไม่มี defaultRequest 1 ก็กลายเป็น default ของ request ด้วย) — ดังนั้น LimitRange ของ namespace นี้ (max: cpu: "1", min: cpu: 100m ไม่มีขอบเขต memory เลย) เลยเติม cpu ให้ Pod ด้านบนแบบเงียบ ๆ เหลือแค่ memory ที่ไม่ได้ตั้งค่าจริง ๆ ResourceQuota เองไม่เคยเติม default ให้เลย มันแค่ reject เท่านั้น — ตรงนี้มัน reject พอดีตัวเดียวที่ LimitRange ไม่ได้มีความเห็นอะไรด้วยเลย

k8s/namespaces-and-resource-quotas/stuck-crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: slowresources.example.com
spec:
group: example.com
names:
kind: SlowResource
plural: slowresources
singular: slowresource
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
# k8s/namespaces-and-resource-quotas/stuck-ns.yaml — @expect-error dry-run=server never actually registers the CRD above with the API server, so a CR instance of that same never-installed CRD fails validation in this harness with a real, separate error (`no matches for kind "SlowResource"`) — proven for real below on a cluster where the CRD was actually (non-dry-run) applied first
apiVersion: v1
kind: Namespace
metadata:
name: stuck-demo
---
apiVersion: example.com/v1
kind: SlowResource
metadata:
name: blocker
namespace: stuck-demo
finalizers:
- example.com/never-removed
spec: {}
$ kubectl apply -f stuck-crd.yaml
customresourcedefinition.apiextensions.k8s.io/slowresources.example.com created
$ kubectl apply -f stuck-ns.yaml
namespace/stuck-demo created
slowresource.example.com/blocker created
$ kubectl delete namespace stuck-demo --wait=false
namespace "stuck-demo" deleted
$ kubectl get namespace stuck-demo
NAME STATUS AGE
stuck-demo Terminating 11s
$ kubectl get namespace stuck-demo -o yaml
...
- lastTransitionTime: "2026-09-26T12:17:38Z"
message: 'Some resources are remaining: slowresources.example.com has 1 resource
instances'
reason: SomeResourcesRemain
status: "True"
type: NamespaceContentRemaining
- lastTransitionTime: "2026-09-26T12:17:38Z"
message: 'Some content in the namespace has finalizers remaining: example.com/never-removed
in 1 resource instances'
reason: SomeFinalizersRemain
status: "True"
type: NamespaceFinalizersRemaining
phase: Terminating

จริงและตรงตามกลไกที่คาดไว้เป๊ะ: namespace controller รอทุก object ข้างในถูกลบออกจริง ๆ ก่อน และ object ที่มี finalizer ค้างอยู่จะได้แค่ deletionTimestamp ไม่เคยถูกลบจริงจนกว่า finalizer ทุกตัวจะถูกเคลียร์ namespace เลยค้างอยู่ที่ Terminating ตลอดไป status.conditions ระบุปัญหาตรง ๆ (SomeFinalizersRemain ระบุชื่อ example.com/never-removed) วิธีที่ถูกต้องในการ ตรวจสอบ เรื่องนี้ — ไม่ใช่วิธี ตอบสนอง แรกสุด — คือการ sweep ตาม namespace ไม่ใช่การไปแก้ metadata.finalizers ทันทีเป็นทางแรก

เรื่องข้างเคียงจริงที่ควรรู้เวลาใช้ harness ของคอร์สนี้เอง (หรือ workflow แบบ --dry-run=server ไหนก็ตาม) พิสูจน์คู่ CRD-กับ-instance แบบนี้: kubectl apply --dry-run=server บน CRD ไม่เคยลงทะเบียนมันกับ API server จริง (dry-run แปลว่าไม่มีอะไรถูกเก็บจริง) การ dry-run แยกต่างหาก ของ instance SlowResource กับ cluster ที่ไม่เคย apply CRD จริง ๆ เลยจะ fail ด้วย error จริงที่ต่างออกไป — no matches for kind "SlowResource" in version "example.com/v1": ensure CRDs are installed first นั่นไม่ใช่ข้อผิดพลาดใน instance manifest แต่เป็นข้อจำกัดจริงของการพิสูจน์ CRD ใหม่เอี่ยมกับ instance ของมันในรอบ dry-run เดียวกัน และนี่คือเหตุผลที่ fence ที่สองด้านบนถูก mark @expect-error สำหรับ harness ของคอร์สนี้ ทั้งที่ (ตามที่พิสูจน์ไปแล้ว) มันทำงานได้สมบูรณ์แบบบน cluster ที่ CRD ถูก apply จริงแบบ non-dry-run มาก่อน:

scripts/find-stuck-namespace-resources.sh
kubectl api-resources --verbs=list --namespaced -o name | while read -r r; do
cnt=$(kubectl get "$r" -n stuck-demo --no-headers 2>/dev/null | wc -l | tr -d ' ')
if [ "$cnt" != "0" ]; then echo "$r: $cnt"; fi
done
slowresources.example.com: 1

sweep เจอ resource kind เดียวที่มี object เหลืออยู่ในจริง ๆ ตรงกับ status.conditions เป๊ะ — จากตรงนั้น ทางแก้ที่ถูกต้องคือเอา finalizer entry เฉพาะที่ object เอง มีออก (หรือทำให้ controller ที่ควรจะเอาออกกลับมารันอีกครั้ง) ไม่ใช่ไปแก้ metadata.finalizers ที่ตัว namespace เอง

scripts/inventory-namespaced-kinds.sh
kubectl api-resources --namespaced=true --no-headers | wc -l
kubectl api-resources --namespaced=true -o name
$ kubectl api-resources --namespaced=true --no-headers | wc -l
45
$ kubectl api-resources --namespaced=true -o name
configmaps
controllerrevisions.apps
cronjobs.batch
csistoragecapacities.storage.k8s.io
daemonsets.apps
deployments.apps
endpoints
endpointslices.discovery.k8s.io
events
horizontalpodautoscalers.autoscaling
ingresses.networking.k8s.io
jobs.batch
leases.coordination.k8s.io
limitranges
networkpolicies.crd.projectcalico.org
networkpolicies.networking.k8s.io
persistentvolumeclaims
poddisruptionbudgets.policy
pods
podtemplates
replicasets.apps
replicationcontrollers
resourcequotas
rolebindings.rbac.authorization.k8s.io
roles.rbac.authorization.k8s.io
secrets
serviceaccounts
services
slowresources.example.com
statefulsets.apps
... (รวม 45 บน cluster นี้)

45 namespaced kind จริงบน cluster นี้ — kubectl get all -A ครอบคลุมแค่ kind ที่พบบ่อยตามรายการ hardcode คงที่ (Pod, Deployment, ReplicaSet, Service และอีกไม่กี่ตัว) — ไม่รวม ResourceQuota, LimitRange, ConfigMap, Secret, Role/RoleBinding, NetworkPolicy, หรือ PodDisruptionBudget เลย ทั้งที่ทุกตัวอยู่ใน list จริงด้านบนในฐานะ namespaced object ธรรมดา kubectl api-resources --namespaced=true คือ inventory ที่ครบจริงว่า “namespaced” หมายถึงอะไรบน cluster หนึ่ง ๆ — จำนวนและเนื้อหาที่แน่นอนขึ้นอยู่กับว่า CRD ไหนติดตั้งอยู่บ้าง (Calico ที่ติดตั้งบน cluster นี้ กับ CRD SlowResource ของคอร์สเองก็เพิ่มแถวที่ cluster เปล่าจะไม่มี) script หรือความเคยชินที่ grep output ของ get all -A แล้วคิดว่าเห็น namespaced object ทุกตัวใน cluster แล้ว พลาดไปเกือบทั้งหมดแบบเงียบ ๆ

flowchart LR
  subgraph cluster["Cluster"]
    subgraph nsa["Namespace: team-a"]
      qa["ResourceQuota"] --- la["LimitRange"]
      pa1["Pod"] --- pa2["Pod"]
    end
    subgraph nsb["Namespace: team-b"]
      qb["ResourceQuota"] --- lb["LimitRange"]
      pb1["Pod"] --- pb2["Pod"]
    end
  end
สอง namespace แต่ละอันถูกจำกัดด้วย ResourceQuota และ LimitRange ของตัวเอง

ตอนรีวิว manifest ของ namespace/quota ที่ AI สร้าง ให้เช็ค

  • manifest ที่คิดว่า ResourceQuota เติม request/limit ที่หายไปแบบเดียวกับ default/defaultRequest ของ LimitRange — พิสูจน์/อ้างอิงด้านบนแล้วว่า ResourceQuota แค่ reject เท่านั้น ไม่เคยเติม default เองเลย
  • script cleanup หรือ deletion ที่ไม่มีการจัดการ namespace ที่ค้าง Terminating — อ้างอิงด้านบนแล้วว่านี่คือสถานะจริงที่พบบ่อย ไม่ใช่ edge case สมมติ
  • script audit หรือ cleanup ที่ grep kubectl get all -A แล้วคิดว่าเห็น namespaced object ทุกตัวแล้ว — อ้างอิงด้านบนแล้วว่า get all คือ list คงที่เล็ก ๆ ที่ไม่รวม ResourceQuota, LimitRange, ConfigMap, Secret, RBAC object, NetworkPolicy, และ PodDisruptionBudget เป็นต้น
  • โค้ดหรือเอกสารที่ปฏิบัติต่อขอบเขต namespace ราวกับเทียบเท่า NetworkPolicy default-deny — namespace จำกัดแค่ ชื่อ กับ การนับ resource ไม่เคยจำกัด การเข้าถึงทาง network เลย ตามที่หัวข้อเปิดบทนี้พูดไว้แล้ว

🐛 หา bug ในโค้ดนี้

k8s/namespaces-and-resource-quotas/team-b-pod.yaml
apiVersion: v1
kind: Namespace
metadata:
name: team-b
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-b-quota
namespace: team-b
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
---
apiVersion: v1
kind: Pod
metadata:
name: worker
namespace: team-b
spec:
containers:
- name: app
image: myregistry/worker:1.0
เฉลย

ResourceQuota ของ team-b track requests.cpu/requests.memory/limits.cpu/limits.memory แต่ manifest Pod ไม่ได้ตั้ง block resources บน container เลย และไม่มี LimitRange ใด ๆ ใน namespace นี้ที่จะเติม default ให้ พิสูจน์ด้านบนแล้วว่านี่ไม่ใช่กรณีที่ Pod จะได้ default request มาเงียบ ๆ — API server จะ reject Pod นี้ตรง ๆ ด้วย error must specify ที่ระบุทุก resource ที่ track ไว้ที่ container ไม่ได้ตั้ง (must specify limits.cpu,limits.memory,requests.cpu,requests.memory for: app) และไม่มีอะไรใน manifest นี้ที่จะป้องกัน rejection นั้นได้เลย ทางแก้: เพิ่ม resources.requests/resources.limits ให้ container ตรง ๆ หรือไม่ก็เพิ่ม LimitRange ให้ namespace พร้อมตั้ง default/defaultRequest ไว้ เพื่อให้ container ที่ไม่ได้ตั้งค่าได้ default ที่สมเหตุสมผลแทนที่จะถูก reject ตรง ๆ

namespace คือขอบเขตเรื่อง ชื่อและการนับ resource ไม่ใช่ขอบเขตเรื่อง ความสามารถ ด้วยตัวเอง ResourceQuota นับการใช้รวมของทั้ง namespace LimitRange เติมและจำกัดว่า Pod/container แต่ละตัวขอได้แค่ไหน และทั้งคู่ (รวมถึงตัว namespace เอง) ไม่แตะเรื่องการเข้าถึงทาง network เลย ซึ่งเป็นการควบคุมคนละชั้นไปเลย (NetworkPolicy อยู่ใน module Networking)

ทางเลือกข้อดีต้นทุน
ResourceQuota track requests.*/limits.*จำกัดการใช้รวมของ namespace ได้จริง อ้างอิงด้านบนพร้อม rejection รูปแบบจริงทุก Pod ใน namespace ต้องตั้ง request/limit เอง (หรือมี default จาก LimitRange) ไม่งั้นถูก reject ตรง ๆ
LimitRange พร้อม default/defaultRequestตัดภาระ “ต้องตั้งเอง” ออกจากทุกคนที่เขียน manifest อ้างอิงด้านบนdefault ที่ apply แบบเงียบ ๆ อาจผิดสำหรับ workload บางตัวถ้าไม่มีใครสังเกต
Quota แบบนับจำนวน object (pods: "3")ป้องกันการสร้าง object เกินควบคุมไม่ว่าขนาดจะเท่าไหร่ อ้างอิงด้านบนบล็อกการ scale-up ที่ถูกต้องได้ด้วย error เรื่อง “จำนวน” ถ้าไม่มีใครเช็ค quota ก่อน
ตรวจ namespace ที่ค้าง Terminating ด้วยการ sweep ตาม namespaceเจอ resource ที่บล็อกจริง แบบไม่ทำลายอะไรช้ากว่าการ force-clear finalizer — แต่ force-clear ซ่อนปัญหาจริงไว้แทนที่จะแก้
  • “ResourceQuota เติม default request/limit ให้ Pod ที่ไม่ได้ตั้งเอง” อ้างอิงด้านบนแล้ว — แค่ reject เท่านั้น LimitRange ต่างหากที่เติม default ให้ และเติมก็ต่อเมื่อตั้งค่าไว้เท่านั้น
  • “kubectl get all -A แสดง object ทุกตัวใน cluster” อ้างอิงด้านบนแล้ว — เป็น list คงที่ที่ไม่ครบ kubectl api-resources --namespaced=true ต่างหากคือ inventory ที่ครบจริง
  • “namespace ที่ค้าง Terminating แก้ได้แค่ทางเดียวคือไปแก้ finalizer ออก” อ้างอิงด้านบนแล้ว — ตรวจดูว่า resource ตัวไหนที่ยังมี finalizer ค้างอยู่ (ผ่านการ sweep ตาม namespace) คือขั้นแรกที่ถูกต้องและไม่ทำลายอะไร
โดย default namespace ไม่ได้ให้อะไรระหว่าง Pod ที่อยู่คนละ namespace
object ไหนต่อไปนี้เป็น cluster-scoped ไม่ใช่ namespaced
ResourceQuota คุมอะไรที่ LimitRange ไม่ได้คุม
ทำไม namespace ถึงต้องมี LimitRange เพิ่มจาก ResourceQuota
Pod ที่ไม่มี block resources ถูก reject ด้วย error จริงนี้ ใน namespace ที่ ResourceQuota track requests.cpu/requests.memory/limits.cpu/limits.memory และ LimitRange ตั้ง max: cpu: "1" / min: cpu: 100m (ไม่มีขอบเขต memory ไม่มี default ชัดเจน) ทำไม error ถึงระบุแค่ memory ไม่มี cpu เลย
Error from server (Forbidden): error when creating "no-requests.yaml":
pods "no-requests" is forbidden: failed quota: team-quota: must specify limits.memory for: app; requests.memory for: app
namespace ค้างอยู่ที่ Terminating มาแล้วหนึ่งชั่วโมงหลังรัน kubectl delete namespace ขั้นแรกที่ถูกต้องในการตรวจสอบตามบทนี้คืออะไร