Kubernetes คืออะไร? (ฉบับเข้าใจง่าย)
สมมติเรามีเว็บไซต์ที่รันบน server ปกติจะ SSH เข้าไป deploy เอง ถ้ามี server เดียวก็ไม่ยาก แต่ถ้ามี 3 servers ล่ะ? ต้อง deploy ทีละเครื่อง? ถ้าเครื่องหนึ่งล่ม ต้องย้ายไป deploy เครื่องอื่นเอง?
Kubernetes (เรียกสั้นๆ ว่า k8s) เป็นระบบที่จัดการเรื่องเหล่านี้ให้ — บอกมันว่า “ฉันอยากให้แอปนี้รันอยู่ 3 ตัว” แล้ว k8s จะ:
- จัดการ deploy ให้กระจายไปหลายเครื่อง
- ถ้าเครื่องไหนล่ม ย้าย app ไปเครื่องอื่นอัตโนมัติ
- จัดการ network ให้ app คุยกันได้แม้อยู่คนละเครื่อง
- ทำ load balancing กระจาย traffic ให้
ศัพท์พื้นฐานที่ต้องรู้
| คำศัพท์ | คืออะไร | เปรียบเทียบ |
|---|---|---|
| Node | เครื่อง server 1 เครื่อง | คอมพิวเตอร์ 1 เครื่อง |
| Pod | หน่วยเล็กสุดที่รัน app | กล่องที่ใส่ container(s) ไว้ |
| Container | โปรแกรมที่ถูก package พร้อม dependencies | เหมือน Docker container |
| Deployment | บอก k8s ว่าต้องการ Pod แบบไหน กี่ตัว | แบบแปลนก่อสร้าง |
| Service | ที่อยู่ถาวรสำหรับเข้าถึง Pod (Pod อาจย้ายได้) | เบอร์โทรที่โอนสายได้ |
| Ingress | กฎบอกว่า domain ไหนไปหา Service ไหน | พนักงานต้อนรับ |
| Namespace | แบ่งพื้นที่ใน cluster ไม่ให้ app ชนกัน | ห้องแต่ละห้องในตึก |
ทำไมถึงเลือก k3s?
k3s คือ Kubernetes เวอร์ชันเบา สร้างโดย Rancher Labs (ปัจจุบันเป็นส่วนหนึ่งของ SUSE) จุดเด่นคือ:
| k3s | k8s (kubeadm) | MicroK8s | |
|---|---|---|---|
| ขนาด | single binary ~70MB | หลายตัว ~500MB+ | snap package |
| Database | SQLite (default) | ต้องมี etcd cluster | dqlite |
| RAM ขั้นต่ำ | ~512MB | ~2GB+ | ~1GB |
| ติดตั้ง | คำสั่งเดียว | หลายขั้นตอน | snap install |
| เหมาะกับ | VPS, edge, lab | production ใหญ่ๆ | development |
ทั้ง 3 เป็น Certified Kubernetes เหมือนกัน — หมายความว่า kubectl, Helm, CRDs ทุกอย่างทำงานเหมือนกันหมด ต่างกันแค่วิธีติดตั้งและ resource ที่ใช้
k3s เหมาะกับ:
- VPS ที่ RAM จำกัด — ไม่อยาก waste resources ให้ control plane
- Self-hosting — ติดตั้งง่าย maintain น้อย
- Multi-node ข้าม data center — รองรับ node อยู่คนละประเทศได้
สิ่งที่ k3s มาให้พร้อม (ไม่ต้องติดตั้งเพิ่ม):
- Traefik — reverse proxy/ingress controller
- CoreDNS — DNS สำหรับ service discovery
- Flannel — overlay network สำหรับ pod-to-pod communication
Cluster Architecture: Control Plane + Workers
Cluster คือกลุ่มของ nodes (servers) ที่ทำงานร่วมกันเป็นระบบเดียว
k3s cluster แบ่ง node เป็น 2 ประเภท:
┌────────────────────────────────────────────────────────────────┐
│ k3s Cluster │
│ │
│ ┌─────────────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Control Plane │ │ Worker 1 │ │ Worker 2 │ │
│ │ (node หลัก) │ │ │ │ │ │
│ │ │ │ รัน Pods │ │ รัน Pods │ │
│ │ - API Server │ │ ตาม │ │ ตาม │ │
│ │ - Scheduler │ │ ที่ถูกสั่ง │ │ ที่ถูกสั่ง │ │
│ │ - Controller Manager│ │ │ │ │ │
│ │ - SQLite │ │ │ │ │ │
│ │ + รัน Pods ได้ด้วย │ │ │ │ │ │
│ └──────────┬───────────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────────┴──────────────────┘ │
│ Flannel overlay network │
└────────────────────────────────────────────────────────────────┘
Control Plane (สมองของ cluster):
- API Server — จุดเดียวที่ทุกอย่างคุยกัน (
kubectlก็คุยผ่าน API Server) - Scheduler — ตัดสินใจว่า Pod ใหม่ควรไปรันที่ node ไหน (ดูจาก resource ที่เหลือ)
- Controller Manager — คอยดูว่าสถานะจริงตรงกับที่เราบอกไว้ไหม (เช่น ถ้าบอกว่าต้องมี 3 pods แต่ตอนนี้มี 2 มันจะสร้างเพิ่มให้)
- SQLite — database สำหรับเก็บสถานะทั้งหมดของ cluster (k8s ปกติใช้ etcd)
Worker Nodes (แรงงานของ cluster):
- รัน Pods ตามที่ Control Plane สั่ง
- แต่ละ node มี kubelet (agent ที่คุยกับ Control Plane) และ containerd (ตัวรัน containers)
ตัวอย่าง: cluster ข้ามประเทศ
k3s รองรับ node ที่อยู่คนละ data center หรือแม้แต่คนละประเทศ:
Thailand Singapore
┌─────────────────┐ ┌─────────────────┐
│ Control Plane │ ◄──25ms──► │ Worker │
│ + Worker │ │ │
│ 8 vCPU/32GB │ │ 4 vCPU/8GB │
└────────┬────────┘ └─────────────────┘
│ <1ms
┌────────┴────────┐
│ Worker │
│ 4 vCPU/8GB │
└─────────────────┘
- Nodes ใน DC เดียวกัน: latency < 1ms
- Nodes ข้ามประเทศ: latency ~25ms (ยังใช้งานได้ดี)
- Scheduler จะกระจาย pods ตาม resource ที่เหลือของแต่ละ node
- Pods ที่ต้องใช้ local storage จะถูก pin ไว้ที่ node เดิม
Networking: Pod คุยกันข้าม Node ได้ยังไง?
นี่คือส่วนที่ซับซ้อนที่สุดของ Kubernetes — แต่เข้าใจได้ถ้าแบ่งเป็นชั้นๆ
ปัญหา
แต่ละ Pod มี IP address ของตัวเอง (เช่น 10.42.0.5) แต่ IP นี้เป็น virtual IP ที่มีอยู่แค่ใน cluster ถ้า Pod A อยู่บน node-1 (Thailand) อยากคุยกับ Pod B บน node-3 (Singapore) packet จะวิ่งข้ามไปได้ยังไง?
คำตอบ: Overlay Network (Flannel VXLAN)
Overlay Network คืออะไร? — คือ network ชั้นที่ 2 ที่สร้างขึ้นมา “ทับ” บน network จริง เหมือนอุโมงค์ลอดใต้ดิน — ข้างบน (physical network) เป็นถนนปกติ ข้างล่าง (overlay) เป็นทางลอดที่ pods ใช้คุยกัน
Flannel สร้าง overlay network ด้วยเทคโนโลยี VXLAN — ห่อ (encapsulate) packet ของ pod ไว้ใน UDP packet อีกชั้น แล้วส่งผ่าน internet ปกติ:
Pod A (Thailand) Pod B (Singapore)
│ ▲
▼ │
┌─────────┐ ┌─────────┐
│ cni0 │ bridge bridge │ cni0 │
│ (สะพาน │ │ (สะพาน │
│ เชื่อม │ │ เชื่อม │
│ pods) │ │ pods) │
└────┬────┘ └────┬────┘
▼ ▲
┌──────────┐ ┌──────────┐
│flannel.1 │ ◄─── VXLAN tunnel ────────► │flannel.1 │
│ (อุโมงค์) │ ห่อ pod packet ใน UDP │ (อุโมงค์) │
└────┬─────┘ └────┬─────┘
▼ ▲
┌─────────┐ Internet (~25ms) ┌─────────┐
│ eth0 │ ──────────────────────────── │ eth0 │
│(NIC จริง)│ │(NIC จริง)│
└─────────┘ └─────────┘
ขั้นตอนที่เกิดขึ้น:
- Pod A ส่ง packet ไปหา Pod B (ใช้ virtual IP)
- Packet ผ่าน cni0 bridge (สะพานเชื่อม pods บน node เดียวกัน)
- Kernel เห็นว่า Pod B อยู่บน node อื่น → ส่งไป flannel.1
- Flannel encapsulate (ห่อ) packet เดิมไว้ใน UDP packet ใหม่ แปะ IP จริงของ node ปลายทาง
- UDP packet วิ่งผ่าน internet ข้ามไปอีกประเทศ
- Node ปลายทางรับ → decapsulate (แกะ) → ส่งเข้า cni0 → ถึง Pod B
สิ่งสำคัญ: Flannel แบ่ง IP range ให้แต่ละ node ไม่ซ้ำกัน เช่น node-1 ได้ 10.42.0.x, node-2 ได้ 10.42.1.x ทำให้ route ถูกต้องเสมอ
Firewall — สิ่งที่มักลืม
สิ่งที่ต้องเปิดในทุกรูปแบบ firewall:
- VXLAN port — ระหว่าง ทุก node ไม่ใช่แค่ control plane (node ต้องคุยกันเป็น mesh)
- Pod CIDR + Service CIDR — ถ้าใช้ UFW ต้อง allow IP range ของ pods ด้วย ไม่งั้น pod traffic ถูกบล็อก
- Flannel interfaces — cni0 และ flannel.1 ต้องอยู่ใน trusted zone
ข้อผิดพลาดที่พบบ่อย: เพิ่ม worker node ใหม่ เปิด firewall บน control plane แล้ว แต่ลืมเปิดบน worker เดิม — ทำให้ pods บน worker เก่ากับ worker ใหม่คุยกันไม่ได้
Traffic Routing: จาก Internet ถึง Pod
เมื่อ user เปิดเว็บไซต์ที่ host บน k3s traffic ต้องวิ่งผ่านหลาย layer:
User พิมพ์ URL ในเบราว์เซอร์
│
▼
┌────────────────────────────┐
│ Reverse Proxy (nginx) │ ← รับ traffic จาก internet
│ port 80 / 443 │ ← จัดการ SSL (HTTPS)
└────────────┬───────────────┘
│
▼
┌────────────────────────────┐
│ Traefik (Ingress) │ ← อ่าน domain → เลือก Service
│ (มากับ k3s) │
└────────────┬───────────────┘
│
▼
┌────────────────────────────┐
│ Service │ ← load balance ไปหา Pods
└────────────┬───────────────┘
│
▼
┌────────────────────────────┐
│ Pod (app จริง) │ ← ประมวลผล → ส่ง response กลับ
└────────────────────────────┘
Ingress คืออะไร?
Ingress คือกฎที่บอก Traefik ว่า:
- ถ้า domain คือ
blog.example.com→ ส่งไปหา blog service - ถ้า domain คือ
app.example.com→ ส่งไปหา app service
เหมือนพนักงานต้อนรับที่ดูนามบัตร (domain) แล้วบอกว่าต้องไปห้องไหน
Ingress vs IngressRoute
Kubernetes มี Ingress มาตรฐาน แต่ Traefik มี CRD (Custom Resource) ที่ชื่อ IngressRoute ด้วย ซึ่งทำได้มากกว่า:
| Feature | Ingress (standard) | IngressRoute (Traefik CRD) |
|---|---|---|
| Basic routing | ✅ | ✅ |
| Priority (กำหนดลำดับ route) | ❌ | ✅ |
| Sticky sessions (ยึดติด pod เดิม) | ❌ | ✅ |
| Middleware (gzip, rate-limit) | ❌ | ✅ |
| ใช้กับ Traefik อื่นได้ | ✅ (standard) | ❌ (Traefik only) |
เมื่อไหร่ใช้อะไร?
- Ingress — app ทั่วไปที่แค่ต้องการ domain → service
- IngressRoute — app ที่ต้องการ WebSocket (sticky sessions), compression, หรือ routing ซับซ้อน
TLS (HTTPS) อัตโนมัติ
ทุกเว็บไซต์ควรมี HTTPS ใน Kubernetes ใช้ cert-manager ร่วมกับ Let’s Encrypt เพื่อออก TLS certificate ฟรี + auto-renew:
# แค่ใส่ annotation นี้ใน Ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
cert-manager จะ:
- เห็น Ingress ใหม่ที่มี annotation
- ขอ certificate จาก Let’s Encrypt อัตโนมัติ
- เก็บ certificate เป็น Kubernetes Secret
- ต่ออายุให้ก่อนหมดอายุ
ไม่ต้อง renew certificate เอง ไม่ต้องจ่ายเงิน
GitOps — Deploy ด้วย Git
GitOps คืออะไร? — คือแนวคิดที่ใช้ Git repo เป็น “ต้นฉบับความจริง” (source of truth) ของ infrastructure ทั้งหมด อยากเปลี่ยนอะไร → แก้ YAML ใน Git → push → ระบบ sync ให้อัตโนมัติ
ปัญหาของการ deploy แบบเดิม
แบบเดิม:
Developer → kubectl apply -f ... → Cluster
(ใครทำ? เมื่อไหร่? ทำอะไร? ไม่มี audit trail)
GitOps:
Developer → git push → Git repo → ArgoCD → Cluster
(ทุกอย่างมี commit history, review ได้, rollback ได้)
ArgoCD — GitOps Controller
ArgoCD เป็นเครื่องมือที่:
- Watch Git repo ตลอดเวลา
- เทียบ สถานะใน Git กับสถานะจริงบน cluster
- ถ้าต่างกัน → sync ให้ตรงกับ Git อัตโนมัติ
ถ้าใครแอบ kubectl edit แก้อะไรบน cluster โดยไม่ผ่าน Git → ArgoCD จะ revert กลับ ให้ตรงกับ Git (เรียกว่า selfHeal)
App of Apps Pattern
เมื่อมีหลาย apps บน cluster จัดกลุ่มด้วย App of Apps pattern:
root (Application หลัก)
│
├── infrastructure ──── cert-manager, Keycloak, ...
│ (ระบบพื้นฐาน)
│
├── platform ────────── Longhorn, Vault, ...
│ (platform services)
│
├── observability ───── Grafana, Loki, Tempo, ...
│ (monitoring stack)
│
├── apps ────────────── blog, n8n, ...
│ (user-facing apps)
│
└── games ───────────── game services
แต่ละกลุ่มเป็น AppProject ที่จำกัด scope — app ใน games project ไปแตะ namespace observability ไม่ได้ ป้องกันความผิดพลาดข้าม boundary
Storage: เก็บข้อมูลยังไง?
Pods ใน Kubernetes เป็น ephemeral (ชั่วคราว) — ถ้า pod ตาย ข้อมูลข้างในหายหมด ถ้าต้องการเก็บข้อมูลถาวร ต้องใช้ Persistent Volume (PV)
StorageClass คืออะไร? — คือ “ประเภท” ของ storage ที่ cluster มีให้ เหมือนเลือกประเภท hard drive: SSD เร็วแต่แพง, HDD ช้าแต่ถูก
ประเภท Storage ที่ใช้บ่อย
| ประเภท | คืออะไร | ข้อดี | ข้อเสีย | เหมาะกับ |
|---|---|---|---|---|
| local-path | เก็บบน disk ของ node ที่ pod รันอยู่ | เร็ว, ง่าย | pod ย้าย node ไม่ได้ | ข้อมูลไม่สำคัญ |
| Longhorn (replicated) | copy ข้อมูลไปหลาย nodes | node ล่ม ข้อมูลยังอยู่ | ช้ากว่าเพราะต้อง sync | database, ข้อมูลสำคัญ |
| Longhorn (single) | เก็บที่ node เดียว แต่ manage ด้วย Longhorn | ขยายได้, snapshot ได้ | pod ย้ายไม่ได้ | data ที่ต้องการ performance |
| hostPath | mount directory จาก node ตรงๆ | เร็วที่สุด | ไม่มี abstraction | app ที่ pin ไว้ที่ node เดิมแน่นอน |
วิธีเลือก
ข้อมูลสำคัญ + ต้อง HA?
├── ใช่ → Longhorn replicated (copy ข้าม node)
│
└── ไม่ → ต้องการ performance สูง?
├── ใช่ → Longhorn single หรือ hostPath
└── ไม่ → local-path (default, ง่ายที่สุด)
ข้อควรระวัง: ถ้าใช้ storage ที่ bind กับ node เดียว → pod จะย้าย node ไม่ได้ ถ้า node ล่ม pod จะ pending จนกว่า node กลับมา
Security Patterns
Secrets Management — เก็บ password ยังไง?
Kubernetes มี Secret object สำหรับเก็บข้อมูล sensitive (password, API key) แต่ default แค่ base64 encode (ไม่ได้ encrypt จริง) ดังนั้นควรเพิ่ม:
- Encryption at rest — k3s รองรับ encrypt secrets บน disk ด้วย AES
- External secret store — ใช้ HashiCorp Vault เก็บ secrets แยก จัดการ access control ละเอียดกว่า
Vault ทำงานยังไง? — เก็บ secrets ไว้ใน encrypted storage, ต้อง unseal (ปลดล็อก) ด้วย keys ก่อนถึงจะอ่านได้ มีระบบ Shamir’s Secret Sharing คือแบ่ง key เป็นหลายส่วน ต้องรวมกันครบถึงจะ unseal ได้
Authentication — SSO ด้วย Keycloak
แทนที่แต่ละ app จะทำระบบ login เอง ใช้ Single Sign-On (SSO):
User เข้า app A
│ ยังไม่ได้ login
▼
OAuth2 Proxy (ตัวกลาง)
│ redirect ไป
▼
Keycloak (Identity Provider)
│ user login ที่นี่ที่เดียว
▼
ได้ token กลับมา
│
▼
เข้า app A ได้ (และ app B, C ได้ด้วยโดยไม่ต้อง login อีก)
- Keycloak = ศูนย์กลาง login สร้าง user ที่เดียว ใช้ได้ทุก app
- OAuth2 Proxy = ตัวกลางวางหน้า app แต่ละตัว ทำให้ app ไม่ต้องเขียน auth logic เอง
Observability — Monitor ระบบยังไง?
Self-host ทุกอย่าง = ต้อง monitor ทุกอย่าง ไม่มี managed service คอยแจ้งเตือนให้
3 เสาหลักของ Observability
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Metrics │ │ Logs │ │ Traces │
│ (ตัวเลข) │ │ (ข้อความ) │ │ (เส้นทาง) │
│ │ │ │ │ │
│ CPU 40% │ │ ERROR: conn │ │ Request A: │
│ Memory 53% │ │ refused at │ │ svc-1 → │
│ Requests/s │ │ line 42 │ │ svc-2 → │
│ Error rate │ │ │ │ svc-3 (50ms)│
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────┐
│ Grafana (Dashboard) │
│ ดูทุกอย่างในที่เดียว │
└──────────────────────────────────────────────┘
| เสา | คืออะไร | เครื่องมือ | ใช้ตอบคำถาม |
|---|---|---|---|
| Metrics | ตัวเลขที่เปลี่ยนแปลงตามเวลา | Victoria Metrics (แทน Prometheus, กิน RAM น้อยกว่า) | “CPU สูงขึ้นตั้งแต่เมื่อไหร่?” |
| Logs | ข้อความจากโปรแกรม | Loki | “Error message บอกว่าอะไร?” |
| Traces | เส้นทางของ request ข้าม services | Tempo | “Request ช้าเพราะติดที่ service ไหน?” |
Auto-instrumentation ด้วย OTel Operator
OpenTelemetry (OTel) Operator สามารถ inject sidecar เข้า pods อัตโนมัติ ทำให้ app ส่ง metrics/logs/traces ได้โดย ไม่ต้องแก้ code ของ app เลย แค่ annotate pod ว่าต้องการ instrumentation
บทเรียนจาก Production
อย่า Restart k3s ถ้าไม่จำเป็น
k3s มี script k3s-killall.sh ที่ถูกเรียกตอน restart ซึ่งจะลบ network interfaces (flannel.1) และ iptables rules ทิ้งหมด ทำให้ pod networking พังทั้ง cluster ต้อง rebuild manual
แนวทาง: ถ้าต้องเปลี่ยน config ลองหาวิธีที่ไม่ต้อง restart ก่อน เช่น kubectl apply แก้ที่ Kubernetes level แทน
Backup Secrets เป็นนิสัย
ถ้า encryption key สำหรับ Kubernetes secrets หาย → secrets ทั้งหมดจะอ่านไม่ได้อีกเลย ต้อง recreate ทั้งหมด
แนวทาง: export secrets ออกมาเก็บไว้ที่อื่นเป็นประจำ อย่าพึ่ง encryption key ตัวเดียว
Firewall ต้องเปิดแบบ Mesh
k3s nodes ต้องคุยกันเป็น mesh (ทุก node ↔ ทุก node) ไม่ใช่แค่ star (worker ↔ control plane)
เพิ่ม worker ใหม่ = ต้องเปิด firewall บน ทุก node ที่มีอยู่ ไม่ใช่แค่ control plane
ArgoCD Memory Limit
ArgoCD application-controller กิน memory ตาม จำนวน applications ที่ manage ถ้ามี 20+ apps ควรเพิ่ม memory limit ไม่งั้นจะ OOMKilled เป็นประจำ
Stale EndpointSlice = 503 Error
Traefik v3 ใช้ EndpointSlice (แทน Endpoints เดิม) ในการ route traffic บางครั้งหลัง pod restart, EndpointSlice เก่าค้างอยู่ → Traefik route ไปหา IP ที่ไม่มีแล้ว → 503
แก้: kubectl delete endpointslice <name> แล้ว controller จะสร้างใหม่ให้
สรุป
| หัวข้อ | เครื่องมือ | ทำหน้าที่ |
|---|---|---|
| Orchestration | k3s | จัดการ containers บนหลาย nodes |
| Networking | Flannel (VXLAN) | ให้ pods คุยกันข้าม node ได้ |
| Ingress | Traefik | route traffic จาก domain ไปหา pods |
| TLS | cert-manager + Let’s Encrypt | HTTPS อัตโนมัติ ฟรี |
| GitOps | ArgoCD | deploy ผ่าน Git, auto-sync |
| Storage | Longhorn + local-path | เก็บข้อมูลถาวร replicate ข้าม node |
| Secrets | Vault | เก็บ password/API keys อย่างปลอดภัย |
| Auth | Keycloak + OAuth2 Proxy | SSO login ที่เดียวใช้ทุก app |
| Monitoring | Victoria Metrics + Grafana + Loki + Tempo | metrics, logs, traces, dashboards |
Kubernetes ไม่จำเป็นต้องซับซ้อน — k3s ทำให้เริ่มต้นได้ง่าย ติดตั้งด้วยคำสั่งเดียว แล้วค่อยๆ เพิ่ม components ที่ต้องการ ถ้ากำลังคิดจะลอง self-host อะไรสักอย่าง k3s เป็นจุดเริ่มต้นที่ดี