จากโพสต์ที่แล้วเราพูดถึง CI/CD Pipeline ว่ามันช่วยให้เรา build, test, deploy แบบอัตโนมัติ
แต่เคยมั้ยที่... "ในเครื่องฉันรันได้นะ แต่ขึ้น server แล้วพัง" 🤦
ปัญหานี้เกิดจากความแตกต่างของ environment — เวอร์ชันของ OS, library, config ต่างกัน ทำให้ code ที่ทำงานได้ในเครื่องเรากลับพังในเครื่องอื่น
วิธีแก้คือ ทำให้ทุกที่ใช้ environment เดียวกัน ซึ่งมี 2 แนวทางหลัก:
- Virtual Machines (VMs) — จำลองเครื่องคอมพิวเตอร์ทั้งเครื่อง
- Docker Containers — จำลองแค่สิ่งที่ app ต้องการ
มาดูกันว่าทั้งสองอย่างคืออะไร ต่างกันยังไง แล้วควรใช้ตัวไหนเมื่อไหร่
Virtual Machine (VM) คืออะไร?
VM (Virtual Machine) คือการจำลองคอมพิวเตอร์ทั้งเครื่องด้วย software — มี CPU, RAM, Disk, Network เสมือนครบ รันอยู่บนเครื่องจริง (Host) ผ่าน Hypervisor ที่จัดสรร resource ให้แต่ละ VM เหมือนแบ่งห้องในอพาร์ทเมนท์ — แต่ละ VM เป็นอิสระจากกัน ติดตั้ง OS ต่างกันได้ แม้ VM หนึ่งพังก็ไม่กระทบ VM อื่น
สังเกตว่า แต่ละ VM มี Guest OS ของตัวเอง ทำให้:
- ✅ แยกจากกันสมบูรณ์ (isolation สูงมาก)
- ✅ รัน OS ต่างกันได้ (Windows บน Linux host)
- ❌ แต่กิน RAM, CPU, Disk เยอะมาก
- ❌ เปิดช้า (boot OS ทั้งเครื่อง)
Hypervisor ยอดนิยม:
- Type 1 (Bare-metal): VMware ESXi, Hyper-V, Proxmox — รันบน hardware ตรงๆ
- Type 2 (Hosted): VirtualBox, VMware Workstation — รันบน OS อีกที
Docker Container คืออะไร?
Container คือการจำลองแค่ environment ที่ app ต้องการ — ไม่ต้องจำลอง OS ทั้งตัว! Container ใช้ kernel ร่วมกับ Host OS แล้วใช้ Linux features (namespaces, cgroups) แยก process, filesystem, network ของแต่ละ container ผลลัพธ์คือ: เบามาก (MB แทน GB), เร็วมาก (เริ่มในวินาที แทนนาที), และ portable (รันได้ทุกที่ที่มี Docker)
สังเกตว่า ไม่มี Guest OS — container ใช้ kernel ของ Host OS ร่วมกัน ทำให้:
- ✅ เบามาก (MB vs GB)
- ✅ เปิดเร็วมาก (วินาที vs นาที)
- ✅ รันได้หลาย container พร้อมกัน
- ❌ ต้องเป็น Linux kernel เดียวกัน (บน Mac/Windows ใช้ VM เล็กๆ ซ่อนอยู่)
- ❌ isolation น้อยกว่า VM
เปรียบเทียบ VM vs Container
ตารางด้านล่างเปรียบเทียบ VM กับ Container ในทุกมิติ — สังเกตว่า Container เร็วกว่า เบากว่า และ scale ง่ายกว่าในเกือบทุกด้าน แต่ VM ยังมีข้อดีด้าน isolation ที่แข็งแกร่งกว่า (แยก kernel) และรองรับ ต่าง OS ได้ (เช่น รัน Windows บน Linux host):
| Virtual Machine | Docker Container | |
|---|---|---|
| ขนาด | หลาย GB (มี OS เต็ม) | หลัก MB — ร้อย MB |
| เวลาเปิด | นาที (boot OS) | วินาที |
| Performance | Overhead จาก 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
ความสัมพันธ์:
ตัวอย่างจริง: 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 เมื่อ:
- 🐳 ต้องการ deploy app เร็วๆ
- 🐳 อยาก environment เหมือนกันทุกที่ (dev = staging = production)
- 🐳 ต้องรัน microservices หลายตัว
- 🐳 ใช้กับ CI/CD pipeline
- 🐳 ต้อง scale ขึ้น/ลงเร็ว (Kubernetes)
ใช้ VM เมื่อ:
- 🖥️ ต้องรัน OS ต่างกัน (Windows app บน Linux host)
- 🖥️ ต้องการ security isolation สูงมาก (multi-tenant, compliance)
- 🖥️ รัน legacy app ที่ต้องการ OS เฉพาะ
- 🖥️ ต้องการ full control ของ OS (kernel tuning, custom drivers)
ใช้ทั้งสอง:
ในองค์กรขนาดใหญ่มักใช้ทั้งคู่: VM เป็น infrastructure layer + Container รันอยู่บน VM
Cloud providers (AWS, GCP, Azure) ใช้ VM เป็น backend แล้วให้เรารัน container บน VM อีกที
คำสั่ง 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 ต้องมี:
- VM = จำลองเครื่องทั้งเครื่อง (มี Guest OS) → หนัก แต่ isolation สูง
- Container = จำลองแค่ environment (แชร์ kernel) → เบา เร็ว portable
- Dockerfile → Image → Container (สูตร → แผ่น CD → เครื่องเล่น)
- Docker Compose = รันหลาย container พร้อมกันด้วยไฟล์เดียว
- ในโลกจริง ใช้ทั้งคู่ — VM เป็น infrastructure, Container รัน app
- Docker แก้ปัญหา "It works on my machine" ได้จริง 🐳
ในโพสต์หน้าเราจะมาพูดถึง API Request Lifecycle — เวลากด send request ไป server มันเกิดอะไรขึ้นบ้าง? 🌐🐕