Base Image ขนาดเล็กและ .dockerignore
Build context คืออะไร
หัวข้อที่มีชื่อว่า “Build context คืออะไร”เมื่อรัน docker build . Docker จะ package ทุกอย่างในไดเรกทอรีปัจจุบันเป็น build context และส่งไปยัง build daemon Build context ขนาดใหญ่จะทำให้ทุก build ช้าลง แม้ว่าไฟล์ส่วนใหญ่จะไม่ถูกใช้โดย instruction COPY ใดๆ
Sending build context to Docker daemon 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 | ~78 MB | apt ecosystem เต็มรูปแบบ; ใหญ่ |
debian:bookworm | ~117 MB | Debian เต็ม; พบบ่อย |
node:22 | ~1.1 GB | รวม Debian เต็มและ devtools |
node:22-slim | ~235 MB | Debian slim; ไม่มี devtools |
node:22-alpine | ~55 MB | Alpine Linux; เล็กที่สุดที่มี shell |
cgr.dev/chainguard/node | ~50 MB | Distroless; minimal, ไม่มี shell |
scratch | 0 MB | ว่างเปล่าสมบูรณ์; สำหรับ static binary |
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:22-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 ที่ผู้โจมตีจะใช้ประโยชน์ได้
FROM gcr.io/distroless/nodejs22-debian12เพราะไม่มี 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:22-alpine
WORKDIR /app
# Only manifests first for cache efficiency
COPY package.json ./
RUN echo '{}' > package-lock.json
# Application source (node_modules excluded by .dockerignore)
COPY src/ ./src/ 2>/dev/null || true
RUN echo "console.log('Running on Alpine, image is tiny!');" > src/index.js 2>/dev/null || true
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:22แทนnode:22-alpineทั้งที่ application ไม่ได้ต้องการ tool เพิ่มเติมใดๆ ในช่วง runtime
💡 ตัวอย่างจากของจริง
เอกสาร best practice อย่างเป็นทางการของ Docker เตือนซ้ำว่าโปรเจกต์ Node.js ที่ไม่มี
.dockerignoreมักส่ง build context หลายร้อย MB เพราะnode_modules/ถูกรวมไปด้วยทุกครั้ง ทั้งที่ dependency จะถูกติดตั้งใหม่ภายใน image อยู่แล้ว