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

สุดยอดทีม (Extraordinary Team)

สุดยอดทีม (Extraordinary Team)

ท้ายหนังสือ Teamwork is an Individual Skill ของ Christopher Avery ได้กล่าวถึงสมการของสุดยอดทีมไว้ดังนี้ครับ Extraordinary Collaboration = Exchange + Expansion + Integrity ผมใช้เวลาอ่านตรงนี้ และอีก 3 บทที่ขยายความเรื่อง Exchange, Expansion และ Integrity อยู่เกือบ 2 สัปดาห์กว่าจะพอเข้าใจมันอย่

By Chokchai
ไล่ตามความฝัน กับ ดูแลตัวเอง

ไล่ตามความฝัน กับ ดูแลตัวเอง

ไล่ตามความฝัน กับ ดูแลตัวเอง ก่อนหน้านี้ผมเคยเล่าถึงขั้วตรงข้าม (Polarity) ระหว่างความคล่องตัวกับความสร้างสรรค์ไปแล้ว ครั้งนี้ผมมองว่า “การไล่ตามความฝัน” และ “การดูแลตัวเอง” (เปรียบเสมือน นักรบ กับ นักรัก) ก็เป็นแสงและเงาของกันและกั

By Chokchai
สกรัมเป็น Empirical process

สกรัมเป็น Empirical process

กระบวนการแก้ปัญหาในโลกแบ่งเป็น 2 แบบ แบบแรกคือ Defined process ซึ่งเป็นกระบวนการที่มีขั้นมีตอนชัดเจน เช่น Waterfall เป็นต้น ส่วนแบบที่สองคือ Empirical process หรือ "กระบวนการเชิงประจักษ์" ซึ่งเป็นการทำไปแล้วก็ปรับไปเรื่อย ๆ สกรัมเป็นแบบหลัง

By Chokchai
สกรัมมาสเตอร์ observe ผู้คน

สกรัมมาสเตอร์ observe ผู้คน

ครั้งที่แล้วผมแบ่งปันไปว่าสิ่งหนึ่งที่ผมตอนเป็นสกรัมมาสเตอร์มองหาคือ polarity หรือขั้วตรงข้าม ซึ่งคู่แรกที่ผมแบ่งปันไปคือ ระเบียบ (control) และความสร้างสรรค์ (creative) วันนี้ผมตะมาแบ่งปันอีกรูปแบบหนึ่งของ 2 ขั้วนี้ที่เรียกว่า survive (อยู่รอดปลอดภั

By Chokchai