ข้ามไปยังเนื้อหา

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
VM stack vs container stack

ชั้น hypervisor และ guest OS หายไปในโมเดล container container หลายตัวบน host เดียวกันแชร์ kernel เดียว ทำให้ขนาดต่อ container เล็กลงอย่างมาก

  • Microservices — แต่ละบริการส่งมอบเป็น image ของตัวเอง ปรับขนาดได้อิสระ และรีสตาร์ทโดยไม่กระทบ sibling อื่น
  • CI/CD pipelines — container แบบชั่วคราวให้ทุก build มี environment ที่สะอาดและทำซ้ำได้ ซึ่งจะหายไปเมื่อเสร็จสิ้น
  • environment นักพัฒนาที่สอดคล้องกัน — image เดียวกันทำงานบนแล็ปท็อปของนักพัฒนา ใน CI และในโปรดักชัน กำจัดบั๊ก “works on my machine”
  • การขยายขนาดแนวนอนที่รวดเร็ว — container instance ใหม่เริ่มต้นในมิลลิวินาที ทำให้ auto-scaling ตอบสนองได้ดี
  • การแยกความปลอดภัยที่แข็งแกร่ง — container ที่ถูกโจมตีอาจหลุดออกสู่ kernel host ได้ในทางทฤษฎี; ขอบเขต hypervisor ของ VM เป็นกำแพงที่แข็งแกร่งกว่ามาก
  • ต่างตระกูล OS — การรัน Windows workloads บน host Linux (หรือกลับกัน) ต้องใช้ VM เพราะ container แชร์ kernel host
  • application เลกาซี — ซอฟต์แวร์ที่ต้องการเวอร์ชัน kernel เฉพาะ, kernel module หรือการกำหนดค่าระดับระบบที่ไม่สามารถแชร์กับ host ได้

คำสองคำนี้มักสับสนกัน ความแตกต่างมีความแม่นยำดังนี้:

  • 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
Image layers vs container layers

การลบ container จะลบเฉพาะ writable layer ของตัวเอง image พื้นฐานยังคงอยู่และสามารถนำมาใช้สร้าง container ใหม่ได้ทันที

ตัวเลือกBenefitCost
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 ทำไม่ได้

container แชร์อะไรกับ host ที่ VM ไม่แชร์?
ข้อใดอธิบายได้ดีที่สุดว่าทำไม container เริ่มต้นเร็วกว่า VM?
คุณต้องการรัน Windows workload บน host Linux ควรใช้อะไร?
ความสัมพันธ์ระหว่าง Docker image กับ Docker container คืออะไร?