Back to notes
mastery-platform-devops
Featured

Docker Optimization Mastery: สกัดไขมัน สร้าง Image ระดับเทพ

เลิกสร้าง Docker Image ขนาด 1GB! เจาะลึกเทคนิค Multi-stage Build และ Layer Caching ที่จะทำให้การ Build ของคุณเร็วขึ้น 10 เท่า และ Image เล็กเพียงหยิบมือ

January 30, 20263 min read readNNexis by Seereen

🛑 1. The Problem First: "Image ที่บวมน้ำและ Build ที่ช้าอืด"

ลองนึกถึงวันที่คุณต้องแก้โค้ดเพียงบรรทัดเดียว แต่ต้องนั่งรอ Docker Build ใหม่ทั้งหมดนาน 10 นาที:

HLJS DOCKERFILE
# ❌ Naive Approach: ทุกอย่างกองรวมกันใน Stage เดียว
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
# 🌋 พัง! แก้โค้ด 1 ตัวอักษร Docker จะมองว่า Layer 'COPY . .' เปลี่ยน
# และสั่งรัน 'npm install' ใหม่ทั้งหมดทุุกครั้ง เสียเวลาชีวิตและ Bandwidth มหาศาล
# แถม Image สุดท้ายยังบวมถึง 1GB เพราะมีทั้ง Compiler และ Source Code อยู่ข้างใน

ปัญหา: Docker Image ที่ใหญ่เกินไปทำให้การ Deploy ช้า (Network Latency) และกินพื้นที่เก็บข้อมูล (Storage Cost) ยิ่งไปกว่านั้น ยิ่งมีไฟล์ใน Image เยอะ ยิ่งเพิ่มโอกาสให้แฮกเกอร์โจมตี (Attack Surface) ได้ง่ายขึ้นครับ


💡 2. Real-Life Analogy: การขนส่งเฟอร์นิเจอร์ vs รถเข็นสำเร็จรูป

  • Standard Build: เหมือนคุณขนทุุกอย่างเข้าบ้าน ทั้งเลื่อย ไม้ กาว และช่างไม้ เพื่อไปประกอบเตียงในห้องนอน เมื่อทำเสร็จ ทุุกอย่างยังวางรกอยู่ในบ้าน (Image ขนาดใหญ่ที่มีเครื่องมือทำมาหากินค้างอยู่)
  • Multi-stage Build: เหมือนคุณประกอบเตียงที่ "โรงงาน (Stage 1)" จนเสร็จ แล้วจ้างรถกระบะขนแค่ "เตียงสำเร็จรูป (Stage 2)" ไปวางที่บ้าน หลังประกอบเสร็จ โรงงานจะถูกทุบทิ้งไป ไม่เหลือขยะรกบ้าน
  • Layer Caching: เหมือน "การต่อเลโก้". ถ้าคุณเปลี่ยนแค่หัวหุ่นยนต์ คุณก็แค่ถอดหัวออกแล้วใส่หัวใหม่เข้าไป (Layer ล่างๆ) โดยไม่ต้องรื้อแขนขา (Layer บนๆ ที่ยังเหมือนเดิม) ใหม่แต่แรก

🚀 3. Execution Journey: มหากาพย์การทำ Multi-stage Build

เราจะแยกขั้นตอนการสร้างงาน (Build) ออกจากการรันงานจริง (Runtime)

🛠 Step-by-step:

  1. Stage 1 (Builder): ใช้ Image ตัวเต็มที่มี Compiler เพื่อ compile หรือ build โปรเจกต์
  2. Layer Caching Rule: ย้ายคำสั่ง COPY package.json ขึ้นมาก่อน เพื่อให้ Docker จำ Cache ของ install ไว้ได้ถ้าไฟล์นี้ไม่เปลี่ยน
  3. Stage 2 (Runner): ใช้ Base Image ขนาดจิ๋ว (เช่น Alpine) แล้วก๊อปปี้แค่ไฟล์ผลลัพธ์จาก Stage 1 มาใส่
  4. The Cleanup: ทิ้งทุุกชื่อไฟล์ที่ไม่จำเป็นด้วย .dockerignore
HLJS DOCKERFILE
# ✅ Best Practice: มัลติสเตจสกัดไขมัน
# --- Stage 1: Build ---
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci # 🛠 ใช้ ci เพื่อความแม่นยำและดึง cache ได้ดีกว่า
COPY . .
RUN npm run build

# --- Stage 2: Runtime ---
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.next ./.next # 🛠 ก๊อปปี้มาแค่สิ่งที่จำเป็นต้องรัน
COPY --from=builder /app/node_modules ./node_modules
USER node # 🔒 Security: ห้ามใช้ root รัน (Junior Trap!)
CMD ["npm", "start"]

🪤 4. The Junior Trap: โรค "Running as Root"

จูเนียร์มักจะปล่อยให้ Docker รันในฐานะ User root โดยไม่ตั้งใจ:

HLJS DOCKERFILE
# ❌ Junior Trap: ไม่ระบุ User
CMD ["npm", "start"]
# 🌋 พัง! ถ้าโปรแกรมของคุณถูกแฮก แฮกเกอร์จะได้สิทธิ์ root ของ Container ทันที
# และมีโอกาสที่จะเจาะทะลุออกไปยังเครื่องเซิร์ฟเวอร์หลัก (Host) ของคุณได้

ระวัง: ทุุกวินาทีที่รัน Production จงใช้สิทธิ์ที่ต่ำที่สุดเท่าที่จะทำได้ ✅ การแก้ไข: ระบุ USER node (สำหรับ Node.js) หรือสร้าง user ใหม่ใน Dockerfile เสมอครับ


⚖️ 5. The Why Matrix: Alpine vs Slim vs Full

หัวข้อFull Image (Debian)Slim (Debian ตัดขยะ)Alpine (Linux ขนาดจิ๋ว)
ขนาดไฟล์🐘 ใหญ่มาก (1GB+)🐕 ปานกลาง (200MB)🐜 เล็กจิ๋ว (<50MB)
ความปลอดภัยต่ำ (มี Tool ให้แฮกเยอะ)สูง🚀 สูงสุด (ทิ้งทุกอย่าง!)
ความเข้ากันได้สูงสุดสูงปานกลาง (อาจมีปัญหากับบางไลบรารี)
เหมาะกับช่วงเริ่มพัฒนาProduction ส่วนใหญ่Production ที่ต้องการ Performance สุงสุด

🎓 6. Senior Mindset Summary

การเป็น Senior คือการมองว่า "เราไม่ได้ลดขนาด Image เพื่อประหยัดพื้นที่เพียงอย่างเดียว แต่เพื่อลดช่องโหว่ทางความปลอดภัย". Dockerfile ที่สะอาดคือภาพสะท้อนของวิศวกรที่ใส่ใจในรายละเอียด ทุุกบรรทัดที่คุณเขียนมีผลต่อความเร็ว ความปลอดภัย และราคาที่บริษัทต้องจ่ายครับ!

Share this note

© 2026 My Notes by Seereen