Optimize Docker Build

Optimize Docker Build

สัปดาห์ที่แล้วผมได้ไป Odd-e boring gathering ที่หางโจวมา ชาว Odd-e ทั่วโลกจะมาเจอกันปีละ 2 ครั้งเพื่อแลกเปลี่ยนความรู้กัน

ครั้งนี้ ผมเลือกที่จะร่วมกันสร้าง product ขึ้นมาด้วยกันกับเพื่อนๆชาว Odd-e เราทำ Sprint 5 วัน รับ item มา 2 item จาก product owner เราตกลงกันว่าเราจะ pair programming กันทุกลมหายใจ มี techical requirement นิดหน่อยว่า architecture ต้องเป็นอย่างไร และทุกอย่างต้อง run อยู่ใน docker หลังตกลงกันเสร็จแล้ว sprint ก็เริ่มต้น

ทุก ๆ คน เก่งกันมาก ๆ ผมได้เรียนรู้เยอะมาก สมศักดิ์ศรีทีมที่สมาชิกแต่ละคนเป็นโค้ชมือพระกาฬจากทั่วโลกมารวมตัวกันจริง ๆ

จบ sprint ปรากฏว่าไม่มีห่าอะไรเสร็จเลย… เวลาส่วนใหญ่เราเสียไปกับการ download maven package กับ download npm package สิ่งสำคัญที่ผมได้เรียนรู้จากประสบการณ์ sprint นี้คือ

เวลาเขียน docker file ให้แยกจังหวะ download dependency libraries กับ compile code ออกจากกัน

ลองดูตัวอย่าง Dockerfile ด้านล่าง

FROM maven:slim as build-stage
COPY ./ ./
RUN mvn install
CMD mvn spring-boot:run

(Gist) https://gist.github.com/juacompe/1733f108197e6eb22b5e2e9180547e70

ตั้งต้นจาก maven image แล้ว copy code แล้วก็สั่ง build แล้วก็ run ดูตรงไปตรงมา ปัญหาคือ ทุก ๆ ครั้งที่เราแก้โค้ด บรรทัดที่ 2 จะ dirty แล้วมันจะต้องทำ mvn install ใหม่ (ซึ่งจังหวะนี้จะ download libs ทั้งหลาย) ทุกครั้ง…

ลองมาดูอันที่แยกจังหวะ download กับจังหวะ build กัน

FROM maven:slim
# copy pom file
COPY ./pom.xml ./
# download all dependency libraries
RUN mvn dependency:go-offline -B
# copy the rest of the code
COPY ./ ./
# build package
RUN mvn install
CMD mvn spring-boot:run

(Gist) https://gist.github.com/juacompe/6b522ed46f26c4953657d7264ed13703
separate library downloading and package building

พอแก้เป็นแบบนี้ ตราบใดที่ pom.xml ไม่ถูกแก้ ตอนสั่ง docker build มันจะใช้ cache ไปจนถึงบรรทัดที่ 7 ( COPY ./ ./ ) ซึ่งทำให้ไม่ต้อง download libs ทั้งหลายใหม่ ทำให้มันเร็วขึ้นมาก

นอกจากนี้ ขณะที่เรากำลังแก้ Dockerfile เราไม่ได้แก้โค้ดเลย แต่พอสั่งบรรทัดที่ 7 ที่มัน copy ทุกอย่าง มันก็จะต้อง build ใหม่ทุกครั้ง ทำไงดี?

เราสามารถกำหนด file ที่เราจะไม่ copy เข้าไปใน image ได้ ใน file ชื่อ .dockerignore ครับ

Dockerfile
.dockerignore
.git/


(Gist) https://gist.github.com/juacompe/d09c0fb42c166af643591ed01b00f25d
.dockerignore

file นี้ระบุว่า ไอ้ file Dockerfile ,.dockerignore และ.git เนี่ย ไม่ต้องเอาเข้าไปนะ เพราะใน container ไม่จำเป็นต้องใช้

เพียงแค่นี้ เราก็สามารถ get feedback เร็ว ๆ เวลาที่เราแก้ Dockerfile แล้วจะลอง run docker build ดูได้แล้วครับ

ถ้าอยากประหยัดเวลามากกว่านี้ทำไง?

มี 3 ทางถ้าอยาก optimize มากกว่านี้ ประกอบด้วย 1 ทางสวย ๆ และอีก 2 ทางสกปรก ๆ หน่อย

ทางแรก คือ สร้าง dockerhub ขึ้นมา host เอง เพื่อจะได้ไม่ต้องไป load image จาก internet ทางนี้สวยสุด ทำยากไหม? แล้วแต่ความชำนาญ ผมเห็น Chai Feng (เพื่อนจาก Odd-e ทีมเซี่ยงไฮ้) ทำ 10 นาที

ทางที่สองคือ สร้าง docker image ใหม่ที่ download dependency libs เสร็จแล้ว แล้ว push ขึ้น docker hub เพื่อใช้เป็น base image ต่อให้ pom.xml เปลี่ยน ก็ download เพิ่มไม่เยอะ

ทางที่สามคือ mount path ที่ใช้ในการเก็บ dependency libraries (~/.m2e/) ออกมาใส่เครื่อง host แบบนี้เราจะได้ใช้ประโยชน์จาก caching ของ maven เอง

ถ้าเป็น node project ทำไง?

ใช้ idea เดียวกันครับ คือ copy package.json กับ package-lock.json เข้าไปก่อน แล้ว run npm install แยกกันกับ npm build

credit: http://whitfin.io/speeding-up-maven-docker-builds/ สำหรับคำสั่ง download mvn dependencies

ref: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

Read more

ในวันที่ฉันผิดข้อตกลง

ในวันที่ฉันผิดข้อตกลง

ในหนังสือ Teamwork is an Individual Skill ของ Christopher Avery นอกจากจะสอนให้ผมรู้จักวิธีทักเวลาเพื่อนผิดข้อตกลงแล้ว ยังสอนวิธีซ่อมความสัมพันธ์ในวันที่ผมเป็นฝ่ายผิดข้อตกลงด้วย ซึ่งมี 4 ขั้นตอนดังนี้ครับ 1. Acknowledge mistakes (ยอมรับความผิ

By Chokchai
ในวันที่เพื่อนผิดข้อตกลง

ในวันที่เพื่อนผิดข้อตกลง

หนังสือ Teamwork is an individual skill ของ Christopher Avery เป็นคลังสมบัติจริง ๆ มีหลายหลักการที่ผมเก็บสะสมมาล้วนถูกรวบรวมอยู่ในเล่มนี้ หนังสือเล่มนี้เน้นการสร้างทีมในฝัน แทนที่จะตามหาทีมในฝัน ไม่ว่าเพื่อนร่วมทีมจะเป็นยังไง หนังสื

By Chokchai
Prolonged fasting 2025

Prolonged fasting 2025

ผมตื่นมาเช้านี้ รู้สึกเลยว่าหมดแรง ลองพยายามกำมือแน่น ๆ แต่กำไม่ไหวเลย เรี่ยวแรงมันน้อยไปหมด ลุกขึ้นช้า ๆ หลังปรับความดันได้ ก็ลองไปชั่งน้ำหนัก ลงไปอีก 0.35 กิโลจากเมื่อวาน ลองวัดความดันดู ความดันปรกติ 115/75 ค่อย ๆ พาตั

By Chokchai
ชีวิต

ชีวิต

ผมกำลังพยายามทำ prolonged fasting (อดอาหาร 72 ชั่วโมง) ครั้งแรกในชีวิต ณ ตอนนี้เป็นชั่วโมงที่ 34 เมื่อเช้าตอนออกไปวิ่ง 5 ก.ม. ระหว่างวิ่งอยู่ก็นึกขึ้นมาได้ว่าตอนถือศีลอด (ตามหลักศาสนาอิสลาม) ซึ่งอดตั้งแต่พระอาทิตย์ขึ้นจนพระอาทิตย์ตกดิน ผมเคยคิ

By Chokchai