สถาปัตยกรรมเครื่องและคอมโพเนนต์
Chapter 2: The Machine Architecture (สถาปัตยกรรมระดับฮาร์ดแวร์และเครื่องจักร)
1. The Control Plane (สมองของระบบ)
Learning Progression
- 🟢 Basic Level: ปูพื้นฐานภาษาเข้าใจง่าย - เข้าใจคอนเซปต์ภาพรวมและการแก้ปัญหาเบื้องต้น
- 🟡 Intermediate Level: โค้ด/คอนฟิกไวยากรณ์จริง - การเขียนโค้ดเพื่อใช้งานจริงในระบบ
- 🔴 Professional Level: Under-the-hood & Performance/FinOps - กลไกเบื้องลึกและการรีดประสิทธิภาพ
🏢 Real-World Enterprise Scenario
เคสระบบการเงิน/Big Tech: การรองรับ Transaction จำนวนมหาศาลต่อวินาทีพร้อมประกัน Data Integrity สูงสุด โดยใช้สถาปัตยกรรมที่ยืดหยุ่นและการมอนิเตอร์ระดับสูง
ทฤษฎีและกลไกการทำงาน (How it works):
หากเปรียบ Kubernetes เป็นบริษัท Control Plane คือทีมผู้บริหารระดับสูง (The Brain) ที่คอยตัดสินใจ วางแผน และเก็บข้อมูลทั้งหมดของบริษัท กฎเหล็กคือ Control Plane จะไม่รับภาระงานกรรมกร (ไม่รันแอปพลิเคชันของลูกค้า) แต่จะทำหน้าที่บริหารล้วนๆ ประกอบด้วย 4 หัวใจหลัก:
1. API Server: พนักงานต้อนรับ (Front door) เพียงคนเดียวที่ทุกคน (รวมถึงผู้ดูแลระบบและ Kubelet) ต้องเดินมาคุยด้วย มันทำหน้าที่ตรวจสอบสิทธิ์ (AuthN/AuthZ) และ Admission Control ก่อนจะยอมให้ใครแก้ข้อมูล
2. etcd: ตู้เซฟนิรภัย (Distributed Key-Value Store) เป็นที่เดียวในระบบที่เก็บ "ความจริง (State)" ของคลัสเตอร์ทั้งหมด ใช้ระบบ Raft Consensus ทำให้ข้อมูลไม่สูญหายแม้เครื่องพังไปบางส่วน
3. Scheduler: ฝ่ายจัดสรรทรัพยากร ทำหน้าที่เลือก "เครื่องเซิร์ฟเวอร์ (Node) ที่เหมาะสมที่สุด" ให้กับ Pod ที่กำลังจะเกิดใหม่ โดยพิจารณาจาก CPU/Memory ว่าง และเงื่อนไขต่างๆ (Affinity/Taints)
4. Controller Manager: ผู้จัดการที่ทำหน้าที่เดินตรวจตราตามแผนกต่างๆ (Control Loops) เพื่อเทียบ Desired State กับ Observed State
# ตรวจสอบสถานะของ Control Plane Components ที่ถูกรันอยู่ใน namespace 'kube-system'
$ kubectl get pods -n kube-system -l tier=control-plane
NAME READY STATUS RESTARTS AGE
kube-apiserver-master-node 1/1 Running 0 10d
kube-controller-manager-master-node 1/1 Running 1 10d
kube-scheduler-master-node 1/1 Running 0 10d
etcd-master-node 1/1 Running 0 10d
Use Case ในชีวิตจริง (Real-world Scenario):
ในระบบ Enterprise ระดับ Production อย่างเช่น E-commerce เจ้าใหญ่ พวกเขาจะไม่รัน Control Plane แค่เครื่องเดียวเด็ดขาด แต่จะรันแบบ High Availability (HA) โดยมี Master Nodes 3 เครื่อง (เพื่อรองรับสมการ Quorum ของ etcd ที่ต้องการ (N/2)+1 ในการโหวต) ถ้า Data Center A ไฟดับไป 1 เครื่อง ระบบ Control Plane ก็ยังสามารถทำงานและสั่งงาน Worker Nodes ต่อไปได้โดยไม่มีใครรู้สึกถึงความผิดปกติ
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations):
* Pitfall (ปัญหา): การคิดว่า "Backup ทำเมื่อไหร่ก็ได้" หาก etcd ล่มหรือข้อมูลคอร์รัปต์ และคุณไม่มีแบ็กอัปที่ใช้งานได้ คลัสเตอร์ของคุณจะกลายเป็น "ซาก" ทันที ไม่สามารถลบ สร้าง หรือแก้ไขอะไรได้อีก แม้แอปจะยังรันอยู่ก็ตาม
* Mitigation (วิธีแก้): A backup you have never restored is a guess, not a guarantee. ต้องตั้งระบบ Automated Snapshot สำหรับ etcd เป็นประจำ (เช่น ทุกชั่วโมง) และต้องจัดซ้อมกู้ภัย (Disaster Recovery Drill) ด้วยคำสั่ง etcdctl snapshot restore ในสภาพแวดล้อมจำลองอย่างสม่ำเสมอ
2. The Worker Nodes (กล้ามเนื้อของระบบ)
ทฤษฎีและกลไกการทำงาน (How it works):
ถ้า Control Plane คือผู้บริหาร Worker Nodes ก็คือพนักงานหน้างาน (The Muscle) ที่ทำหน้าที่แบกหามและรันแอปพลิเคชันจริงๆ ของระบบ Worker Node ทุกเครื่องจะถูกออกแบบมาให้เป็นสิ่งของ "ใช้แล้วทิ้ง (Disposable)" เพราะตราบใดที่มันสุขภาพดี เครื่องไหนก็รันงานได้เหมือนกันหมด บน Worker Node หนึ่งเครื่อง จะมีบริการหลักๆ ทำงานอยู่ 3 ตัว:
1. Kubelet: สายลับที่ถูกส่งมาจาก Control Plane ประจำการที่ Node นี้ หน้าที่ของมันคือรอรับคำสั่งจาก API Server แล้วสั่งให้เครื่องเปิด/ปิด Container รวมถึงส่งรายงานสุขภาพของเครื่อง (Node Status) กลับไปรายงานเจ้านาย
2. Container Runtime (เช่น containerd, CRI-O): ซอฟต์แวร์ระดับล่างที่คุยกับ OS Kernel โดยตรง (ผ่าน Container Runtime Interface - CRI) เพื่อสร้างและจัดการวงจรชีวิตของ Container (การดึง Image, รันโปรเซส, จำกัดทรัพยากร)
3. kube-proxy: พนักงานโบกจราจร ทำหน้าที่สร้างกฎเครือข่าย (เช่น iptables หรือ eBPF/nftables) ภายในเครื่อง เพื่อให้แน่ใจว่า Traffic ที่วิ่งเข้ามาหา IP ของ Service จะถูกส่งทะลุเข้าไปหา Pod ที่ถูกต้อง
# เมื่อ SSH เข้าไปที่ Worker Node เราสามารถตรวจสอบสุขภาพของ Kubelet ได้
$ systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Active: active (running) since Mon 2023-10-10 12:00:00 UTC
Docs: https://kubernetes.io/docs/
# เราจะเห็น Log ว่า Kubelet กำลังคุยกับ API Server อย่างขยันขันแข็ง
$ journalctl -u kubelet -f
Use Case ในชีวิตจริง (Real-world Scenario):
บริษัท Streaming Media มีแคมเปญช่วงสุดสัปดาห์ ทำให้ต้องการเซิร์ฟเวอร์เพิ่ม พวกเขาเปิดระบบ Cluster Autoscaler ซึ่งจะไปสั่ง Cloud Provider (เช่น AWS/GCP) ให้เปิดเครื่อง VM ใหม่ (Worker Nodes) เพิ่มเติม 10 เครื่อง ทันทีที่เครื่องเหล่านั้นบูตเสร็จ kubelet ประจำเครื่องจะวิ่งไปรายงานตัวที่ API Server และเปิดให้ Scheduler โยน Pod หนังความละเอียดสูงมารันให้บริการลูกค้าได้ทันที และปิดทิ้งเมื่อหมดวัน
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations):
* Pitfall (ปัญหา): อาการ Node-pressure Eviction สมมติว่ามีแอปแย่ๆ ตัวหนึ่งกิน Disk/Memory ของ Node จนใกล้เต็ม kubelet ที่รักตัวกลัวตายจะทำการไล่ (Evict) Pod ของคนอื่นที่บริสุทธิ์ออกไปจากเครื่องเพื่อปกป้องตัวเองไม่ให้ OS ล่ม
* Mitigation (วิธีแก้): ป้องกันไม่ให้แอปแย่ๆ ลามไปกวนเพื่อนบ้าน ด้วยการตั้งค่า Resource Limits อย่างเข้มงวดกับทุก Pod และอาจพิจารณาปรับจูนค่าเกณฑ์การ Eviction ของ Kubelet (เช่น evictionHard) ให้รัดกุมขึ้น
3. Pods Anatomy (กายวิภาคของพ็อด)
ทฤษฎีและกลไกการทำงาน (How it works):
Pod คือหน่วยที่เล็กที่สุดที่คุณสามารถสร้างได้ใน Kubernetes กฎข้อแรกที่ต้องจำให้ขึ้นใจคือ Pod ไม่ใช่ Container แต่มันคือ "กระเปาะ" ที่ใช้ห่อหุ้ม Container หนึ่งตัว (หรือหลายตัว) เอาไว้ด้วยกัน
สาเหตุที่ K8s ต้องสร้างแนวคิด Pod ขึ้นมาครอบ Container ก็เพื่อสร้าง Shared Context โดย Container ทุกตัวที่รันอยู่ใน Pod เดียวกัน จะถูกจับยัดเข้าไปใน Network Namespace ของ Linux อันเดียวกัน นั่นแปลว่าพวกมัน:
1. แชร์ IP Address เดียวกันเป๊ะ
2. สามารถคุยกันเองผ่าน localhost (127.0.0.1) ได้เลย (เช่น แอป Web คุยกับ Sidecar Proxy)
3. แชร์ Storage Volumes ข้ามกันได้ง่ายๆ
และคุณสมบัติที่สำคัญที่สุดของ Pod คือมันมีความเป็น Ephemeral (ชั่วคราว มีอายุขัย) Pod เกิดมาเพื่อตายและถูกแทนที่ เราจะไม่ SSH เข้าไปรักษา Pod ที่ป่วย แต่เราจะปล่อยให้ Controller ฆ่ามันทิ้งแล้วเสกตัวใหม่ที่สดใสกว่าขึ้นมาแทน
apiVersion: v1
kind: Pod
metadata:
name: my-app-with-sidecar
spec:
containers:
- name: main-web-app
image: my-web-app:latest
ports:
- containerPort: 8080
- name: log-shipper-sidecar # คอนเทนเนอร์ตัวที่ 2 ที่อยู่ใน Pod เดียวกัน
image: fluentd:latest
# สองตัวนี้คุยกันผ่าน localhost ได้ และเมาท์ไฟล์ System เดียวกันเพื่ออ่าน Log ได้
Use Case ในชีวิตจริง (Real-world Scenario):
Service Mesh อย่าง Istio อาศัยสถาปัตยกรรมของ Pod อย่างเต็มที่ ในคลัสเตอร์ของบริษัท FinTech เมื่อมีการ Deploy แอปพลิเคชัน ระบบ Admission Controller จะแอบฉีด (Inject) คอนเทนเนอร์ envoy-proxy เข้าไปเป็นเพื่อนร่วม Pod (Sidecar) เสมอ ทำให้ทราฟฟิกทุกหยดที่แอปพลิเคชันปล่อยออกมา จะต้องไหลผ่าน Proxy ตัวนี้ทาง localhost ก่อนออกสู่โลกภายนอก ช่วยให้ทีม Security บังคับใช้การเข้ารหัส mTLS ได้โดยที่นักพัฒนาไม่ต้องแก้โค้ดเลย
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations):
* Pitfall (ปัญหา): มือใหม่มักพยายามยัดทุกอย่าง (เช่น Web, Database, Redis) ลงไปใน Pod เดียวกันเพื่อให้มันคุยกันง่ายๆ ซึ่งเป็น Anti-pattern อย่างร้ายแรง เพราะมันทำให้คุณไม่สามารถ Scale Web แยกกับ Database ได้ และถ้าแอปใดแอปหนึ่งพัง Pod ทั้งกระเปาะอาจจะถูก Restart ไปด้วย
* Mitigation (วิธีแก้): ใช้หลักการ 1 Application Process per Pod เสมอ หากแอปพลิเคชันคนละฟังก์ชัน (เช่น Frontend กับ Backend) ให้แยกเป็นคนละ Pod แล้วให้พวกมันคุยกันข้ามเครือข่ายผ่าน Service แทน การรวม Container ไว้ใน Pod เดียว ควรทำเฉพาะกับกระบวนการที่แยกจากกันไม่ได้จริงๆ เท่านั้น (เช่น Sidecar/Helper)
4. Requests, Limits & Quality of Service (QoS)
ทฤษฎีและกลไกการทำงาน (How it works):
ระบบรับเหมาจัดสรรทรัพยากรของ K8s ควบคุมด้วยตัวเลข 2 ชุด ที่มีความหมายต่างกันคนละขั้ว:
1. Requests (คำสัญญา): ตัวเลขที่ Pod "ขอจอง" เป็นขั้นต่ำ Scheduler จะใช้ตัวเลขนี้บวกเลขคณิตดูว่า Node ไหนมีที่ว่างพอให้ลง ถ้าขอเยอะไปจะติด Pending แต่ข้อดีคือ การันตีว่าคุณจะได้ใช้ CPU/Mem ระดับนี้แน่นอน
2. Limits (เพดาน): ตัวเลขขีดจำกัดสูงสุดที่ Pod ห้ามใช้เกิน Kubelet (และ Linux cgroups) เป็นคนบังคับใช้กฎนี้
ความลับที่มืออาชีพต้องรู้คือ การตั้งค่า 2 ตัวนี้ จะส่งผลต่อ Quality of Service (QoS) Class ซึ่งเป็นตัวกำหนดว่า "ใครจะถูกประหารก่อน" เมื่อเครื่องเซิร์ฟเวอร์แรมเต็ม:
* Guaranteed: ตั้ง Requests = Limits (ถูกประหารเป็นคนสุดท้าย VIP)
* Burstable: ตั้ง Requests < Limits (ถูกประหารเป็นชนชั้นกลาง)
* BestEffort: ไม่ตั้งค่าอะไรเลย (ถูกประหารคนแรกสุดทันทีที่เครื่องมีปัญหา)
apiVersion: v1
kind: Pod
metadata:
name: payment-processing
spec:
containers:
- name: payment-app
image: my-payment:v1
resources:
requests:
memory: "1Gi"
cpu: "500m" # ครึ่งคอร์
limits:
memory: "1Gi" # ค่า Limits = Requests สร้างสถานะ Guaranteed QoS
cpu: "500m"
Use Case ในชีวิตจริง (Real-world Scenario):
ในคลัสเตอร์ของบริษัทเกมที่มีทรัพยากรจำกัด พวกเขารัน Backend สำคัญไว้ในระดับ Guaranteed (Requests=Limits) เพื่อไม่ให้โดนแตะต้อง และรันระบบวิเคราะห์ข้อมูล (Data Analytics Batch Jobs) ไว้ในระดับ BestEffort (ไม่ใส่ Requests) ในช่วงดึกที่ไม่มีคนเล่นเกม Batch Jobs เหล่านี้จะสูบ CPU/Mem ที่ว่างอยู่ไปใช้จนเกลี้ยงอย่างคุ้มค่า แต่ทันทีที่มีคนเข้าเกมจนแรมเริ่มตึง Kubelet จะเชือด Batch Jobs (BestEffort) ทิ้งทันที เพื่อคืนพื้นที่ให้ระบบหลัก
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations):
* Pitfall (ปัญหา): CPU ทะลุ Limit จะโดน "บีบคอ (Throttling)" ทำให้แอปอืด แต่ถ้า Memory ทะลุ Limit จะโดน "ยิงทิ้ง (OOMKilled - Out of Memory)" และถูกบังคับ Restart ทันที อาการ OOMKilled เป็นฝันร้ายที่สุดของ DevOps เพราะมันรบกวนผู้ใช้งานจริง (Downtime)
* Mitigation (วิธีแก้): ห้ามตั้งค่า Memory Limit สุ่มสี่สุ่มห้า ต้องรันโหลดเทสต์ (Load Test) และใช้ Monitoring อย่าง Grafana สังเกตพฤติกรรมการกิน Memory สูงสุด (Peak) ของแอปพลิเคชันก่อนเสมอ แล้วจึงบวกเผื่อบัฟเฟอร์ไปอีก 20-30% เป็นค่า Limit ส่วน CPU นั้นบางองค์กรเลือกที่จะเลิกตั้งค่า Limit ไปเลย (ใช้แค่ Request) เพื่อหลีกเลี่ยงปัญหา CPU Throttling โดยไม่จำเป็น
5. Health Probes & Workload Controllers
ทฤษฎีและกลไกการทำงาน (How it works):
Kubernetes จะรู้ได้อย่างไรว่าแอปของคุณข้างในรันพร้อมทำงานแล้ว? มันไม่สามารถเดาจากภายนอกได้ K8s จึงเตรียม "ปรอทวัดไข้ (Health Probes)" ไว้ให้คุณฝังเข้าไปใน Pod โดยมี 3 ประเภทที่แก้ปัญหาต่างกัน:
1. Liveness Probe: ถามว่า "แอปยังหายใจอยู่ไหม?" (ถ้าแอปค้าง/Deadlock และ Probe ล้มเหลว Kubelet จะ Restart คอนเทนเนอร์ทิ้งทันที)
2. Readiness Probe: ถามว่า "แอปพร้อมรับลูกค้าหรือยัง?" (ถ้าแอปกำลังบูต/เชื่อม DB และ Probe ล้มเหลว K8s จะดึง IP ของ Pod นี้ออกจาก Load Balancer ทั่วคลัสเตอร์ชั่วคราว ทราฟฟิกจะไม่ถูกส่งมาหา)
3. Startup Probe: เกราะป้องกันพิเศษ สำหรับแอปที่บูตช้ามากๆ (เช่น Java Legacy) มันจะไปสั่งปิด Liveness Probe ชั่วคราวในช่วงแรก เพื่อไม่ให้ระบบเผลอฆ่าแอปทิ้งซ้ำซากทั้งๆ ที่แอปแค่กำลังโหลด
ส่วน Workload Controllers คือหัวหน้างานที่ครอบ Pod อีกที (คุณแทบจะไม่เขียน YAML สร้าง Pod เปล่าๆ เอง) เช่น Deployment (ดูแลแอปทั่วไป ไม่มีสถานะ), StatefulSet (ดูแล Database ต้องการ IP และ Storage แน่นอน), และ DaemonSet (ดูแลระบบ Monitoring ที่ต้องไปเกิดฝังตัวอยู่ทุกๆ Node เครื่องละ 1 ตัว)
spec:
containers:
- name: api-server
image: api:v1
# ปิดวาล์วรับทราฟฟิกจนกว่าจะคืนค่า HTTP 200
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# ถ้าค้างจนคืนค่าไม่ได้ ให้ Restart ทิ้ง
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
Use Case ในชีวิตจริง (Real-world Scenario):
การอัปเดตเวอร์ชันแอปพลิเคชันแบบ Zero Downtime (Rolling Update) ผ่าน Deployment อาศัย Readiness Probe เป็นกุญแจสำคัญ เมื่อ K8s สร้าง Pod เวอร์ชันใหม่ มันจะยังไม่ส่งทราฟฟิกเข้าไป และยังไม่ลบ Pod เวอร์ชันเก่าทิ้ง จนกว่า Readiness Probe ของ Pod ใหม่จะตอบกลับมาว่า 200 OK (พร้อมให้บริการแล้ว) เมื่อพร้อม มันจึงเริ่มสลับทราฟฟิกไปหาตัวใหม่ และค่อยๆ ทยอยปิดตัวเก่าลง ทำให้ลูกค้าที่กดหน้าเว็บอยู่ไม่เจอหน้า Error 502 เลยแม้แต่คนเดียว
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations):
* Pitfall (ปัญหา): นักพัฒนาเอา Endpoint เดียวกัน (เช่น /ping หรือ /health) ไปใส่ให้ทั้ง Liveness และ Readiness และในโค้ดของ Endpoint นั้นมีการเช็คการเชื่อมต่อ Database หาก Database มีปัญหาเน็ตหลุดชั่วคราว สิ่งที่เกิดขึ้นคือ Liveness จะพัง และ K8s จะพาเหรดกันฆ่า/Restart Web Pods ทุกตัวทิ้งพร้อมๆ กันจนพินาศทั้งคลัสเตอร์ (Cascading Failure)
* Mitigation (วิธีแก้): ต้องแยกจุดประสงค์ให้ขาด:
* Readiness ควรเช็ค Deep Check (เช่น เช็ค DB, Cache) ถ้า DB พัง Pod ควรแค่หลุดออกจาก Service แต่ตัวแอปไม่ควรตาย
* Liveness ควรเป็นแค่ Shallow Check เท่านั้น (เช่น เช็คว่า HTTP thread ยังตอบสนองไหม) ไม่ควรพึ่งพา External Service อย่าง DB เด็ดขาด
🛠️ Weekend Sandbox Challenge: "The QoS Eviction Simulator"
โจทย์ปฏิบัติการ: โจทย์ท้าทายความสามารถ:
1. รัน Local Cluster (Minikube/KinD)
2. สร้าง Namespace ใหม่ และสร้าง Pod 2 ตัว:
* Pod A (Guaranteed): ตั้งค่า Requests และ Limits ของ Memory เป็น 500Mi เท่ากันเป๊ะ
* Pod B (BestEffort): ไม่ใส่ค่า Resources ใดๆ เลย
3. ความท้าทาย: ติดตั้งเครื่องมือเช่น stress หรือรันสคริปต์ Python ภายในเครื่อง Node (หรือเปิด Pod มฤตยู) เพื่อตั้งใจสูบ Memory ของระบบจนใกล้เต็ม 100%
4. พิสูจน์ผลลัพธ์: ตรวจสอบผ่าน kubectl get pods -w ว่า Pod ใดโดน Evicted ก่อนกัน จงถ่ายรูปบันทึกหลักฐานของการเกิด Node-pressure Eviction และการทำงานของ QoS Class!
💼 Senior Technical Interview Q&A
Q1: "ระหว่าง Control Plane กับ Worker Node ส่วนไหนถ้าพังแล้วส่งผลกระทบต่อ End-user (ลูกค้าที่เข้าเว็บ) ทันที และอธิบายเหตุผล?"
A: Worker Node ครับ เพราะเป็นสถานที่ที่รัน Application Workload จริงๆ หาก Worker Node ล่ม Pod ของแอปพลิเคชันจะดับไปพร้อมกับมัน ทำให้ลูกค้าเข้าเว็บไม่ได้ (หากไม่มี Pod สำรองในเครื่องอื่น) ในขณะที่ถ้า Control Plane ล่มทั้งหมด (เช่น API Server หรือ etcd ดับ) ลูกค้าที่เข้าเว็บอยู่จะไม่รู้สึกอะไรเลย เพราะ Worker Node และ Kube-proxy ยังคงทำหน้าที่ Route ทราฟฟิกให้ Pod ชุดเดิมต่อไปได้ตามปกติ สิ่งที่เราจะสูญเสียไปคือ 'ความสามารถในการแก้ไขระบบ' (เช่น สั่งสเกลเพิ่มไม่ได้, แก้ไขคอนฟิกไม่ได้, และระบบจะไม่ Reconcile สร้าง Pod ใหม่ให้หากมีพังเพิ่มเติม) จนกว่า Control Plane จะฟื้นครับ
Q2: "ทำไม OOMKilled ถึงถือว่าเป็นปัญหาใหญ่กว่า CPU Throttling ใน Kubernetes? และคุณจะรับมืออย่างไร?"
A: CPU Throttling หมายถึงคอนเทนเนอร์ถูกบีบให้ประมวลผลช้าลง ซึ่งทำให้เกิด Latency กับผู้ใช้ แต่กระบวนการทำงานยังไม่ถูกขัดจังหวะครับ แต่ OOMKilled (Out of Memory) เกิดขึ้นเมื่อ Memory ทะลุ Limit ระบบ Linux Kernel (OOM Killer) จะไม่มีทางเลือกอื่นนอกจากทำลายโปรเซสนั้นทิ้งทันที (Kill -9) ทำให้แอปพลิเคชันเกิด Downtime และข้อมูลที่รันค้างอยู่ในหน่วยความจำสูญหาย การรับมือคือ ผมจะทำ Load Testing เพื่อหา Baseline ของ Memory Usage จากนั้นตั้งค่า Memory Limits ให้ครอบคลุม Peak Load + Buffer (เช่น 20%) และตั้ง Alerts บน Prometheus ให้แจ้งเตือนหาก Memory พุ่งแตะระดับ 80% ของ Limits ก่อนที่จะเกิด OOMKilled จริงครับ
### 💻 Weekend Sandbox Challenge: "The QoS Eviction Simulator"
โจทย์ท้าทายความสามารถ:
1. รัน Local Cluster (Minikube/KinD)
2. สร้าง Namespace ใหม่ และสร้าง Pod 2 ตัว:
* Pod A (Guaranteed): ตั้งค่า Requests และ Limits ของ Memory เป็น 500Mi เท่ากันเป๊ะ
* Pod B (BestEffort): ไม่ใส่ค่า Resources ใดๆ เลย
3. ความท้าทาย: ติดตั้งเครื่องมือเช่น stress หรือรันสคริปต์ Python ภายในเครื่อง Node (หรือเปิด Pod มฤตยู) เพื่อตั้งใจสูบ Memory ของระบบจนใกล้เต็ม 100%
4. พิสูจน์ผลลัพธ์: ตรวจสอบผ่าน kubectl get pods -w ว่า Pod ใดโดน Evicted ก่อนกัน จงถ่ายรูปบันทึกหลักฐานของการเกิด Node-pressure Eviction และการทำงานของ QoS Class!
Deep Dive & Production Architecture
🟢 Basic Level (ปูพื้นฐานภาษาเข้าใจง่าย / Core Concepts)
ทฤษฎีและกลไกการทำงาน (Theory & Mechanism): แนวคิดพื้นฐานของการวางโครงสร้างระบบให้ทำงานได้อย่างถูกต้อง ตั้งแต่การเชื่อมต่อเครือข่าย การกำหนดขอบเขตทรัพยากร ไปจนถึงการสื่อสารระหว่างส่วนประกอบต่างๆ ในระบบคลาวด์
ตัวอย่างโค้ดหรือการตั้งค่า (Code/Config Example): โครงสร้างการตั้งค่าเบื้องต้น
# Basic Structural Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: basic-system-config
data:
mode: "development"
log_level: "info"Use Case ในชีวิตจริง (Real-world Scenario): ระบบแอปพลิเคชันภายในองค์กร หรือบริการทั่วไปที่มีปริมาณการใช้งานคงที่ ที่เน้นความง่ายในการจัดการและแก้ไขปัญหา
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): การละเลยการตั้งค่าความปลอดภัยพื้นฐาน แนะนำให้ใช้เครื่องมือตรวจสอบอัตโนมัติ (Linter/Scanner) ตั้งแต่ขั้นตอนการพัฒนา
🟡 Intermediate Level (โค้ด/คอนฟิกไวยากรณ์จริง / Real Implementation)
ทฤษฎีและกลไกการทำงาน (Theory & Mechanism): การออกแบบสถาปัตยกรรมระดับกลางที่คำนึงถึงความทนทาน (Resiliency) การขยายตัว (Scalability) และการควบคุมเส้นทางการส่งข้อมูลเครือข่ายอย่างมีประสิทธิภาพ
ตัวอย่างโค้ดหรือการตั้งค่า (Code/Config Example): การกำหนด Network Policy และ Resource Limits
# Intermediate Access Control & Scaling
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: api-gateway-policy
spec:
podSelector:
matchLabels:
role: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: myprojectUse Case ในชีวิตจริง (Real-world Scenario): แพลตฟอร์มอีคอมเมิร์ซที่มียอดผู้ใช้งานเพิ่มขึ้นแบบฉับพลันในบางช่วงเวลา (Spike Traffic) เช่น ช่วงแคมเปญส่งเสริมการขาย
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): การคอนฟิก Policy ผิดพลาดอาจทำให้ Service ตัดขาดจากระบบ เฝ้าระวังด้วยการทดสอบการเชื่อมต่อ (Connectivity Test) ทุกครั้งที่เปลี่ยนค่า
🔴 Professional Level (Under-the-hood & Performance/FinOps)
ทฤษฎีและกลไกการทำงาน (Theory & Mechanism): การวิเคราะห์เชิงลึกไปถึงการทำงานระดับ Kernel (เช่น eBPF) และการทำ Optimization ทรัพยากรคลาวด์ พร้อมกับการนำแนวคิด FinOps มาใช้ควบคุมค่าใช้จ่ายโดยไม่ลดทอนประสิทธิภาพ
ตัวอย่างโค้ดหรือการตั้งค่า (Code/Config Example): การปรับจูน Resource ควบคู่กับ HPA และ Node Affinity
# Professional FinOps & Performance Tuning
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: high-performance-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: data-processor
minReplicas: 3
maxReplicas: 150
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300Use Case ในชีวิตจริง (Real-world Scenario): ระบบ Streaming Data Platform ระดับโลกที่ต้องประมวลผลข้อมูลระดับ Petabytes ต่อวัน พร้อมจัดการ Cost Optimization ขั้นสูง
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): การเกิด OOMKilled แบบเงียบๆ หรือปัญหา Cloud Cost Spikes ควรตั้งแจ้งเตือนผ่าน Budget Alerts และทำ Profiling ประสิทธิภาพแอปพลิเคชันอย่างสม่ำเสมอ
🏢 Real-World Enterprise Scenario (เคสระบบการเงิน/Big Tech)
ทฤษฎีและกลไกการทำงาน (Theory & Mechanism): โครงสร้างระบบสำหรับองค์กรขนาดใหญ่ที่เน้น Multi-Region Active-Active, การทำ Disaster Recovery (DR) อัตโนมัติ, และการปฏิบัติตามมาตรฐานความปลอดภัยขั้นสูงสุด (Compliance & Governance)
ตัวอย่างโค้ดหรือการตั้งค่า (Code/Config Example): Infrastructure as Code (IaC) สำหรับ Enterprise Environment
# Enterprise Multi-AZ Infrastructure
module "enterprise_core_network" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "prod-banking-core-vpc"
cidr = "10.100.0.0/16"
azs = ["ap-southeast-1a", "ap-southeast-1b", "ap-southeast-1c"]
private_subnets = ["10.100.1.0/24", "10.100.2.0/24", "10.100.3.0/24"]
public_subnets = ["10.100.101.0/24", "10.100.102.0/24", "10.100.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = false
one_nat_gateway_per_az = true
enable_vpn_gateway = true
}Use Case ในชีวิตจริง (Real-world Scenario): ระบบ Core Banking ของธนาคารข้ามชาติ หรือระบบ Payment Gateway ที่ต้องมี Uptime 99.999% และห้ามมีข้อมูลสูญหาย (Zero Data Loss)
ข้อควรระวังและวิธีแก้ (Pitfalls & Mitigations): ความล้มเหลวระดับศูนย์ข้อมูล (Data Center Outage) แก้ไขด้วยสถาปัตยกรรม Multi-Region failover อัตโนมัติ และซ้อมแผน Disaster Recovery ทุกไตรมาส