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) จุดเด่นคือ:

k3sk8s (kubeadm)MicroK8s
ขนาดsingle binary ~70MBหลายตัว ~500MB+snap package
DatabaseSQLite (default)ต้องมี etcd clusterdqlite
RAM ขั้นต่ำ~512MB~2GB+~1GB
ติดตั้งคำสั่งเดียวหลายขั้นตอนsnap install
เหมาะกับVPS, edge, labproduction ใหญ่ๆ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 จริง)│
└─────────┘                               └─────────┘

ขั้นตอนที่เกิดขึ้น:

  1. Pod A ส่ง packet ไปหา Pod B (ใช้ virtual IP)
  2. Packet ผ่าน cni0 bridge (สะพานเชื่อม pods บน node เดียวกัน)
  3. Kernel เห็นว่า Pod B อยู่บน node อื่น → ส่งไป flannel.1
  4. Flannel encapsulate (ห่อ) packet เดิมไว้ใน UDP packet ใหม่ แปะ IP จริงของ node ปลายทาง
  5. UDP packet วิ่งผ่าน internet ข้ามไปอีกประเทศ
  6. 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 ด้วย ซึ่งทำได้มากกว่า:

FeatureIngress (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 จะ:

  1. เห็น Ingress ใหม่ที่มี annotation
  2. ขอ certificate จาก Let’s Encrypt อัตโนมัติ
  3. เก็บ certificate เป็น Kubernetes Secret
  4. ต่ออายุให้ก่อนหมดอายุ

ไม่ต้อง 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 เป็นเครื่องมือที่:

  1. Watch Git repo ตลอดเวลา
  2. เทียบ สถานะใน Git กับสถานะจริงบน cluster
  3. ถ้าต่างกัน → 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 ข้อมูลไปหลาย nodesnode ล่ม ข้อมูลยังอยู่ช้ากว่าเพราะต้อง syncdatabase, ข้อมูลสำคัญ
Longhorn (single)เก็บที่ node เดียว แต่ manage ด้วย Longhornขยายได้, snapshot ได้pod ย้ายไม่ได้data ที่ต้องการ performance
hostPathmount directory จาก node ตรงๆเร็วที่สุดไม่มี abstractionapp ที่ 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 ข้าม servicesTempo“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 จะสร้างใหม่ให้

สรุป

หัวข้อเครื่องมือทำหน้าที่
Orchestrationk3sจัดการ containers บนหลาย nodes
NetworkingFlannel (VXLAN)ให้ pods คุยกันข้าม node ได้
IngressTraefikroute traffic จาก domain ไปหา pods
TLScert-manager + Let’s EncryptHTTPS อัตโนมัติ ฟรี
GitOpsArgoCDdeploy ผ่าน Git, auto-sync
StorageLonghorn + local-pathเก็บข้อมูลถาวร replicate ข้าม node
SecretsVaultเก็บ password/API keys อย่างปลอดภัย
AuthKeycloak + OAuth2 ProxySSO login ที่เดียวใช้ทุก app
MonitoringVictoria Metrics + Grafana + Loki + Tempometrics, logs, traces, dashboards

Kubernetes ไม่จำเป็นต้องซับซ้อน — k3s ทำให้เริ่มต้นได้ง่าย ติดตั้งด้วยคำสั่งเดียว แล้วค่อยๆ เพิ่ม components ที่ต้องการ ถ้ากำลังคิดจะลอง self-host อะไรสักอย่าง k3s เป็นจุดเริ่มต้นที่ดี