ก้าวข้ามขีดจำกัดของการรันคอนเทนเนอร์แบบเดี่ยว สู่การบริหารจัดการ Cluster ระดับ Enterprise ด้วย K8s
เราได้เรียนรู้การนำแอปพลิเคชันใส่ลงในกล่อง (Container)
พิมพ์เขียวของแอปฯ ที่รวมโค้ดและไลบรารีทุกอย่างไว้
แอปฯ ที่กำลังรันอยู่ แยกขาดจากระบบหลัก
เครื่องมือรันหลายคอนเทนเนอร์พร้อมกันบนเครื่องเดียว
คำสั่ง `docker-compose up` หรือ `docker run` อาจจะเพียงพอสำหรับการทดสอบแอปพลิเคชันในสภาพแวดล้อมการพัฒนา (Development Environment) เท่านั้น
เมื่อมีผู้ใช้งานเพิ่มขึ้นอย่างมหาศาล การขยาย (Scale) คอนเทนเนอร์อยู่บนเครื่องเดียวจะทำให้ทรัพยากร (CPU/RAM) ไม่เพียงพอ
ในสถานการณ์ Production ระดับ Enterprise ระบบต้องการความพร้อมใช้งานสูง (HA) และการบริหารจัดการที่สามารถ Load Balance ข้ามหลายเซิร์ฟเวอร์ พร้อมระบบกู้คืนอัตโนมัติ (Intelligent Failovers)
แพลตฟอร์ม Orchestration จะช่วยขยายขีดความสามารถในการจัดการวงจรชีวิต (Lifecycle) ให้กับแอปพลิเคชันที่ซับซ้อนและมีหลายคอนเทนเนอร์ที่ถูก Deploy ไว้บน Cluster ของเครื่องโฮสต์หลายๆ เครื่อง
กระบวนการของ Orchestration เกี่ยวข้องกับเครื่องมือที่สามารถทำงานแบบอัตโนมัติ (Automate) ครอบคลุมตั้งแต่การวางคอนเทนเนอร์เริ่มต้น การย้ายคอนเทนเนอร์ไปยังโฮสต์อื่นตามความเหมาะสม ไปจนถึงการ Scale และทำ Failover
มีซอฟต์แวร์หลายตัวที่เกิดมาเพื่อแก้ปัญหานี้
มาพร้อมกับ Docker ใช้งานง่าย แต่ฟีเจอร์อาจไม่ซับซ้อนเท่าตัวอื่น
สร้างมาจาก Apache Mesos เหมาะสำหรับ Datacenter ขนาดใหญ่
ผู้นำตลาดปัจจุบันที่สร้างโดย Google กลายเป็นมาตรฐานหลักของอุตสาหกรรม
Kubernetes เป็นแพลตฟอร์มแบบ Open-source สำหรับทำระบบอัตโนมัติในการ Deploy, Scale และจัดการแอปพลิเคชันที่เป็นคอนเทนเนอร์ ข้ามกลุ่มของโฮสต์ (Clusters of hosts)
*มักถูกเรียกย่อๆ ว่า K8s (K ตามด้วยตัวอักษร 8 ตัว และจบด้วย s)
กระจาย Traffic ไม่ให้คอนเทนเนอร์ตัวใดตัวหนึ่งรับโหลดหนักเกินไป
จัดการเชื่อมต่อ Storage (เช่น Local, AWS EBS, NFS) เข้ากับแอปฯ อัตโนมัติ
อัปเดตแอปเวอร์ชันใหม่แบบไม่สะดุด และถอยกลับได้ทันทีถ้าพัง
รีสตาร์ทคอนเทนเนอร์ที่พัง หรือย้ายไปเครื่องอื่นเมื่อโฮสต์มีปัญหา
ระบบถูกออกแบบเป็น Cluster ที่แบ่งเป็น 2 ส่วนหลักๆ
(Control Plane)
ทำหน้าที่เป็นสมองสั่งการ จัดการและควบคุมภาพรวมของ Cluster
ประตูหน้าบ้านของ K8s ทุกการสื่อสาร (UI, CLI) ต้องวิ่งผ่านตัวนี้
ฐานข้อมูล Key-Value ความเร็วสูง เก็บข้อมูลสถานะทั้งหมดของ Cluster (Source of Truth)
ทำหน้าที่ตัดสินใจว่า คอนเทนเนอร์ตัวใหม่ ควรไปรันที่ Worker Node เครื่องไหน
คอยตรวจสอบว่าระบบทำงานตรงตามสถานะที่ผู้ใช้ต้องการหรือไม่ (Desired State)
คอมพิวเตอร์ลูกข่ายที่รับหน้าที่รันแอปพลิเคชัน (Workloads) จริงๆ
เอเจนต์ที่รับคำสั่งจาก Master Node
จัดการกฎด้าน Network และการสื่อสาร
ตัวรันคอนเทนเนอร์ (เช่น containerd, CRI-O, Docker)
"ผู้จัดการประจำสาขา"
"เจ้าหน้าที่จราจรเครือข่าย"
ใน Kubernetes เราไม่สั่งงานโดยตรงไปที่ Container แต่เราสั่งผ่านสิ่งที่เรียกว่า "Objects"
Kubernetes จะจัดกลุ่มคอนเทนเนอร์ที่ทำงานร่วมกันเป็นแอปพลิเคชัน ให้อยู่ในหน่วยทางตรรกะ (Logical units) เดียวกันเพื่อการจัดการที่ง่ายขึ้น
จุดเด่นของ Pods:
Container
ตัวแอปพลิเคชัน
Pod
กล่องหุ้ม Container
*Kubernetes ไม่สนว่าข้างในรันด้วย Docker หรือ Container Runtime อื่น แต่มันจัดการผ่าน Pod
ในความเป็นจริง เราไม่ค่อยสั่งสร้าง Pod ขึ้นมาตรงๆ เพราะถ้า Pod ตาย มันก็ตายไปเลย ไม่ฟื้นขึ้นมาใหม่
คุณแค่บอกว่า "อยากได้อะไร" เดี๋ยว K8s จัดการให้เอง
Desired State
"ฉันขอ Pod ของ Nginx 3 ตัว"
Current State
"ตอนนี้มี Pod รันอยู่แค่ 2 ตัว (อีกตัวพัง)"
"ปัญหาของ Pod คือ IP ไม่คงที่"
เวลา Deployment สร้าง Pod ใหม่ขึ้นมาแทนตัวที่พัง IP Address ของ Pod นั้นจะเปลี่ยนไปเสมอ ทำให้ส่วนอื่นของระบบ (เช่น Frontend) ไม่รู้ว่าจะต้องส่ง Request ไปที่ IP ไหน
ให้ IP ภายใน Cluster คุยกันเองได้เท่านั้น 외부 (Internet) เข้าถึงไม่ได้ เหมาะสำหรับ Database
เปิด Port เฉพาะ (30000-32767) บนทุกๆ Worker Node สามารถเข้าถึงผ่าน `NodeIP:NodePort`
สั่งให้ Cloud Provider (เช่น AWS, Azure) จ่าย External IP เพื่อรับ Traffic จาก Internet โดยตรง
เปรียบเสมือน "Cluster เสมือน (Virtual Clusters)" ที่ซ้อนอยู่ใน Cluster จริง
ช่วยในการแบ่งขอบเขตและแยก Resource ออกจากกัน เหมาะสำหรับ:
การสั่งงาน K8s เราจะไม่ค่อยใช้คำสั่ง Command line ตรงๆ (Imperative) แต่เราจะเขียนไฟล์ Manifests ด้วยภาษา YAML (Declarative)
ข้อดี: สามารถเก็บไฟล์ YAML ไว้ใน Git (Version Control) เพื่อติดตามการแก้ไข และทำ GitOps ได้
ทุกๆ Manifest file ใน K8s จะต้องประกอบด้วย 4 ส่วนสำคัญ (Root fields):
apiVersion:
ระบุเวอร์ชันของ API K8s (เช่น v1, apps/v1)
kind:
ชนิดของ Object (เช่น Pod, Deployment, Service)
metadata:
ข้อมูลระบุตัวตน (เช่น name, labels, namespace)
spec:
สเปคที่ต้องการให้ทำงาน (เช่น container image, จำนวน replicas, พอร์ต)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3 # ขอ 3 สำเนา
selector:
matchLabels:
app: nginx
template: # (ข้อมูลส่วนของ Pod)
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer # ขอ IP ภายนอก
selector:
app: nginx # ค้นหา Pod ที่มีป้ายชื่อ (label) นี้
ports:
- protocol: TCP
port: 80 # พอร์ตของ Service
targetPort: 80 # พอร์ตของ Container
เมื่อเขียน YAML เสร็จ เราจะใช้เครื่องมือ `kubectl` ในการสั่งรัน K8s
# คำสั่งเวทมนตร์ (สร้างทุกอย่างตามที่ระบุในไฟล์)
$ kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deployment created
# ตรวจสอบว่า Pod รันขึ้นมาหรือยัง
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-7fb96c846b-xyz12 1/1 Running 0 10s
nginx-deployment-7fb96c846b-abc34 1/1 Running 0 10s
nginx-deployment-7fb96c846b-def56 1/1 Running 0 10s
การติดตั้ง K8s ด้วยตัวเองตั้งแต่ศูนย์ (The Hard Way) ค่อนข้างซับซ้อน ปัจจุบัน Cloud Providers มักจะให้บริการ Managed Kubernetes เพื่อดูแล Master Node ให้เรา:
*ผู้พัฒนาเพียงแค่กำหนด Worker Node และสั่งงานผ่าน `kubectl` ทำให้ชีวิตง่ายขึ้นมหาศาล
มีคำถามเกี่ยวกับ Kubernetes Architecture หรือ Concepts ไหมครับ?
ในส่วนปฏิบัติการถัดไป เราจะนำทฤษฎีมาลองปฏิบัติจริง โดยการจำลอง K8s Cluster ลงบนเครื่องคอมพิวเตอร์ของคุณ!
จำลอง K8s Cluster บนเครื่องส่วนตัว และทดลอง Deploy แอปพลิเคชันแรกของคุณ
kubectl CLIMinikube เป็นเครื่องมือที่ใช้สร้าง K8s Cluster แบบ 1-Node (รวม Master/Worker ในตัว) สำหรับใช้พัฒนาและทดสอบบนเครื่องส่วนตัว (มี Docker เป็น Prerequisites)
# 1. เปิด Terminal (หรือ PowerShell/WSL) แล้วพิมพ์คำสั่งเริ่มต้น Minikube
$ minikube start
# ผลลัพธ์ที่ควรจะเห็น (อาจใช้เวลาดาวน์โหลด Image สักพักในครั้งแรก):
😄 minikube vX.X.X on ...
✨ Automatically selected the docker driver
🐳 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
kubectl คือไม้กายสิทธิ์ของเราในการสั่งงาน Kubernetes ลองใช้คำสั่งเพื่อเช็คสถานะ Cluster กัน
# 1. ดูข้อมูลการเชื่อมต่อของ Cluster
$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:XXXXX
CoreDNS is running at https://127.0.0.1:XXXXX/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
# 2. ตรวจสอบโหนด (Nodes) ที่รันอยู่
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 2m v1.x.x
เราจะใช้วิธีแบบ Declarative โดยการเขียนไฟล์ YAML เพื่อบอก K8s ว่าเราต้องการรัน Nginx (Web Server)
# สร้างไฟล์ชื่อ nginx-pod.yaml
$ nano nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-pod # ชื่อของ Pod
labels:
app: web # ป้ายกำกับ (สำคัญมากตอนทำ Service)
spec:
containers:
- name: nginx-container
image: nginx:latest # ดึง Image Nginx จาก Docker Hub
ports:
- containerPort: 80 # พอร์ตที่คอนเทนเนอร์ทำงาน
นำไฟล์ YAML ไปรันบน Kubernetes Cluster และคอยดูสถานะการสร้าง Pod
# 1. Apply ไฟล์ YAML
$ kubectl apply -f nginx-pod.yaml
pod/my-nginx-pod created
# 2. ดูสถานะของ Pods ทั้งหมด (อาจจะขึ้น ContainerCreating รอสักครู่)
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-nginx-pod 1/1 Running 0 15s
# 3. ขอดูรายละเอียดเชิงลึกของ Pod (เอาไว้ใช้เวลา Error)
$ kubectl describe pod my-nginx-pod
ถึง Pod จะรันแล้ว แต่เราจะเข้าเว็บจากเบราว์เซอร์เราไม่ได้ เพราะมันอยู่ใน Private IP ของ K8s! เราต้องสร้าง Service ชนิด NodePort เพื่อเจาะช่องโหว่ (Expose) ออกมา
# สร้างไฟล์ชื่อ nginx-svc.yaml
$ nano nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort # เปิดพอร์ตที่ระดับ Node (เครื่อง Minikube)
selector:
app: web # 🌟 ตรงนี้ต้องตรงกับ Label ของ Pod! (app: web)
ports:
- port: 80 # พอร์ตของ Service
targetPort: 80 # พอร์ตของ Container (Nginx)
nodePort: 30080 # พอร์ตที่จะถูกเปิดให้เข้าถึงได้จากภายนอก (30000-32767)
Deploy ตัว Service ขึ้นไปบน Cluster เพื่อเชื่อมต่อกับ Pod ที่รันอยู่
# 1. Apply ไฟล์ Service YAML
$ kubectl apply -f nginx-svc.yaml
service/nginx-service created
# 2. ตรวจสอบสถานะของ Services
$ kubectl get svc
สังเกตว่า nginx-service ถูกสร้างขึ้นมาและชี้ Port 80 ไปที่พอร์ตภายนอก 30080 แล้ว
Minikube มีเครื่องมืออำนวยความสะดวกในการหา IP และ Port เพื่อเปิดเว็บไซต์ผ่านเบราว์เซอร์อัตโนมัติ
# พิมพ์คำสั่งนี้ใน Terminal
$ minikube service nginx-service
|-----------|---------------|-------------|
| NAMESPACE | NAME | TARGET PORT |
|-----------|---------------|-------------|
| default | nginx-service | 80 |
|-----------|---------------|-------------|
🎉 Opening service default/nginx-service in default browser...
เบราว์เซอร์ของคุณจะถูกเปิดขึ้นมาที่ URL เช่น http://127.0.0.1:XXXXX หรือ http://192.168.49.2:30080
สาเหตุ: พิมพ์ชื่อ Image ผิด หรือระบบดึง Image จาก Docker Hub ไม่ได้
แก้: ใช้คำสั่ง kubectl describe pod [name] เพื่อดู Error Log บรรทัดล่างสุด
สาเหตุ: แอปพลิเคชันในคอนเทนเนอร์แครชทันทีที่รัน
แก้: ดูสาเหตุการพังได้ด้วยคำสั่ง kubectl logs [name]
สาเหตุ: Service ไม่เจอ Pod หรือระบุ Port ผิด
แก้: เช็ค selector (app: web) ใน Service ว่าสะกดตรงกับ labels ใน Pod แบบตัวอักษรต่อตัวอักษรหรือไม่
nginx-pod.yamlnginx-svc.yamlkubectl get pods และ kubectl get svc โชว์สถานะ Running และพอร์ตminikube stop เมื่อทำ Lab เสร็จเพื่อคืนทรัพยากรให้คอมพิวเตอร์ของคุณ