ข้ามไปเนื้อหาหลัก
Docker· ~14 นาที· อัปเดตล่าสุด

Multi-stage Build และลดขนาด Image

ทำ image ให้เล็ก เร็ว และสะอาดด้วย multi-stage

ปูพื้นฐาน: Image ที่ดีควรจะมีขนาดเล็กที่สุดเท่าที่จะเป็นไปได้ เพราะทำให้ดาวน์โหลดไว ประหยัดพื้นที่ และมีความปลอดภัยสูง แต่ปัญหาคือตอน Build แอป มักจะต้องใช้เครื่องมือสารพัด (เช่น Compiler) ซึ่งทำให้ Image บวม

Multi-stage เหมือนการทำอาหารในครัวใหญ่

Multi-stage build เหมือนทำอาหารในครัวใหญ่แล้วยกเฉพาะจานเสร็จออกมาเสิร์ฟ — เครื่องมือ/วัตถุดิบ (compiler, dependency สำหรับ build) ทิ้งไว้ในครัว ไม่ติดไปกับจาน · image สุดท้ายจึงเล็กและสะอาด

ปัญหา: ถ้าใส่ทั้ง compiler + source + dependency ลง image เดียว มันจะใหญ่และมีของไม่จำเป็น (ช้าตอน pull, ผิวโจมตีกว้าง) · multi-stage แยกขั้น build ออกจากขั้น run แล้วก๊อปเฉพาะผลลัพธ์

# ---- stage 1: build (มีเครื่องมือครบ) ----
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build          # ได้ผลลัพธ์ใน /app/dist

# ---- stage 2: run (image เล็ก เอาแค่ผลลัพธ์) ----
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
# ไม่มี node/npm/source ติดมา — เหลือแค่ไฟล์ที่เสิร์ฟจริง
multi-stage: stage build แยกจาก stage run
  • เลือก base image เล็ก-alpine หรือ -slim เล็กกว่าปกติหลายเท่า
  • multi-stage — ทิ้งเครื่องมือ build ไว้ เอาแค่ผลลัพธ์ (artifact) เข้า image สุดท้าย
  • รวมคำสั่ง RUN และล้าง cache ในบรรทัดเดียว เพื่อลด layer/ขนาด
  • .dockerignore — กัน node_modules/.git ไม่ให้เข้า build context

สรุป Key Takeaways

  • Multi-stage: แยก stage build (เครื่องมือครบ) จาก stage run (เอาแค่ผลลัพธ์)
  • ใช้ base image เล็ก (alpine/slim) + .dockerignore
  • image เล็ก → pull เร็ว, ประหยัด, attack surface น้อย

คำถามที่พบบ่อย

Multi-stage build ช่วยอะไร เห็นผลแค่ไหน

แยก "ขั้น build" (ต้องมี compiler, dependencies ครบ) ออกจาก "ขั้นรันจริง" (เอาเฉพาะผลลัพธ์) — image Node จาก ~1GB เหลือหลักร้อย MB, Go เหลือหลักสิบ MB ได้ — เล็กลง = pull เร็ว, พื้นที่โจมตีน้อยลง, สแกนช่องโหว่ผ่านง่ายขึ้น

เลือก base image ยังไงให้เล็กและปลอดภัย

ไล่ตามลำดับ: distroless/scratch (เล็กสุด ปลอดภัยสุด แต่ debug ยาก) → alpine (เล็ก มี shell — ระวังปัญหา musl กับบาง library) → slim variant ของ official image (สมดุลดี) — และ pin เวอร์ชันชัดเจนเสมอ อย่าใช้ :latest เป็น base

อ่านจบแล้วอย่าลืมทำเครื่องหมาย