Kubernetes ทำงานอย่างไร
โมดูลนี้มีไว้ทำอะไร
หัวข้อที่มีชื่อว่า “โมดูลนี้มีไว้ทำอะไร”ทุก module ก่อนหน้าในคอร์สนี้สอนให้คุณ ใช้ Kubernetes เป็น เขียน manifest, apply ด้วย kubectl, อ่าน status กลับมา, scale, scheduling, security, storage และ ship ด้วย Helm/GitOps ไม่มีตอนไหนต้องรู้ว่า API server ทำอะไรกับ request จริง ๆ ระหว่างตอนที่คุณพิมพ์ kubectl apply กับตอนที่ object มีอยู่จริง, controller รู้ได้อย่างไรว่ามีอะไรเปลี่ยน, kube-scheduler plugin ที่คุณเห็นชื่อ extension point มาแล้วคืออะไรกันแน่ในเชิงโค้ด, mutating webhook กับ ValidatingAdmissionPolicy รันตามลำดับไหนจริง ๆ หรือ managedFields เก็บอะไรจริง ๆ เวลาสอง tool apply object เดียวกัน
ช่องว่างนั้นแหละคือจุดที่โค้ด/tooling Kubernetes ที่ AI เขียนพังแบบดูผิวเผินแล้วเหมือนถูก เช่น controller ที่เขียนด้วย List ใน for-loop แทนที่จะใช้ shared informer แล้ว poll เงียบ ๆ พลาด event ระหว่างรอบ, reconcile function ที่ไม่มี rate limiting จน hot-loop ซ้ำ ๆ บน error ถาวร, สมมติว่า webhook รัน “ก่อน validation เสมอ” ทั้งที่ chain จริงสลับ mutating/validating คนละแบบ, หรือ script ที่ “แก้” conflict ของ managedFields ด้วยการ force เอา field ทุกอันมาเป็นของตัวเองแทนที่จะอ่านว่า field ไหนขัดกันจริง ๆ ไม่มีข้อไหนเป็น syntax error ไม่มีข้อไหนถูกจับด้วย kubectl apply --dry-run=client ทุกข้อคือข้อเท็จจริงเรื่อง runtime ที่ module นี้พิสูจน์ให้ดูได้
Module นี้มีหน้าที่เดียว ให้ความรู้เรื่อง runtime ห้าเรื่องที่ทำให้คุณดู โค้ดหรือ YAML ของ Kubernetes ที่คนอื่นเขียน — controller, webhook config, scheduler profile, script เต็มไปด้วย kubectl apply --server-side — แล้วตอบได้ว่า
- เกิดอะไรขึ้นจริงกับ request ข้างใน API server และ watch ทำงานจริงอย่างไร? (API server กับ etcd —
resourceVersion, watch, bookmark,410 Goneและ etcd ในฐานะที่เดียวที่ state อยู่จริง) - controller รู้ได้อย่างไรว่า “มีอะไรเปลี่ยน” โดยไม่ poll? (controller, informer และ workqueue — Reflector → DeltaFIFO → Indexer/Lister → workqueue → reconcile ตรงจาก
client-go) - scheduler “plugin” คืออะไรจริง ๆ และรันตามลำดับไหน? (scheduler framework — extension-point interface จริง และชื่อ plugin จริงจาก
pkg/scheduler) - mutating webhook, schema validation, validating webhook และ
ValidatingAdmissionPolicyรันลำดับไหนจริง ๆ? (admission chain — พิสูจน์ด้วย chain จริง, dry-run จริง และ source ที่กำหนดลำดับนี้ตรง ๆ) managedFieldsเก็บอะไรจริง ๆ และ “conflict” หมายความว่าอะไรจริง ๆ? (Server-Side Apply internals — markerf:/k:/v:,x-kubernetes-list-typeและ librarystructured-merge-diffที่ทำให้มันทำงานได้)
ทุกข้ออ้างใน module นี้อ้างอิงจากสามอย่าง source จริงของ Kubernetes ที่ github.com/kubernetes/kubernetes tag v1.37.0 (เวอร์ชันที่คอร์สนี้ pin ไว้) อ้างเป็นไฟล์และบรรทัดจริง, docs ทางการที่ kubernetes.io/docs หรือการรันจริงบน kind cluster 3 node จริง (kind create cluster --name internals, control-plane 1 + worker 2, Kubernetes 1.37.0) — kubectl -v=8 trace จริง, etcdctl get จริง, log ของ scheduler จริง, error จริงจาก API server — วางไว้ใต้ข้ออ้างนั้นเสมอ ไม่ใช่การเดา internals
สิ่งที่ module นี้ครอบคลุม
หัวข้อที่มีชื่อว่า “สิ่งที่ module นี้ครอบคลุม”| บทเรียน | ตอบคำถามอะไร |
|---|---|
| API Server and etcd Watch | เส้นทาง request จริงผ่าน API server คืออะไร และ watch รักษาความสอดคล้องด้วย resourceVersion ได้อย่างไร? |
| Controllers, Informers, and Workqueues | controller ทำอะไรจริง ๆ ในเชิงกลไก ตั้งแต่ watch event มาถึงจนถึง reconcile? |
| Scheduler Framework | extension point และ plugin จริงที่ scheduler รันคืออะไร และเปลี่ยนตัวไหน active ได้อย่างไร? |
| Admission Chain | mutating webhook, validation, validating webhook และ VAP/MAP รันตามลำดับไหนจริง ๆ ที่พิสูจน์ได้จาก source? |
| Server-Side Apply Internals | managedFields เก็บอะไรจริง ๆ และอะไรตัดสินว่าสอง manager ขัดกัน? |
Module Foundations แนะนำ kubectl apply --server-side และ error conflict ของ field manager จริงไปแล้วจากมุมมองภายนอก module นี้ไปไกลกว่านั้นเข้าไปดู request path จริง, watch จริง, scheduler plugin จริง, ลำดับ admission จริง และ merge algorithm จริง
flowchart TD kubectl["kubectl apply -f pod.yaml"] --> authn["Authentication"] authn --> authz["Authorization (RBAC)"] authz --> mutate["Mutating admission chain\n(in-tree -> MutatingAdmissionPolicy -> MutatingAdmissionWebhook)\n(Admission Chain)"] mutate --> schema["Schema + strategy validation\n(OpenAPI, x-kubernetes-list-type)\n(Server-Side Apply Internals)"] schema --> validate["Validating admission chain\n(in-tree -> ValidatingAdmissionPolicy -> ValidatingAdmissionWebhook)\n(Admission Chain)"] validate --> etcd["etcd: ที่เดียวที่ state อยู่จริง\n(API Server and etcd Watch)"] etcd --> watch["Watch stream เรียงตาม resourceVersion"] watch --> reflector["client-go Reflector -> DeltaFIFO -> Indexer/Lister\n(Controllers, Informers, and Workqueues)"] reflector --> queue["workqueue (rate-limited, level-triggered)"] queue --> reconcile["Controller reconcile\n(เช่น ReplicaSet controller สร้าง Pod)"] reconcile --> sched["kube-scheduler: Filter -> Score -> Bind\n(Scheduler Framework)"] sched --> kubelet["kubelet สั่งรัน container"]
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”ทุกอย่างใน module นี้คือเรื่องเดียวกัน เล่าจากห้าจุดบน loop เดียวกัน คุณส่ง mutation หนึ่งครั้ง API server รันมันผ่าน pipeline ตายตัว (auth, admission, validation, storage) แล้วเขียน truth เพียงชุดเดียวลง etcd ทุก component อื่น — controller, scheduler, kubectl get -w — รู้เรื่อง write นั้นด้วยวิธีเดียวกันคือ watch stream ที่เรียงด้วย resourceVersion จาก API server ตัวเดียวกันนั้น ไม่เคย poll ไม่เคยคุยกับ etcd ตรง ๆ controller ก็แค่ “watch, queue, reconcile” ที่ต่อสายผ่านกลไก informer ของ client-go scheduler ก็แค่ consumer อีกตัวของ watch stream เดียวกัน ที่รัน pipeline ของ plugin ที่มีชื่อก่อนเขียนผลตัดสินใจกลับผ่าน API server ตัวเดียวกัน admission กับ Server-Side Apply ก็แค่โครงสร้างเพิ่มเติมที่ API server ใส่ลงใน write path เอง ก่อนอะไรจะไปถึง etcd พอวางข้อเท็จจริงข้อไหนใน module นี้ลงบน loop เดียวกันนี้ได้ “Kubernetes ทำงานอย่างไร” ก็เลิกเป็นเรื่องห้าเรื่องที่ต้องท่องแยกกัน
ความเข้าใจผิดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ความเข้าใจผิดที่พบบ่อย”- “controller poll API server เป็นช่วง ๆ เพื่อเช็คว่ามีอะไรเปลี่ยน” Controllers, Informers, and Workqueues พิสูจน์ตรงข้ามด้วย informer จริงที่รันอยู่ มัน list ครั้งเดียวแล้วเปิด HTTP watch connection ค้างไว้นาน ๆ แล้วตอบสนองต่อ event
ADDED/MODIFIED/DELETEDทีละตัว ส่วน fullListเป็นช่วง ๆ ที่คุณอาจเคยได้ยินคือ resync ที่เป็น safety net ไม่ใช่กลไกหลัก - “admission webhook ทั้งหมดรันในกลุ่มเดียวไม่แยกกัน ตามลำดับ registration” Admission Chain พิสูจน์ลำดับจริงตรงจาก
pkg/kubeapiserver/options/plugins.gomutating admission (in-tree plugin แล้วMutatingAdmissionPolicyแล้วMutatingAdmissionWebhook) จบทั้งหมดก่อน แล้ว schema/strategy validation ถึงรัน แล้ว validating admission (in-tree,ValidatingAdmissionPolicy,ValidatingAdmissionWebhook) ถึงรัน — สอง phase ที่แยกกันจริง ไม่ใช่กลุ่มเดียว - “scheduler เป็นกล่องดำที่แค่เลือก node” Scheduler Framework พิสูจน์ว่ามันคือ pipeline ของ plugin ที่มีชื่อแยกกัน สลับได้แยกกัน ชื่อจริงตรงจาก
pkg/scheduler/framework/plugins/namesบน extension point ตายตัวที่นิยามในk8s.io/kube-scheduler/framework - “
managedFieldsคือ idea เดียวกับ annotationlast-applied-configurationเก่า แค่ย้ายไปทำฝั่ง server” Server-Side Apply Internals พิสูจน์ว่าโครงสร้างต่างกันจริงmanagedFieldsคือ map ownership ต่อ manager ต่อ field คีย์ด้วย marker จริงของ OpenAPI schema (x-kubernetes-list-type: mapเทียบกับatomic) คำนวณด้วย librarystructured-merge-diff— ไม่ใช่ blob ก้อนเดียวของ “ครั้งที่แล้วฉัน apply อะไรไป”
อ่านโค้ดที่ AI เขียน
หัวข้อที่มีชื่อว่า “อ่านโค้ดที่ AI เขียน”จุดประสงค์ทั้งหมดของ module นี้คือ section นี้ ห้าครั้ง หนึ่งครั้งต่อบท ตัวอย่างระดับภาพรวมไว้ก่อน โค้ดที่ดูเหมือน controller ที่ถูกต้อง แต่ขาดสิ่งเดียวที่ทำให้มันเป็น controller จริง ๆ ไม่ใช่แค่ตัว poll
🐛 หา bug ในโค้ดนี้
// A "controller" a teammate wrote to react to Pod changessetInterval(async () => {const pods = await api.listNamespacedPod('default');for (const pod of pods.body.items) { reconcile(pod);}}, 5000);เฉลย
โค้ดนี้รัน reconcile กับทุก Pod ทุก 5 วินาที ตลอดไป ไม่ว่าอะไรจะเปลี่ยนหรือไม่ก็ตาม — Controllers, Informers, and Workqueues พิสูจน์ว่าผิด controller จริงใช้ watch ส่ง event ADDED/MODIFIED/DELETED ทีละตัวผ่าน Reflector เข้า DeltaFIFO แล้ว reconcile เฉพาะ object ที่ key ถูก enqueue จริง เวอร์ชัน setInterval นี้ reconcile ทุก object ทุก tick โดยไม่สนว่าเปลี่ยนหรือเปล่า (ภาระ API server เพิ่มตามขนาด cluster ไม่ใช่ตามอัตราการเปลี่ยน) และที่แย่กว่านั้นมันพลาดการเปลี่ยนแปลงได้เลยถ้า object ถูกสร้างแล้วลบภายในช่วง 5 วินาทีเดียวกัน เพราะ poll ไม่มีอะไรรับประกันว่าจะเห็นทุก state ระหว่างทางเหมือน watch stream ที่เรียงลำดับ