.dockerignore
เรียนรู้วิธีใช้ .dockerignore เพื่อกรองไฟล์ออกจาก build context ก่อน Docker daemon ได้รับ ช่วยให้ build เร็วขึ้น image เล็กลง และป้องกัน secret ไม่ให้ติดเข้าไปใน image โดยไม่ตั้งใจ
ภาพจำสำคัญบทนี้
.dockerignore กรองไฟล์ออกก่อน Docker รับ context | ต้อง ignore node_modules/, .git/, .env เสมอ | syntax เหมือน .gitignore | วางที่ root ของ build context
ส่วนที่ 1
.dockerignore คืออะไร
ลองนึกถึงกระเป๋าเดินทาง — ถ้าคุณต้องการนำของไปฝากเพื่อน คุณคงไม่ยัดทุกอย่างในบ้านใส่กระเป๋า แต่จะเลือกเฉพาะสิ่งที่จำเป็นจริง ๆ เท่านั้น .dockerignore (ด็อกเกอร์อิกนอร์) คือไฟล์ที่บอก Docker ว่า "ไฟล์ไหนไม่ต้องส่งไป" ก่อนที่ Docker จะเริ่ม build image ชื่อไฟล์คือ .dockerignore เริ่มด้วยจุด (.) เขียนติดกัน ไม่มีนามสกุล และต้องวางไว้ที่ root ของ build context (โฟลเดอร์เดียวกับที่รัน docker build)
- .dockerignore คือไฟล์ข้อความธรรมดาที่บอก Docker ว่าไฟล์หรือโฟลเดอร์ไหนควรถูก 'มองข้าม' ก่อนส่งเข้า build context
- Docker daemon อ่าน .dockerignore ก่อนเสมอ — ไฟล์ที่ตรงกับ pattern จะไม่ถูกส่งไปเลย แม้แต่บรรทัดเดียว
- วางไฟล์ที่ root ของ build context เดียวกับ Dockerfile และคำสั่ง docker build .
ส่วนที่ 2
ทำไมเราควรใช้ .dockerignore
เวลาสั่ง docker build . (จุดคือ build context) Docker จะส่งทุกไฟล์และโฟลเดอร์ใน directory นั้นไปให้ Docker daemon ก่อน — รวมถึง node_modules ที่มีไฟล์นับแสนชิ้น, ไฟล์ .env ที่มี secret, และ .git ที่มีประวัติการเปลี่ยนแปลงทั้งหมด ถ้าไม่มี .dockerignore สิ่งเหล่านี้จะถูกส่งไปทั้งหมด ทำให้ build ช้าและเสี่ยงต่อความปลอดภัย
ประเด็นที่ 1
Build เร็วขึ้น — ลด build context ขนาดจาก ~870MB เหลือ ~2MB Docker daemon ได้รับข้อมูลน้อยลง ส่งเร็วขึ้นมาก
ประเด็นที่ 2
ป้องกัน secret ไม่ให้ติดเข้า image — ไฟล์ .env ที่มี database password, API key หรือ token จะไม่ถูก COPY เข้าไป image โดยไม่ตั้งใจ
ประเด็นที่ 3
ลด layer cache invalidation — ไฟล์ที่ไม่จำเป็น (เช่น log หรือ build artifacts) เปลี่ยนบ่อย ถ้าไม่ ignore จะทำให้ Docker ต้อง rebuild ทุกครั้ง
ประเด็นที่ 4
Image เล็กลง — ไม่มีไฟล์ที่ไม่จำเป็นแฝงอยู่ใน layer ทำให้ image สุดท้ายมีขนาดเล็กและ push/pull เร็วขึ้น
ส่วนที่ 3
ความสัมพันธ์ระหว่าง .dockerignore กับ build context
เมื่อสั่ง docker build . (จุดด้านหลังคือ path ของ build context) Docker จะทำตามลำดับนี้: ขั้นที่ 1 — Docker client อ่าน .dockerignore ก่อนส่งอะไรทั้งนั้น ขั้นที่ 2 — ไฟล์และโฟลเดอร์ที่ตรงกับ pattern ใน .dockerignore จะถูก "กัน" ออก ขั้นที่ 3 — เฉพาะไฟล์ที่เหลือเท่านั้นที่ถูกส่งไปเป็น build context ให้ Docker daemon ขั้นที่ 4 — Docker daemon อ่าน Dockerfile และรัน instruction ต่าง ๆ — คำสั่ง COPY จะมองเห็นเฉพาะไฟล์ที่อยู่ใน context เท่านั้น สรุป: .dockerignore ทำงานก่อน Dockerfile เสมอ ไม่ใช่หลัง
จุด (.) ด้านหลังคือ build context — Docker daemon จะรับ directory นี้ (ยกเว้นที่ .dockerignore กัน) ก่อนรัน Dockerfile
ภาพที่ 1 — build context ก่อนใช้ .dockerignore
ภาพที่ 1: เมื่อไม่มี .dockerignore Docker จะส่งทุกไฟล์รวมถึง node_modules (~800MB), .git, .env (secret) และ build artifacts ทั้งหมดไปให้ Docker daemon — ทำให้ build ช้าและเสี่ยงต่อความปลอดภัย
ส่วนที่ 4
ปัญหาที่เกิดเมื่อไม่มี .dockerignore
โปรเจกต์ Node.js / Next.js ทั่วไปที่ไม่มี .dockerignore จะส่ง build context ขนาดใหญ่มาก ดูตัวอย่างปัญหาที่พบบ่อย:
| ปัญหา | สาเหตุ | ผลกระทบ |
|---|---|---|
| node_modules/ ถูกส่งทั้งหมด | dependencies ที่ติดตั้งไว้บนเครื่อง dev มีไฟล์มากกว่า 100,000 ชิ้น | build context ใหญ่ขึ้นหลาย GB ทำให้ส่งช้าและ COPY เข้าไปซ้ำซ้อน |
| .git/ ถูกส่ง | โฟลเดอร์ .git มีประวัติ commit และ objects ทั้งหมด | เพิ่มขนาด context โดยไม่จำเป็น และเสี่ยง leak ประวัติโค้ดใน image |
| .env ติดเข้า image | COPY . . คัดลอกทุกไฟล์รวมถึง .env โดยไม่ตั้งใจ | secret เช่น DB_PASSWORD, API_KEY ถูกฝังใน image layer ที่แจกจ่ายได้ |
| dist/ / .next/ ถูกส่ง | build output จาก dev ถูกส่งไปทั้งหมด | ซ้ำซ้อนกับสิ่งที่ RUN npm run build สร้างใหม่ใน image อยู่แล้ว |
ส่วนที่ 5
ตัวอย่างไฟล์ที่ควร ignore
ไฟล์และโฟลเดอร์เหล่านี้ควรอยู่ใน .dockerignore เสมอในโปรเจกต์ Node.js หรือ Next.js เพราะไม่จำเป็นสำหรับการ build หรืออันตรายหากติดเข้าไปใน image
- node_modules/ — dependencies ทั้งหมด: Docker จะ RUN npm ci ติดตั้งใหม่ใน image อยู่แล้ว ไม่ต้องส่งของเก่าจากเครื่องเรา
- .git/ — git repository history: ประวัติ commit และ branch ไม่มีความหมายใน production image
- *.log และ logs/ — log files ระหว่าง development: สร้างขึ้นโดยแอปขณะรัน ไม่ใช่ส่วนหนึ่งของ source code
- .env / .env.* / .env.local — environment variables: มี secret, password, API key ที่ไม่ควรถูกฝังอยู่ใน image ที่แจกจ่าย
- dist/ / build/ / .next/ / out/ — build artifacts: จะถูกสร้างใหม่ด้วย RUN npm run build ใน image อยู่แล้ว ส่งซ้ำไม่มีประโยชน์
ส่วนที่ 6
ตัวอย่างไฟล์ .dockerignore แบบง่าย
นี่คือตัวอย่าง .dockerignore ที่ใช้ได้จริงสำหรับโปรเจกต์ Node.js / Next.js ทั่วไป วางไว้ที่ root ของโปรเจกต์เดียวกับ Dockerfile
แต่ละ pattern บรรทัดหนึ่งคือกฎหนึ่งข้อ บรรทัดที่ขึ้นต้นด้วย # คือ comment
ภาพที่ 2 — build context หลังใช้ .dockerignore
ภาพที่ 2: หลังเพิ่ม .dockerignore ไฟล์ที่ไม่จำเป็นถูกกรองออกก่อนส่งไป Docker daemon — build context เล็กลงจาก ~870MB เหลือ ~2MB build เร็วขึ้น และ secret ไม่ติดเข้า image อีกต่อไป
ส่วนที่ 7
อธิบายแต่ละบรรทัดในตัวอย่าง
มาดูความหมายของแต่ละ pattern ในไฟล์ .dockerignore ด้านบน
| Pattern | ความหมาย | ทำไมต้อง ignore |
|---|---|---|
| node_modules/ | โฟลเดอร์ node_modules ทั้งหมด (trailing slash ระบุว่าเป็นโฟลเดอร์) | Dockerfile จะ RUN npm ci ติดตั้ง dependencies ใหม่อยู่แล้ว ส่งซ้ำทำให้ช้าและอาจ override |
| .git/ | โฟลเดอร์ .git ที่เก็บ git history ทั้งหมด | ประวัติ commit ไม่มีประโยชน์ใน image และอาจเพิ่มขนาด context หลายสิบ MB |
| .env / .env.* | ไฟล์ environment ทุกชนิด รวมถึง .env.local, .env.production | มี secret เช่น DB password, API key — ถ้าติดเข้า image ใครก็ดึงออกได้ด้วย docker run |
| dist/ / build/ / .next/ | build artifacts จากการ build ก่อนหน้า | Dockerfile จะสร้างใหม่ด้วย RUN npm run build ส่งซ้ำทำให้ context ใหญ่โดยไม่จำเป็น |
| *.log | ไฟล์ log ทุกชนิดในทุก directory (wildcard *) | สร้างขึ้นขณะรันแอปใน dev ไม่ใช่ส่วนหนึ่งของ source code |
| .eslintrc* / .prettierrc* | config ของ linter และ formatter ทุกรูปแบบ | ใช้ตอน development เท่านั้น production image ไม่ต้องการ |
| .DS_Store | metadata ที่ macOS สร้างอัตโนมัติ | สร้างโดย OS ไม่เกี่ยวกับแอปเลย ไม่มีประโยชน์ใน image |
| # comment | บรรทัดที่ขึ้นต้นด้วย # เป็น comment | ไม่มีผลต่อการ ignore — ใช้อธิบายเหตุผลให้คนในทีมเข้าใจ |
ส่วนที่ 8
เปรียบเทียบ .dockerignore กับ .gitignore
หลายคนสับสนระหว่าง .dockerignore กับ .gitignore เพราะ syntax เหมือนกันทุกประการ แต่ทั้งสองทำงานคนละจุดและคนละเวลา ควรมีทั้งสองไฟล์ในทุกโปรเจกต์
| ประเด็น | .gitignore | .dockerignore |
|---|---|---|
| วัตถุประสงค์ | บอก git ไม่ให้ track ไฟล์เข้า repository | บอก Docker ไม่ให้รับไฟล์เข้า build context |
| ทำงานตอนไหน | ทุก git operation เช่น add, commit, status | เฉพาะตอนสั่ง docker build เท่านั้น |
| Syntax | glob pattern — *, **, ?, !, / | glob pattern — เหมือนกันทุกประการ |
| Pattern ที่ต้องการ | มักเหมือนกัน แต่ .gitignore อาจ ignore dist/ ที่ .dockerignore ไม่ควร ignore (กรณีพิเศษ) | มักเหมือนกัน แต่มีบางกรณีที่ต่าง เช่น Dockerfile เองไม่ควรอยู่ใน .dockerignore |
| ต้องมีทั้งสองไฟล์ไหม | ใช่ — ทำงานคนละ context | ใช่ — แม้ pattern คล้ายกันมาก ควรแยกเพื่อควบคุมได้อิสระ |
ส่วนที่ 9
ข้อดีของการใช้ .dockerignore
สรุปประโยชน์ที่วัดได้จริงเมื่อเพิ่ม .dockerignore เข้าโปรเจกต์
ประเด็นที่ 1
Build เร็วขึ้นอย่างเห็นได้ชัด — โปรเจกต์ Node.js ที่ node_modules มีขนาด 500MB+ จะลด context เหลือแค่ไม่กี่ MB ส่งเร็วขึ้นหลายสิบเท่า
ประเด็นที่ 2
ปลอดภัยจาก secret leak — .env และ credential files ถูกกันออกตั้งแต่ต้น แม้ COPY . . จะไม่มีทางดึง secret เข้าไปใน image
ประเด็นที่ 3
Layer cache ทำงานได้ถูกต้อง — ไฟล์ที่เปลี่ยนบ่อยและไม่จำเป็น เช่น log ไม่ trigger cache invalidation อีกต่อไป
ประเด็นที่ 4
Image สุดท้ายสะอาดและเล็กลง — ไม่มีไฟล์ dev tooling หรือ build artifacts แฝงอยู่ใน layer ที่ไม่จำเป็น
ส่วนที่ 10
ข้อผิดพลาดที่พบบ่อย
รายการต่อไปนี้คือปัญหาที่มักเกิดขึ้นเมื่อเริ่มใช้ .dockerignore พร้อมวิธีแก้
| ข้อผิดพลาด | สาเหตุ | วิธีแก้ |
|---|---|---|
| ลืมเพิ่ม node_modules/ | คิดว่า Docker รู้เองว่าไม่ต้อง copy | เพิ่ม node_modules/ ในทุกโปรเจกต์ Node.js โดยไม่มีข้อยกเว้น |
| .env ยังติดเข้า image | ลืม ignore ไว้ และ COPY . . คัดลอกทุกอย่าง | เพิ่ม .env และ .env.* ทันที ตรวจสอบด้วย docker run --rm <image> cat .env |
| ไฟล์ที่ต้องการหายไปหลัง COPY | เขียน pattern กว้างเกินไป เช่น * ignore ทุกอย่าง | ใช้ ! เพื่อ re-include ไฟล์ที่ต้องการ เช่น !src/ หรือ !package.json |
| .dockerignore อยู่ผิดที่ | วางไฟล์ไว้ใน subdirectory แทนที่จะอยู่ root | ต้องวาง .dockerignore ที่ root ของ build context เดียวกับ path ที่ระบุใน docker build |
| ใช้ pattern แล้วไม่ได้ผล | ลืม trailing slash หรือใช้ path แบบ absolute | ใช้ path สัมพัทธ์จาก build context เสมอ เช่น node_modules/ ไม่ใช่ /app/node_modules/ |
ส่วนที่ 11
สถานการณ์จริงในการใช้งาน
ขั้นตอนเพิ่ม .dockerignore เข้าโปรเจกต์ที่มีอยู่แล้ว เพื่อปรับปรุง build ให้ดีขึ้นทันที
ส่วนที่ 12
สรุปท้ายบทแบบจำง่าย
จำ 4 จุดสำคัญของ .dockerignore: 1. .dockerignore กรองไฟล์ออกก่อนที่ Docker daemon จะได้รับ build context 2. วางที่ root ของ build context เดียวกับ Dockerfile 3. Syntax เหมือน .gitignore ทุกประการ — glob pattern, *, **, ! 4. ต้อง ignore node_modules/, .env, .git/ ในทุกโปรเจกต์ Node.js
- .dockerignore อ่านก่อน Dockerfile เสมอ — ไฟล์ที่ถูก ignore จะไม่ถูกส่งไปเป็น build context เลย
- วางที่ root ของ build context (directory เดียวกับที่ระบุใน docker build .)
- Syntax เหมือน .gitignore — glob pattern, *, **, !, / ใช้ได้ทั้งหมด
- ต้อง ignore node_modules/, .env / .env.*, .git/ เสมอในโปรเจกต์ Node.js
- ดู 'Sending build context to Docker daemon X.XX MB' ใน output เพื่อวัดขนาด context
- .dockerignore และ .gitignore ทำงานคนละจุด ควรมีทั้งสองไฟล์ในทุกโปรเจกต์
แบบฝึกหัด
ทดสอบความเข้าใจ
ลองตอบคำถามต่อไปนี้ด้วยตัวเอง แล้วกดดูแนวเฉลยเพื่อเปรียบเทียบ