Dockerfile Linter: จับปัญหา Security, Cache และขนาด Image ก่อน Build ทุกครั้ง
ตรวจ Dockerfile ใน browser ได้ทันที ทั้งปัญหา security, cache และขนาด image พร้อม fix ระดับบรรทัด ตาม rule แบบ hadolint ที่คุ้นเคย
Table of Contents
Dockerfile Linter: จับปัญหา Security, Cache และขนาด Image ก่อน Build ทุกครั้ง
ทุก container ที่คุณ deploy เริ่มต้นจากไฟล์ Dockerfile และทุกความผิดพลาดในไฟล์นั้นจะถูก bake เข้าไปใน image แล้วไหลต่อไปยังเครื่อง production Dockerfile Linter ตรวจ Dockerfile ของคุณได้ใน browser โดยตรง พร้อมชี้ปัญหาด้าน security, cache และขนาด image ด้วย rule ID สไตล์ hadolint ที่คุ้นเคย ระบุระดับความรุนแรง และแนะนำวิธีแก้ระดับบรรทัด — ก่อนที่ layer แรกจะถูก build ด้วยซ้ำ
ส่วนใหญ่แล้วทีมต่างเจอปัญหาเหล่านี้ช้าเกินไป: เจอรหัสผ่านใน image history หลัง push ไปแล้ว, image ตัวโตจนทุก deploy ช้าลง, หรือ build ที่ไม่เคย hit cache เพราะเรียง instruction ผิดลำดับ ทั้งหมดนี้แก้ทีเดียวบรรทัดเดียวถ้าจับได้ตอนเขียนโค้ด แต่กลายเป็นงานสืบค้นชวนปวดหัวถ้าไปเจอตอน production และที่สำคัญ ทุกอย่างที่ paste เข้าไปไม่ถูกอัปโหลดไปไหน — เครื่องมือประมวลผลใน browser 100%
ทำไมต้องใช้ Dockerfile Linter?
- จับความผิดพลาดด้าน security จริง ๆ ไม่ใช่แค่เรื่องสไตล์ SC-ENV-SECRET จับ secret ที่เขียนลงใน ENV, DL3002 จับ container ที่รันด้วย USER root ตลอด และ DL3004 จับ sudo ใน RUN — รูปแบบที่อยู่เบื้องหลังเหตุการณ์ container ที่พังบ่อยที่สุด
- ระบุตำแหน่งระดับบรรทัดพร้อมวิธีแก้ ทุก issue ถูกผูกกับบรรทัดที่ก่อปัญหาพอดี เรียง error ก่อนแล้วไล่ตามเลขบรรทัด ทำให้รายงานอ่านเหมือน to-do list ที่เรียงลำดับให้แล้ว
- ใช้ rule ID สไตล์ hadolint ที่คุ้นเคย DL3006, DL3008, DL3013 และเพื่อน ๆ อีกกลุ่มอ้างอิงหมายเลขเดียวกับ linter ยอดนิยมอย่าง hadolint ดังนั้นเอกสาร บล็อก หรือ wiki ของทีมที่เคยเขียนไว้ยังใช้ได้เลย
- ข้อมูลไม่หลุดออกจากเครื่อง linter ทำงานฝั่ง client ล้วน ๆ เหมาะกับโค้ด infrastructure ภายในที่นโยบายห้ามส่งไปบริการภายนอก
- ได้ feedback เร็วกว่าการ build docker build อาจต้องรอหลายนาทีกว่าจะเห็นปัญหา ที่ตัว linter นี้ชี้ให้เห็นภายในไม่กี่มิลลิวินาที
- ฟรีและไม่มีพิธีรีตอง ไม่ต้อง install ไม่ต้องสมัคร ไม่ต้องคอยอัปเดตเวอร์ชัน เปิดแท็บ paste ไฟล์ แล้วเริ่มแก้ได้เลย
ฟีเจอร์หลัก
| Rule | ระดับความรุนแรง | สิ่งที่ตรวจจับ |
|---|---|---|
| SC-ENV-SECRET | Error | Secret ที่ถูกเขียนลงใน ENV instruction |
| DL3011 | Error | หมายเลข port ไม่ถูกต้องใน EXPOSE |
| DL3006 | Warning | FROM ที่ pin ด้วย tag latest ที่ลอยตัว |
| DL3004 | Warning | sudo ภายใน RUN instruction |
| DL3002 | Warning | Container ที่ไม่เคยออกจาก USER root |
| DL3020 | Warning | ใช้ ADD ในจุดที่ COPY ปลอดภัยกว่า |
| DL3008 | Info | apt-get install โดยไม่ pin เวอร์ชัน |
| DL3009 | Info | apt-get update ที่ไม่ล้าง cache ใน RUN เดียวกัน |
| DL3013 | Info | pip install โดยไม่ใส่ --no-cache-dir |
| DL3016 | Info | npm install โดยไม่ pin เวอร์ชัน |
| DL3048 | Info | HEALTHCHECK หายไปหรือรูปแบบไม่ถูกต้อง |
| DL3059 | Info | RUN ติดกันหลายบรรทัดที่ควรรวมเป็น layer เดียว |
ผลลัพธ์ถูกคัดแยกแบบ error มาก่อน — error อย่าง SC-ENV-SECRET ขึ้นหัวรายการ ตามด้วย warning และ info แต่ละรายการมี rule ID พร้อมคำอธิบายภาษาง่าย ทำให้ developer ที่เพิ่งเริ่มเล่น container ก็อ่านแล้วลงมือแก้ได้ทันที
วิธีการใช้งาน
- เปิด Dockerfile Linter ใน browser สมัยใหม่ตัวไหนก็ได้ ไม่ต้อง install ไม่ต้องสมัครบัญชี
- วาง Dockerfile ลงใน editor หรือพิมพ์ไฟล์ใหม่ตั้งแต่ต้นถ้ากำลังเริ่มโปรเจกต์ใหม่
- อ่านรายการ issue ที่เรียง error ก่อนแล้วไล่ตามเลขบรรทัด เริ่มจากแถว error อย่าง SC-ENV-SECRET ก่อนเป็นอันดับแรก
- แก้ไขตามคำแนะนำที่บรรทัดที่ถูกชี้ ส่วนใหญ่เป็นงานกลไก: pin เวอร์ชัน, ลบ secret, รวมคำสั่ง RUN, หรือเติม --no-cache-dir
- ตรวจซ้ำจนรายงานสะอาด แล้วคัดลอกไฟล์กลับเข้า repository เป็น commit เดียวที่ review ง่าย
กฎแต่ละกลุ่มจับอะไรบ้าง
ด้าน Security: secret และสิทธิ์การเข้าถึง
SC-ENV-SECRET คือ rule ที่ควรถือเป็น build blocker การเขียน ENV DB_PASSWORD=supersecret จะเก็บค่านั้นไว้ใน image configuration ซึ่งค้างอยู่ใน image history และใครก็ที่ pull image ได้ก็อ่านได้ วิธีที่ถูกต้องคือฉีด secret ตอน runtime ผ่าน platform แทน DL3002 เตือนเมื่อ container ไม่เคยออกจาก USER root เพราะ process ที่ถูกแฮ็กจะเริ่มด้วยสิทธิ์สูงสุดทันที และ DL3004 จับ sudo ใน RUN — ถ้าต้องใช้ sudo ตอน build แปลว่า USER ของคุณตั้งผิดอยู่แล้ว
ด้าน Cache และ layer
Docker layer เป็นแบบ append-only นี่คือเหตุผลที่ DL3009 และ DL3059 สำคัญ ถ้า apt-get update รันใน RUN หนึ่งและคำสั่ง install รันอีก RUN หนึ่ง layer ของ package list จะค้างอยู่ใน image ตลอดไป การลบไฟล์ใน layer ถัด ๆ ไปแค่ช่วยซ่อนเท่านั้น DL3059 จับ RUN ที่เขียนติดกันหลายบรรทัดซึ่งควรรวมกันเพื่อให้การล้างค่าออกผลจริง:
# ก่อนแก้: package list ถูก bake ไว้ใน layer แยก FROM python:3.12-slim RUN apt-get update RUN apt-get install -y libpq-dev
# หลังแก้: layer เดียว ล้าง list ภายใน layer นั้นเอง
FROM python:3.12-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends libpq-dev \
&& rm -rf /var/lib/apt/lists/*
เวอร์ชันหลังแก้เหลือ layer เดียวแทนสาม และไม่มี package index ติดไปกับ image อีกเลย
ด้านขนาด Image และการ pin เวอร์ชัน
DL3006 เตือน FROM ที่ใช้ tag latest — ค่าที่ลอยตัวตลอดเวลา ทำให้ build ไม่ reproducible และ rollback ก็กลายเป็นการเดา การ pin เป็น python:3.12-slim ไม่เสียอะไรเลยแต่ได้ build ที่คาดเดาได้ DL3008 ต่อยอดแนวคิดเดียวกันกับ apt-get install, DL3013 ขอให้ใส่ --no-cache-dir ตอน pip install เพื่อไม่ให้ wheel ที่โหลดมาหลงเหลืออยู่ใน layer และ DL3016 ใช้หลักเดียวกันกับ npm install
ด้าน Healthcheck
DL3048 รายงาน HEALTHCHECK ที่หายไปหรือเขียนผิดรูปแบบ ถ้าไม่มี orchestrator จะแยกไม่ออกว่า application ค้างหรือแค่ทำงานหนัก container ที่ crash ค้างแต่ยังรันอยู่ก็ยังรับ traffic ต่อไป การใส่ healthcheck เบา ๆ ช่วยให้ container รายงานสถานะตัวเองได้
ตัวอย่างการใช้งานจริง
เป็น quality gate ก่อนถึง CI
วางไฟล์ตรวจทุกครั้งก่อน commit ที่แตะไฟล์นี้ error จะถูกแก้ก่อนถึง shared branch และ CI ก็ไม่ต้องเป็นที่แรกที่ค้นพบความผิดพลาดอีกต่อไป
Review และ onboarding ที่ไวขึ้น
ตัว linter รับงานกลไกไป ทำให้ reviewer โฟกัสที่ logic และ architecture ส่วนคำอธิบายของแต่ละ rule ยังใช้เป็นสื่อการสอนสำหรับคนที่เพิ่งเริ่มเล่น container ได้อีกทาง
ลดขนาด image ที่อ้วนเกินไป
ตัวการหลักของ image ขนาดยักษ์คือเศษจาก DL3009, การลืม --no-cache-dir และการ install แบบไม่ pin จนดึง package เกินจำเป็น ตรวจก่อนลงมือลดขนาดจะได้ checklist ที่ชัดเจน และบ่อยครั้ง fix เหล่านี้ลดขนาด image ได้ครึ่งหนึ่ง
ดูแล secret ก่อน push
Developer มัก hardcode credential "ไว้เทสต์เครื่องตัวเองก่อน" แล้วลืมลบ เพราะ SC-ENV-SECRET เรียงขึ้นหัวสุดในฐานะ error การตรวจสามสิบวินาทีก่อน push จึงจับรูปแบบนี้ได้พอดี — ก่อน image ไปถึง registry ที่ credential แทบจะถาวรตลอดไป
แนวทางปฏิบัติที่ดี
- ถือว่า error คือ blocker ส่วน warning คือ debt แก้ SC-ENV-SECRET ทันที ส่วน warning อย่าง DL3006 ใส่ไว้ใน sprint เดียวกันได้
- Pin ให้หมดเท่าที่ทำได้ ทั้ง base image tag, apt package และเวอร์ชัน pip/npm — build ที่ reproducible คือการอัปเกรดความเสถียรที่ถูกที่สุด
- Rotate credential ที่เคยตกไปอยู่ในไฟล์ การลบ secret ออกจากบรรทัด ENV ไม่ได้ลบมันออกจาก layer ที่ cache ไว้
- เรียง instruction จากแทบไม่เปลี่ยนไปยังเปลี่ยนบ่อย วาง install dependency ไว้ก่อน copy source code เพื่อให้ cache ยังอุ่นอยู่
- รวมคำสั่งที่เกี่ยวข้องตาม DL3009 และ DL3059 ต่อด้วย && และล้างค่าภายใน instruction เดียวกัน ไม่ให้หลงเหลือไป layer ถัดไป
- ตรวจซ้ำหลัง bump dependency การเปลี่ยน base image อาจก่อ issue ใหม่ ตรวจสิบวินาทีช่วยให้ไฟล์สะอาดต่อเนื่อง
เริ่มสร้าง Image ที่สะอาดขึ้นตั้งแต่วันนี้
ความปลอดภัยของ container ส่วนใหญ่คือเรื่อง hygiene และ hygiene ส่วนใหญ่คือเรื่องนิสัย Dockerfile Linter เปลี่ยน rulebook สไตล์ hadolint ให้เป็น checklist ระดับบรรทัดที่ใช้ได้ทันทีกับ Dockerfile ไฟล์ไหนก็ได้ โดยไม่ต้อง install อะไรเลย — เป็นส่วนตัว ทำงานใน browser ลอง paste Dockerfile ปัจจุบันของคุณดู แล้วจะรู้ว่ามีอะไรรออยู่
เครื่องมือที่เกี่ยวข้องที่คุณอาจสนใจ:
- Dockerfile Generator — สร้าง Dockerfile ที่มีโครงสร้างดีสำหรับ Node.js, Python และ Go
- Docker Compose to Kubernetes Converter — แปลงไฟล์ compose เป็น Kubernetes manifests
- YAML Formatter — จัดรูปแบบและตรวจ YAML config ที่ทำงานร่วมกับ Dockerfile ของคุณ
ขอให้ layer เล็กลง และ secret อยู่ที่ runtime ตลอดไป
คำถามที่พบบ่อย
ถ: Dockerfile ของฉันถูกอัปโหลดขึ้น server ไหม?
ตอบ: ไม่ linter ทำงานใน browser 100% — เนื้อหาถูกวิเคราะห์ด้วย JavaScript ในเครื่อง ไม่มีการส่งข้อมูล เก็บ หรือ log ที่ใดทั้งสิ้น
ถ: เทียบกับการรัน hadolint บนเครื่องตัวเองแล้วต่างกันอย่างไร?
ตอบ: rule ID และระดับความรุนแรงใช้ convention สไตล์ hadolint เหมือนกัน ผลลัพธ์จึงตรงกับที่ hadolint รายงาน ความต่างคือความสะดวก: ไม่ต้องแจก binary ให้ทีม และเปิดใช้ได้ทันทีใน browser ทุกที่
ถ: ทำไม rule ถึงติดกับบางอย่างที่ build ผ่านสบาย?
ตอบ: lint rule สะท้อน best practice ไม่ใช่ hard failure warning อย่าง DL3006 เรื่อง tag latest จะไม่หยุด build ของคุณ แต่เตือนความเสี่ยงที่มักโผล่ทีหลัง ควรมองว่าเป็นข้อความเชิญให้ตัดสินใจอย่างมีสติ ไม่ใช่ error ที่ต้อง suppress
ถ: ใช้กับ multi-stage Dockerfile ได้ไหม?
ตอบ: ได้ ไฟล์ถูกประมวลผลทีละบรรทัด rule จึงครอบคลุมทุก stage รวมถึง SC-ENV-SECRET ใน build stage ที่ไม่เคย copy secret เข้า image สุดท้ายด้วย
ถ: paste Dockerfile จาก repository ส่วนตัวได้ไหม?
ตอบ: นั่นแหละ use case หลัก — เพราะไม่มีอะไรถูกอัปโหลด ไฟล์ภายในที่อ้างถึง private registry และ hostname ภายในจึงตรวจได้โดยไม่ผิดนโยบายการจัดการข้อมูล