Docker DevOps Infrastructure

Docker Containers vs VMs — ต่างกันยังไง ใช้ตัวไหนดี?

By Anirach Mingkhwan DevOps & Vibe Coding 2026
Docker Containers vs VMs — cute dog illustration

จากโพสต์ที่แล้วเราพูดถึง CI/CD Pipeline ว่ามันช่วยให้เรา build, test, deploy แบบอัตโนมัติ

แต่เคยมั้ยที่... "ในเครื่องฉันรันได้นะ แต่ขึ้น server แล้วพัง" 🤦

ปัญหานี้เกิดจากความแตกต่างของ environment — เวอร์ชันของ OS, library, config ต่างกัน ทำให้ code ที่ทำงานได้ในเครื่องเรากลับพังในเครื่องอื่น

วิธีแก้คือ ทำให้ทุกที่ใช้ environment เดียวกัน ซึ่งมี 2 แนวทางหลัก:

  1. Virtual Machines (VMs) — จำลองเครื่องคอมพิวเตอร์ทั้งเครื่อง
  2. Docker Containers — จำลองแค่สิ่งที่ app ต้องการ

มาดูกันว่าทั้งสองอย่างคืออะไร ต่างกันยังไง แล้วควรใช้ตัวไหนเมื่อไหร่


Virtual Machine (VM) คืออะไร?

VM (Virtual Machine) คือการจำลองคอมพิวเตอร์ทั้งเครื่องด้วย software — มี CPU, RAM, Disk, Network เสมือนครบ รันอยู่บนเครื่องจริง (Host) ผ่าน Hypervisor ที่จัดสรร resource ให้แต่ละ VM เหมือนแบ่งห้องในอพาร์ทเมนท์ — แต่ละ VM เป็นอิสระจากกัน ติดตั้ง OS ต่างกันได้ แม้ VM หนึ่งพังก็ไม่กระทบ VM อื่น

Host Machine
Hypervisor
VM 1
App
Libs
Guest OS
VM 2
App
Libs
Guest OS
Host OS
Hardware

สังเกตว่า แต่ละ VM มี Guest OS ของตัวเอง ทำให้:

Hypervisor ยอดนิยม:


Docker Container คืออะไร?

Container คือการจำลองแค่ environment ที่ app ต้องการ — ไม่ต้องจำลอง OS ทั้งตัว! Container ใช้ kernel ร่วมกับ Host OS แล้วใช้ Linux features (namespaces, cgroups) แยก process, filesystem, network ของแต่ละ container ผลลัพธ์คือ: เบามาก (MB แทน GB), เร็วมาก (เริ่มในวินาที แทนนาที), และ portable (รันได้ทุกที่ที่มี Docker)

Host Machine
Container 1
App
Libs
Container 2
App
Libs
Container 3
App
Libs
Docker Engine
Host OS
Hardware

สังเกตว่า ไม่มี Guest OS — container ใช้ kernel ของ Host OS ร่วมกัน ทำให้:


เปรียบเทียบ VM vs Container

ตารางด้านล่างเปรียบเทียบ VM กับ Container ในทุกมิติ — สังเกตว่า Container เร็วกว่า เบากว่า และ scale ง่ายกว่าในเกือบทุกด้าน แต่ VM ยังมีข้อดีด้าน isolation ที่แข็งแกร่งกว่า (แยก kernel) และรองรับ ต่าง OS ได้ (เช่น รัน Windows บน Linux host):

Virtual MachineDocker Container
ขนาดหลาย GB (มี OS เต็ม)หลัก MB — ร้อย MB
เวลาเปิดนาที (boot OS)วินาที
PerformanceOverhead จาก Hypervisorใกล้เคียง native
Isolationสูงมาก (แยก OS)ปานกลาง (แชร์ kernel)
จำนวนที่รันได้5-20 ต่อเครื่อง100+ ต่อเครื่อง
OS ต่างกันได้ได้ (Windows บน Linux)ไม่ได้ (ต้อง Linux kernel)
ใช้ RAMจอง RAM ทั้งก้อนใช้เท่าที่ต้องการ
Portabilityย้ายยาก (ไฟล์ใหญ่)ย้ายง่าย (Image เล็ก)

Docker ทำงานยังไง?

Docker ทำงานบน client-server architecture — Docker CLI (client) ส่งคำสั่งไปยัง Docker Engine (daemon) ที่จัดการ images และ containers มี 3 concepts หลักที่ต้องเข้าใจ เปรียบเทียบกับ OOP: Dockerfile = source code, Image = class, Container = object:

1. Dockerfile — สูตรทำ Image

Dockerfile คือ text file ที่บอกว่าต้องเตรียม environment ยังไง ทีละขั้น — เริ่มจาก base image (เช่น Node.js 20), copy source code เข้าไป, install dependencies, กำหนด port, กำหนด command ที่รันตอน start เหมือนสูตรทำอาหาร — ทำตามขั้นตอนได้ผลเหมือนกันทุกครั้ง:

# เริ่มจาก base image
FROM node:20-alpine

# ตั้ง working directory
WORKDIR /app

# copy package.json แล้วติดตั้ง dependencies
COPY package*.json ./
RUN npm ci --production

# copy source code
COPY . .

# บอกว่า app ใช้ port อะไร
EXPOSE 3000

# คำสั่งรัน app
CMD ["node", "server.js"]

2. Image — สิ่งที่ได้จาก Dockerfile

Image คือ snapshot ของ environment ที่พร้อมรัน — ผลลัพธ์จากการ docker build Dockerfile Image เก็บทุกอย่างที่ app ต้องการ (OS libs, runtime, code, configs) แชร์ผ่าน Docker Hub หรือ private registry ได้ เหมือนแผ่น CD ที่ burn แล้ว — copy ไปรันที่ไหนก็ได้:

# สร้าง image จาก Dockerfile
docker build -t my-app:v1 .

# ดู images ทั้งหมด
docker images

Image เป็น read-only — เหมือน class ใน OOP

3. Container — Instance ที่รันจาก Image

Container คือ image ที่กำลังทำงานอยู่ — สร้างจาก docker run จาก image เดียวสร้าง container ได้หลายตัว แต่ละตัวมี filesystem, network, process space แยกกัน เหมือน object ที่ new จาก class ใน OOP:

# รัน container จาก image
docker run -d -p 3000:3000 --name my-app my-app:v1

# ดู container ที่กำลังรัน
docker ps

# หยุด / ลบ container
docker stop my-app
docker rm my-app

ความสัมพันธ์:

Dockerfile
สูตร
→ build →
Image
แผ่น CD
→ run →
Container
เครื่องเล่น

ตัวอย่างจริง: Deploy Web App

มาเปรียบเทียบขั้นตอนจริงในการ deploy web app ทั้งแบบ VM (วิธีเดิม) กับ Docker (วิธีใหม่) — จะเห็นว่า Docker ลดขั้นตอนได้มาก และที่สำคัญคือ ทุกคนได้ environment เดียวกัน ไม่มี "แต่ในเครื่องฉันมันรันได้นะ" อีกต่อไป:

แบบ VM (วิธีเดิม)

ต้อง SSH เข้า server, ติดตั้ง OS, install dependencies ทีละตัว, configure ทุกอย่างด้วยมือ — ถ้าต้องทำ 10 servers ก็ทำซ้ำ 10 รอบ ถ้าลืมขั้นตอนก็พัง:

# 1. สร้าง VM ใหม่
# 2. ติดตั้ง Ubuntu
# 3. ติดตั้ง Node.js
sudo apt update
sudo apt install nodejs npm

# 4. copy code ไปที่ VM
scp -r ./my-app user@vm-ip:/home/user/

# 5. ติดตั้ง dependencies
cd /home/user/my-app && npm install

# 6. รัน app
node server.js

# ใช้เวลา: 15-30 นาที 😩
# ถ้ามี 3 servers = ทำ 3 รอบ 😩😩😩

แบบ Docker

เขียน Dockerfile ครั้งเดียว แล้ว docker build + docker run ได้เลย — ไม่ว่า dev, staging, production ได้ environment เดียวกันหมด ถ้าต้อง deploy 10 servers ก็แค่ docker run 10 ครั้ง (หรือใช้ K8s จัดการให้):

# 1. สร้าง image (ครั้งเดียว)
docker build -t my-app:v1 .

# 2. รัน (ที่ไหนก็ได้)
docker run -d -p 3000:3000 my-app:v1

# ใช้เวลา: 1-2 นาที 🎉
# ถ้ามี 3 servers = docker run 3 ที 🎉🎉🎉

Docker Compose — รันหลาย Container พร้อมกัน

App จริงไม่ได้มีแค่ container เดียว — มี web server + database + cache + message queue + ... ถ้าต้อง docker run ทีละตัว ตั้ง network เอง ตั้ง volume เอง จะยุ่งมาก! Docker Compose แก้ปัญหานี้โดยกำหนดทุก service ในไฟล์ YAML เดียว แล้วรันทั้งหมดด้วย docker compose up คำสั่งเดียว:

# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://db:5432/myapp
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine

volumes:
  pgdata:
# เปิดทุก service พร้อมกัน
docker compose up -d

# ปิดทุก service
docker compose down

แค่คำสั่งเดียว ได้ web + database + cache พร้อมรัน ✅


แล้วเมื่อไหร่ควรใช้อะไร?

ส่วนใหญ่คำตอบคือ Docker — แต่มีบาง use cases ที่ VM ยังจำเป็น:

ใช้ Docker Container เมื่อ:

ใช้ VM เมื่อ:

ใช้ทั้งสอง:

ในองค์กรขนาดใหญ่มักใช้ทั้งคู่: VM เป็น infrastructure layer + Container รันอยู่บน VM

Cloud providers (AWS, GCP, Azure) ใช้ VM เป็น backend แล้วให้เรารัน container บน VM อีกที

Kubernetes — Pod · Pod · Pod ← Containers
VM (EC2) ← Virtual Machine
Physical Server ← Hardware

คำสั่ง Docker ที่ใช้บ่อย — สรุป

Docker commands ที่ DevOps ใช้ทุกวัน — ไม่ต้องจำทั้งหมด แค่รู้ว่ามีอะไรบ้าง แล้ว docker --help เมื่อต้องการ คำสั่งที่ใช้บ่อยที่สุดคือ docker build, docker run, docker ps, docker logs:

# === Images ===
docker build -t app:v1 .           # สร้าง image
docker images                       # ดู images ทั้งหมด
docker pull nginx:latest            # ดึง image จาก Docker Hub
docker rmi app:v1                   # ลบ image

# === Containers ===
docker run -d -p 8080:80 nginx     # รัน container
docker ps                           # ดู container ที่รันอยู่
docker ps -a                        # ดูทั้งหมด (รวมที่หยุดแล้ว)
docker stop <container_id>          # หยุด
docker rm <container_id>            # ลบ
docker logs <container_id>          # ดู logs
docker exec -it <id> /bin/sh        # เข้าไปใน container

# === Docker Compose ===
docker compose up -d                # เปิดทุก service
docker compose down                 # ปิดทุก service
docker compose logs -f              # ดู logs แบบ realtime

สรุป

Docker เปลี่ยนวิธี deploy software ไปตลอดกาล — จาก "ติดตั้งทีละเครื่อง ลุ้นว่าจะรันได้ไหม" เป็น "build once, run anywhere" ทุก cloud provider, CI/CD pipeline, microservice architecture ล้วนใช้ containers เป็นพื้นฐาน เรียนรู้ Docker เป็น skill แรกๆ ที่ DevOps ต้องมี:

ในโพสต์หน้าเราจะมาพูดถึง API Request Lifecycle — เวลากด send request ไป server มันเกิดอะไรขึ้นบ้าง? 🌐🐕

บทความจากซีรีส์ DevOps & Vibe Coding 2026
← Previous
CI/CD Pipeline — ส่ง Code ขึ้น Production แบบอัตโนมัติ
Next →
API Request Lifecycle — เมื่อกด Send เกิดอะไรขึ้นบ้าง?