การเปรียบเทียบระหว่าง Single-stage Build และ Multi-stage Build (โดยทั่วไปจะหมายถึงการสร้าง Container Image ด้วย Docker)
ทำความเข้าใจภาพรวม
- Single-stage Build (แบบดั้งเดิม / ขั้นตอนเดียว)
- ใช้
Dockerfileที่มีคำสั่งFROMเพียงบรรทัดเดียว - ขั้นตอนการติดตั้ง Tool สำหรับคอมไพล์ (Build tools, SDK, Dependencies) และขั้นตอนการรันโปรแกรม (Runtime) อยู่ใน Image เดียวกันทั้งหมด
- ใช้
- Multi-stage Build (แบบหลายขั้นตอน)
- มีคำสั่ง
FROMหลายตัวในDockerfileเดียวกัน - แบ่งกระบวนการออกเป็นหลาย Stage (เช่น Stage ที่ 1 สำหรับ Build/Compile และ Stage ที่ 2 สำหรับ Runtime)
- สามารถคัดลอก (Copy) เฉพาะ Artifacts หรือไฟล์ที่จำเป็นจาก Stage ก่อนหน้าเข้ามายัง Stage สุดท้ายได้
- มีคำสั่ง
ตารางเปรียบเทียบประเด็นสำคัญ
| หัวข้อ | Single-stage Build | Multi-stage Build |
| ขนาดของ Image (Image Size) | ใหญ่มาก เพราะรวมทั้ง Source code, SDK, Build tools, Dev dependencies และ Cache เอาไว้ | เล็กและกะทัดรัด เพราะมีเฉพาะ Binary/ไฟล์ที่ Build เสร็จแล้ว และ Runtime environment |
| ความปลอดภัย (Security) | ต่ำกว่า เนื่องจากมีเครื่องมือที่ไม่จำเป็น (เช่น gcc, npm, git) และ Source code หลงเหลืออยู่ใน Image ซึ่งเพิ่ม Attack Surface | สูงกว่า มีเฉพาะสิ่งที่จำเป็นต่อการรันโปรแกรม ลดช่องโหว่และลดความเสี่ยงจากเครื่องมือตกค้าง |
| ความซับซ้อนของ Dockerfile | เรียบง่าย เขียนตรงไปตรงมา เข้าใจง่าย เหมาะกับการทดลองเบื้องต้น | ซับซ้อนกว่าเล็กน้อย ต้องออกแบบและจัดการการส่งต่อไฟล์ข้าม Stage |
| การจัดการ Build Script / CI/CD | หากต้องการ Image ขนาดเล็ก มักต้องเขียน Bash script แยก หรือสร้าง Dockerfile 2 ไฟล์ (Builder + Runtime) | จบในไฟล์เดียว ไม่ต้องพึ่งพา Script ซับซ้อนใน Pipeline CI/CD |
| Caching และความเร็วในการ Build | หาก Dependency เปลี่ยน อาจต้องดาวน์โหลดและ Build ใหม่ทั้งหมด | Layer Caching แยกตาม Stage ได้ชัดเจน ทำให้ Build ซ้ำได้เร็วกว่า |
ตัวอย่างการเปรียบเทียบด้วยโค้ด (เช่น แอปพลิเคชัน Node.js/Go)
ตัวอย่าง: Single-stage Build
Dockerfile
YAML
YAML
# ใช้ Node.js ตัวเต็ม
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# สิ่งที่ติดไปด้วย: node_modules ขนาดใหญ่, TypeScript compiler, Source code ทั้งหมด
EXPOSE 3000
CMD ["node", "dist/main.js"]