Base Image ขนาดเล็กและ .dockerignore
Build context คืออะไร
หัวข้อที่มีชื่อว่า “Build context คืออะไร”เมื่อรัน docker build . Docker จะ package ทุกอย่างในไดเรกทอรีปัจจุบันเป็น build context และส่งไปยัง build daemon Build context ขนาดใหญ่จะทำให้ทุก build ช้าลง แม้ว่าไฟล์ส่วนใหญ่จะไม่ถูกใช้โดย instruction COPY ใดๆ
#5 transferring context: 823.4MB ← node_modules รวมอยู่ด้วย!ไฟล์ .dockerignore บอก Docker ว่า path ใดบ้างที่ควรยกเว้นจาก build context — เหมือนกับที่ .gitignore ทำสำหรับ Git
การเขียนไฟล์ .dockerignore
หัวข้อที่มีชื่อว่า “การเขียนไฟล์ .dockerignore”สร้าง .dockerignore ในไดเรกทอรีเดียวกับ Dockerfile:
# Dependencies — ติดตั้งใหม่ภายใน imagenode_modules/vendor/
# Version control.git/.gitignore
# Editor และ OS noise.DS_Store*.log.env.env.*
# Test และ CI files ที่ไม่จำเป็นใน runtime__tests__/coverage/.github/*.test.ts*.spec.tsหลังเพิ่มไฟล์นี้ build context จะลดจากหลายร้อย MB เหลือแค่ไม่กี่ KB สำหรับโปรเจกต์ Node.js ทั่วไป นอกจากนี้การยกเว้นไฟล์ .env ยังป้องกันไม่ให้ secret รั่วไหลเข้าไปใน image โดยไม่ตั้งใจ
การเลือก base image ขนาดเล็ก
หัวข้อที่มีชื่อว่า “การเลือก base image ขนาดเล็ก”Base image มักเป็นส่วนที่ใหญ่ที่สุดของขนาด image ต่อไปนี้คือตัวเลือกทั่วไปจากใหญ่สุดไปเล็กสุด:
| Base | ขนาดที่วัดได้จริง | หมายเหตุ |
|---|---|---|
ubuntu:24.04 | ~101 MB | apt ecosystem เต็มรูปแบบ; ใหญ่ |
debian:bookworm | ~139 MB | Debian เต็ม; พบบ่อย |
node:24 | ~1.14 GB | รวม Debian เต็มและ devtools |
node:24-slim | ~249 MB | Debian slim; ไม่มี devtools |
node:24-alpine | ~166 MB | ชั้น OS ของ Alpine เล็กมาก แต่ Node.js runtime เองต่างหากที่เป็นต้นทุนหลักตอนนี้ |
gcr.io/distroless/nodejs24-debian13 | ~161 MB | Distroless; minimal, ไม่มี shell |
scratch | 0 MB | ว่างเปล่าสมบูรณ์; สำหรับ static binary เท่านั้น ไม่ใช่สำหรับ Node.js |
ขนาดข้างต้นวัดโดยตรงด้วย docker images หลัง docker pull บนเครื่องนี้ (arm64, กันยายน 2026) — ตัวเลขอาจต่างกันบ้างตาม architecture แต่ลำดับเปรียบเทียบและข้อเท็จจริงที่ว่าไม่มี base image ของ Node.js ในปัจจุบันเหลือขนาดใกล้ ~50 MB แบบที่ tutorial เก่า ๆ อ้างไว้ยังคงจริง: Node.js runtime เองต่างหาก ไม่ใช่ชั้น OS ที่เป็นตัวกำหนดขนาด image ในตอนนี้
Alpine Linux
หัวข้อที่มีชื่อว่า “Alpine Linux”Alpine ใช้ musl libc และ BusyBox เป็น base image ขนาดเล็กที่ได้รับความนิยมมากที่สุดสำหรับ container เพราะ:
- Base image ขนาดต่ำกว่า 5 MB
- Package manager
apkครอบคลุม tool ทั่วไปส่วนใหญ่ - Official image สำหรับ Node.js, Python, Go, Ruby และอื่นๆ ล้วนมี variant
-alpine
FROM node:24-alpineข้อควรระวัง: Alpine ใช้ musl แทน glibc package บางอย่างที่ compile สำหรับ glibc (เช่น Node addon บางตัว) อาจต้องการงานเพิ่มเติม สำหรับ application pure-JS มักจะใช้แทนกันได้โดยตรง
Distroless images
หัวข้อที่มีชื่อว่า “Distroless images”Distroless images ของ Google มีเฉพาะ language runtime เท่านั้น — ไม่มี shell, ไม่มี package manager, ไม่มี ls หรือ cat มี attack surface น้อยกว่ามากเพราะไม่มี tooling ที่ผู้โจมตีจะใช้ประโยชน์ได้ แม้ขนาดรวมเป็นไบต์จะใกล้เคียงกับ -alpine แล้วก็ตาม (ทั้งคู่ถูกกำหนดขนาดหลักโดย Node.js runtime เอง)
FROM gcr.io/distroless/nodejs24-debian13เพราะไม่มี shell, CMD และ ENTRYPOINT ต้องใช้ exec form (JSON array):
CMD ["dist/server.js"]ลบ apt cache หลัง install
หัวข้อที่มีชื่อว่า “ลบ apt cache หลัง install”เมื่อต้องติดตั้ง package ด้วย apt-get ควร cleanup package list ใน RUN layer เดียวกันเสมอ:
RUN apt-get update \ && apt-get install -y --no-install-recommends curl \ && rm -rf /var/lib/apt/lists/*--no-install-recommends ข้าม optional recommended package rm -rf /var/lib/apt/lists/* ลบ package index ที่ดาวน์โหลดออกจาก layer หากวางไว้ใน RUN instruction แยกต่างหาก ขนาดนั้นถูก commit ไปแล้วและการ cleanup จะไม่มีผลใดๆ
ลงมือทำ: เปรียบเทียบ build context และ base image
หัวข้อที่มีชื่อว่า “ลงมือทำ: เปรียบเทียบ build context และ base image”snippet ด้านล่างแสดง pattern .dockerignore และ Alpine base image
# syntax=docker/dockerfile:1
# .dockerignore (create alongside this Dockerfile):
# node_modules/
# .git/
# .env
# coverage/
FROM node:24-alpine
WORKDIR /app
# Only manifests first for cache efficiency
RUN echo '{}' > package.json && echo '{}' > package-lock.json
# Application source (node_modules excluded by .dockerignore)
RUN mkdir -p src && echo "console.log('Running on Alpine, image is tiny!');" > src/index.js
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node","src/index.js"]
# --- Build and check the size ---
# docker build -t myapp:alpine .
# docker images myapp:alpineข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
เขียน .dockerignore ครอบคลุมทุก path ที่ไม่จำเป็น | build context เล็กและส่งเร็ว ลดความเสี่ยง secret รั่วไหลเข้า image | ต้องดูแลรายการให้ตรงกับโครงสร้างโปรเจกต์ที่เปลี่ยนไปเรื่อยๆ |
| เลือก base image ที่เล็กกว่า (alpine แทน full distro) | ลดขนาด final image ได้หลักร้อย MB | native addon บางตัวที่ compile กับ glibc อาจต้อง build ใหม่สำหรับ musl |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ไม่มี
.dockerignoreเลย ทำให้.git/และnode_modules/ถูกส่งเข้า build context ทุกครั้ง ทำให้ build ช้าลงมากโดยเฉพาะในโปรเจกต์ที่มี history ยาว - ลืมยกเว้น
.envใน.dockerignoreทำให้ secret ในไฟล์ local หลุดเข้าไปใน image โดยไม่ตั้งใจ - เลือก base image ใหญ่อย่าง
node:24แทนnode:24-alpineทั้งที่ application ไม่ได้ต้องการ tool เพิ่มเติมใดๆ ในช่วง runtime
💡 ตัวอย่างจากของจริง
เอกสาร best practice อย่างเป็นทางการของ Docker เตือนซ้ำว่าโปรเจกต์ Node.js ที่ไม่มี
.dockerignoreมักส่ง build context หลายร้อย MB เพราะnode_modules/ถูกรวมไปด้วยทุกครั้ง ทั้งที่ dependency จะถูกติดตั้งใหม่ภายใน image อยู่แล้ว (docs.docker.com/build/building/context)