เทคนิคการเขียน Dockerfile ให้ดีขึ้นกว่าเดิม
วันนี้จะมาแชร์เทคนิคต่างๆ สำหรับการใช้งาน Dockerfile ให้มีประสิทธิภาพมากขึ้นนะครับ ก่อนอื่นขอย้อนกลับไป พูดถึง Dockerfile กันสักหน่อย ว่าคืออะไร มีหน้าทีอะไร
Dockerfile คือ text document ที่ระบุการใช้งานและคำสั่งทั้งหมด เพื่อเอาไว้ประกอบร่าง Docker Image ขึ้นมา โดยใช้คำสั่ง docker build เพื่อสร้างเป็น Docker Image
*หมายเหตุ ตัวอย่างด้านล่าง จะเป็นการเขียนโปรเจค Java บน Maven
Incremental build time — เวลาในการสร้าง build
ในการพัฒนาโปรแกรม เมื่อเราต้องการสร้าง Docker Image ในครั้งแรกจะยังไม่มีการใช้งานในส่วนของ Caching แต่เมื่อเรามีการเปลี่ยนแปลงโค๊ดแล้วทำการสร้าง Docker Image อีกครั้ง เราจะสามารถใช้งานในส่วนของ Caching นี้ได้ ทำให้เราสามารถลดเวลาในการ Build ได้นะครับ
Tip #1: Order matters for caching
ลำดับของการรันคำสั่งมีความสำคัญ โดยเราถ้าเรามีการเปลี่ยนแปลงไฟล์หรือแก้ไขคำสั่งใน Dockerfile จะทำให้ Caching ไม่สามารถใช้งานได้ เราจึงควรนำคำสั่งที่มีการเปลี่ยนแปลงบ่อยๆ ย้ายไปอยู่ด้านล่างแทน ดังรูปด้านบน
Tip #2: More specific COPY to limit cache busts
ถ้าเป็นไปได้เวลาใช้งานคำสั่ง COPY ในการก๊อปปี้โค๊ดเข้าไปใน Docker Image ให้เราควรหลีกเลี่ยงการใช้งาน “COPY .” (คำสั่งนี้จะก๊อปปี้ไฟล์ทั้งหมดในโฟลเดอร์นั้น ) ให้ใช้งานเป็นระบุโฟลเดอร์ที่ต้องการแทนจะดีกว่า เพราะเมื่อเรามีการแก้ไขไฟล์แค่โฟลเดอร์เดียวหรือไฟล์เดียว จะทำให้ Cahcing ไม่สามารถใช้งานได้
Tip #3: Identify cacheable units such as apt-get update & install
เมื่อเราเขียนคำสั่ง RUN แต่ละบรรทัด การทำ Caching จะแยกกัน เราควรวิเคราะห์คำสั่งที่ทำงานด้วยกันเสมอ มารันด้วยกัน เช่น apt-get update กับ apt-get -y install [package] มาทำงานด้วยกัน เพราะปกติเราจะทำการอัพเดทก่อนเพื่อให้เราสามารถใช้งาน package ในเวอร์ชั่นล่าสุดเสมอ
Reduce Image size — ขนาดของ Docker Image
ในหัวข้อนี้จะพูดเกี่ยวกับเทคนิคการลดขนาดของ Docker Image
Tip #4: Remove unnecessary dependencies
เราควรลบแพคเกจที่ไม่จำเป็นต้องใช้งานในการรันโปรแกรมหรือสิ่งที่ใช้ในการดีบั๊กต่างๆ เช่น vim ssh ออกไปนะครับ ถ้าเราอยากดีบั๊ก เราสามารถลงที่หลังได้ถ้าเราต้องการ
บางครั้งเวลาเราลงแพคเกจต่างๆ จะมีการติดตั้งแพคเกจแนะนำต่างๆมาด้วย เราสามารถใส่คำสั่ง — no-install-recommends เพื่อลงเฉพาะที่เราต้องการใช้งานเท่านั้น
Tip #5: Remove package manager cache
เวลาเราทำการติดตั้งแพคเกจต่างๆ ส่วนใหญ่จะมีการทำ caching ไว้ เพื่อใช้ครั้งต่อไป ซึ่งไม่มีความจำเป็นเมื่อเราใช้งาน Docker Image นะครับ เพราะเราจะทำการ build ใหม่ทุกครั้ง ทำให้เราสามารถลบในส่วนนี้ได้เลยหลังจากเราติดต่อเรียบร้อย
Maintainability — การบำรุงรักษา
Tip #6: Use official images when possible
เราควรเลือกใช้ image จากทางผู้พัฒนาหลัก เพื่อลดเวลาในการบำรุงรักษาต่างๆ เช่น package, security เป็นต้น
Tip #7: Use more specific tags
อย่าพยายามใช้แท็ก latest เพราะเมื่อเราทำการ build ใหม่ ทางโปรแกรมจะทำการดึง image เวอร์ชั่นล่าสุดมาใช้งานเสมอ เพราะฉะนั้นโปรแกรมของเรายังไม่ซัพพอร์ตหรือในเวอร์ชั่นนั้นๆ มีการอัพเดทเปลี่ยนแปลงเยอะ มีโอกาสทำให้โปรแกรมของเราไม่สามารถทำงานได้ ทางที่แนะนำ คือ ให้ระบุเวอร์ชั่นที่เราต้องการเข้าไป แล้วทำการเปลี่ยนเองเมื่อเราต้องการอัพเดทนะครับ
Tip #8: Look for minimal flavours
เลือกใช้งาน tag ให้เหมาะสม เพราะแต่ละ tag มีขนาดไม่เท่ากัน ขึ้นอยู่กับโปรแกรมของเรานะครับ ว่าต้องการ OS แบบไหน โดยที่ยอดนิยมจะเป็น alpine ซึ่งจุดเด่น คือ จะมีขนาด image ที่เล็กมาก ทำให้หลังจาก build แล้ว มีขนาดเล็กมากและในบางครั้งยังทำให้ใช้งานทรัพยากรเครื่องน้อยกว่าด้วยนะครับ
Reproducibility
Tip #9: Use multi-stage builds to remove build dependencies (recommended Dockerfile)
อันนี้เป็นอีกทีนึงที่เรียกว่าการใช้งาน multi-stage เพื่อลดระยะเวลาในการBuild เพราะจะทำการ cahce ไว้แล้ว
- เราสามารถทำการใช้งานคำสั่ง AS [STAGE_NAME] ดังรูปด้านบน
- ขั้นตอนต่อไป เราจะทำการอ้างอิงจากไฟล์ที่เราทำการ build ไว้แล้วในข้างต้น โดยใช้คำสั่ง COPY — from=[STAGE_NAME] โดยในเคสนี้จะใช้ชื่อว่า builder
Multi-stages builds จะช่วยทำให้เราลดเวลาในการรันคำสั่งในส่วนของการลงแพคเกจต่างๆ ก๊อปปี้ไฟล์ ได้นะครับ
ก็จบไปแล้วนะครับ สำหรับเทคนิคเพื่อทำให้เราเขียน Dockerfile ให้มีประสิทธิมากขึ้นนะครับ ยังไงถ้ามีส่วนไหนสงสัยหรือผิดพลาด สามารถคอมเม้นได้เลยนะครับ
Reference : https://blog.docker.com/2019/07/intro-guide-to-dockerfile-best-practices
คิดและเขียนคือสิ่งที่ผมชอบ ได้ทดลองทำอะไรใหม่ๆ เพื่อนำมาประยุกต์และต่อยอดในเรื่องต่างๆ พร้อมถ่ายทอดเรื่องราวจากชีวิตจริง จากประสบการณ์ จากแนวคิดของผม :)