container กับ VM
ความแตกต่างพื้นฐาน
หัวข้อที่มีชื่อว่า “ความแตกต่างพื้นฐาน”ทั้ง container และ VM (VM) แก้ปัญหาเดียวกัน นั่นคือการรันซอฟต์แวร์ใน environment ที่แยกออกจากกัน แต่ทั้งสองบรรลุการแยกนี้ที่ชั้นต่างกันของสแต็ก
VM บูตระบบปฏิบัติการเกสต์แบบเต็มรูปแบบภายใน hypervisor VM แต่ละตัวมี kernel ไลบรารีระบบ และ init system ของตัวเอง ทำให้ VM มีน้ำหนักมาก: ใช้เวลาเป็นวินาที (บางครั้งเป็นนาที) ในการเริ่มต้น และใช้แรมหลายร้อยเมกะไบต์ก่อนที่ application ของคุณจะโหลดด้วยซ้ำ
container ข้ามขั้นตอน guest OS ทั้งหมด โดยแชร์ kernel ของ host และแยกเฉพาะ process namespace, filesystem และ network โดยใช้ฟีเจอร์ kernel Linux (namespaces และ cgroups) ทำให้ container มีน้ำหนักเบา: การเริ่มต้นวัดเป็นมิลลิวินาที และการใช้หน่วยความจำน้อยมาก
การเปรียบเทียบสแต็ก
หัวข้อที่มีชื่อว่า “การเปรียบเทียบสแต็ก”flowchart TB
subgraph VM["Virtual Machine stack"]
direction TB
vmApp["Application"] --> vmGuest["Guest OS (kernel + system libs)"]
vmGuest --> vmHyper["Hypervisor (VMware, KVM, Hyper-V)"]
vmHyper --> vmHost["Host OS Kernel"]
vmHost --> vmHw["Hardware"]
end
subgraph CT["Container stack"]
direction TB
ctApp["Application"] --> ctRt["Container Runtime (containerd / runc)"]
ctRt --> ctHost["Host OS Kernel"]
ctHost --> ctHw["Hardware"]
end ชั้น hypervisor และ guest OS หายไปในโมเดล container container หลายตัวบน host เดียวกันแชร์ kernel เดียว ทำให้ขนาดต่อ container เล็กลงอย่างมาก
เมื่อใดควรใช้ container
หัวข้อที่มีชื่อว่า “เมื่อใดควรใช้ container”- Microservices — แต่ละบริการส่งมอบเป็น image ของตัวเอง ปรับขนาดได้อิสระ และรีสตาร์ทโดยไม่กระทบ sibling อื่น
- CI/CD pipelines — container แบบชั่วคราวให้ทุก build มี environment ที่สะอาดและทำซ้ำได้ ซึ่งจะหายไปเมื่อเสร็จสิ้น
- environment นักพัฒนาที่สอดคล้องกัน — image เดียวกันทำงานบนแล็ปท็อปของนักพัฒนา ใน CI และในโปรดักชัน กำจัดบั๊ก “works on my machine”
- การขยายขนาดแนวนอนที่รวดเร็ว — container instance ใหม่เริ่มต้นในมิลลิวินาที ทำให้ auto-scaling ตอบสนองได้ดี
เมื่อใดควรใช้ VM
หัวข้อที่มีชื่อว่า “เมื่อใดควรใช้ VM”- การแยกความปลอดภัยที่แข็งแกร่ง — container ที่ถูกโจมตีอาจหลุดออกสู่ kernel host ได้ในทางทฤษฎี; ขอบเขต hypervisor ของ VM เป็นกำแพงที่แข็งแกร่งกว่ามาก
- ต่างตระกูล OS — การรัน Windows workloads บน host Linux (หรือกลับกัน) ต้องใช้ VM เพราะ container แชร์ kernel host
- application เลกาซี — ซอฟต์แวร์ที่ต้องการเวอร์ชัน kernel เฉพาะ, kernel module หรือการกำหนดค่าระดับระบบที่ไม่สามารถแชร์กับ host ได้
image กับ container
หัวข้อที่มีชื่อว่า “image กับ container”คำสองคำนี้มักสับสนกัน ความแตกต่างมีความแม่นยำดังนี้:
- image คือ blueprint แบบ static อ่านอย่างเดียว — snapshot ของ layered filesystem ที่รวม application dependencies และ metadata ของคุณ image สร้างครั้งเดียวและแชร์ผ่าน registry
- container คือ instance ที่กำลังทำงาน (หรือหยุด) ของ image เมื่อ Docker เริ่ม container Docker จะเพิ่ม thin writable layer ทับบน read-only image layers คุณสามารถรัน container หลายตัวจาก image เดียวกันพร้อมกัน; ทั้งหมดแชร์ image layers เดียวกัน แต่แต่ละตัวได้รับ writable layer ของตัวเอง
flowchart TB
subgraph IMG["Image (read-only layers)"]
direction TB
i3["Layer 3: app binary"]
i2["Layer 2: python:3.12"]
i1["Layer 1: debian:bookworm-slim"]
i3 --> i2 --> i1
end
subgraph CON["Container = Image + writable layer"]
direction TB
cw["Writable layer (runtime changes)"]
c3["Layer 3: app binary (shared, read-only)"]
c2["Layer 2: python:3.12 (shared, read-only)"]
c1["Layer 1: debian:bookworm-slim (shared, read-only)"]
cw --> c3 --> c2 --> c1
end การลบ container จะลบเฉพาะ writable layer ของตัวเอง image พื้นฐานยังคงอยู่และสามารถนำมาใช้สร้าง container ใหม่ได้ทันที
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| container | เริ่มต้นเร็ว (มิลลิวินาที) ใช้ทรัพยากรน้อยกว่า VM มาก | แชร์ kernel กับ host จึงมีขอบเขตการแยกที่อ่อนกว่า |
| VM | แยกด้วย hypervisor แข็งแกร่งกว่ามาก รองรับ OS ต่างตระกูลได้ | ต้องมี guest OS เต็มรูปแบบ บูตช้า และใช้แรมเยอะ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- คิดว่า container ให้การแยกที่แข็งแกร่งเท่า VM ทั้งที่ container ยังแชร์ kernel เดียวกับ host
- พยายามรัน workload ที่ต้องใช้ OS ต่างตระกูล (เช่น Windows บน host Linux) ด้วย container ทั้งที่กรณีนี้ต้องใช้ VM
- สับสนระหว่าง image (blueprint แบบ static) กับ container (instance ที่กำลังทำงาน) เวลาวางแผน deployment
💡 ตัวอย่างจากของจริง
Google รัน internal system ชื่อ Borg ที่เป็นต้นแบบของ Kubernetes โดย Borg จัดการ container นับพันล้านตัวต่อสัปดาห์มานานกว่าทศวรรษ เพราะ container เบาพอที่จะสเกลในระดับนั้นได้ ในต้นทุนที่ VM ทำไม่ได้