Skip to main content
DockerLibrary / Framework

Docker build เร็วกว่าเดิม เพียงเข้าใจการจัดการ cache

สำหรับใครที่ใช้ Docker อาจจะพอรู้ประโยชน์หลายๆอย่างจากการใช้ Docker ในกระบวนการทำงานแล้วก็กำลังสนุกกับมันอยู่ แต่ก็น่าจะมีหลายๆคนที่พอได้ใช้มาสักระยะหนึ่งก็เริ่มเจอจุดที่ไม่ค่อยสะดวก อย่างเช่นขั้นตอนการสร้าง Docker image ที่เราจะมาพูดถึงกันในบทความนี้

เขียนโดย
Developer
@ borntoDev

Docker Image คืออะไร ?

ก่อนอื่นมาทบทวนแบบสั้นๆกันสักนิดหนึ่ง Docker image เป็นเหมือนหัวใจหลักของ Docker คือการใช้เป็นแม่แบบของ container อธิบายก็คือ เรามีโค้ดที่เขียนขึ้นมาเองไม่ว่าจะเขียนด้วยภาษาอะไรก็ตาม เวลาที่เราอยากทำให้โปรแกรมของเรารันแบบ Docker ได้ ก็จะมีขึ้นตอนคร่าวๆคือ

code ที่เขียน -> แปลงร่างด้วย Dockerfile -> ได้เป็น Docker image -> เอาไปรันในรูปแบบ container

จะเห็นว่าการที่เราจะแปลงโค้ดที่เราเขียนให้กลายเป็น Docker image ได้จะต้องมี Dockerfile ที่ใช้สำหรับแปลงร่าง ซึ่งจุดนี้นี่เองที่อาจจะมีคนประสบปัญหา

 

ทำไมการสร้าง Docker image ถึงช้า ?

การสร้าง Docker image นั้นเป็นงานปกติที่ผู้ใช้ Docker ทุกคนต้องทำกันเป็นประจำอยู่แล้ว โดยคำศัพท์ที่ใช้เรียกกระบวนการนี้ก็ตรงตัวเลยคือคำว่า “build” โดย “ขั้นตอน” ในการ build นั้นเราจะเขียนเอาไว้ในไฟล์ที่ชื่อว่า “Dockerfile”

โดยเจ้า Dockerfile นี้จะมีขั้นตอนตั้งแต่การ copy ไฟล์ของเรา ติดตั้ง library หรือเครื่องมือที่จำเป็นต่างๆ ไปจนถึงการรันโค้ดของเรา ด้วยความที่มันรวมกระบวนการหลายๆอย่างเอาไว้ ทำให้ยิ่งโค้ดของเราเยอะขึ้น ก็ยิ่งต้องใช้เวลานานมากขึ้นเวลาที่ build นับว่าเป็นจุดที่หลีกเลี่ยงไม่ได้จริงๆในการใช้ Docker 

การทำงานของ Dockerfile

อย่างแรกเลยเราต้องรู้ก่อนว่าการ build Docker image นั้นมันทำงานยังไง โดยเราจะใช้ตัวอย่างเป็น calculator app ที่เขียนด้วย React จาก ahfarmer/calculator: Simple calculator built with React (github.com) ลองเอามาทำเป็น Docker image กัน

มาเริ่มจากการสร้างไฟล์ชื่อว่า “Dockerfile” เอาไว้ที่ชั้นนอกสุดของ project

# 1) เลือก base image
FROM node:14-alpine
# 2) กำหนด directory ที่จะทำงาน
WORKDIR /app

# 3) copy ไฟล์ใน /src ทั้งหมด ไปไว้ใน image
COPY ./src /app/src
# 4) copy ไฟล์ package.json ไปไว้ใน image
COPY package.json ./
# 5) ติดตั้ง dependencies
RUN npm install

# 6) เปิด port 3000 ให้เข้าถึงได้
EXPOSE 3000
# 7) run react app
CMD [ "npm", "start" ]

จะเห็นว่ามีอยู่ทั้งหมด 7 คำสั่ง พอเรา build Dockerfile นี้ด้วยคำสั่ง docker build -t calculator . จะเห็นว่า Docker แสดงขั้นตอนออกมาทั้งหมด 5 ขั้นตอน ซึ่งก็คือ คำสั่งที่ 1) – 5) เพราะว่า 6) กับ 7) นั้นเป็นแค่การกำหนดค่าให้กับ image เท่านั้น

ถ้าหากเราลอง build อีกรอบนึงโดยที่ไม่ได้แก้โค้ดอะไรเลย จะสังเกตได้ว่าขั้นตอนที่ Docker แสดงให้ดูนั้นมีบางสิ่งเปลี่ยนไป

ในขั้นตอน [1/5] จะไม่ได้ดาวน์โหลดไฟล์มาใหม่จาก Docker repository เพราะว่ามี base image เก็บอยู่ในเครื่องของเราแล้ว


ส่วนขั้นตอนที่ 2 – 5 จะเห็นว่ามีคำว่า
CACHED อยู่ข้างหน้า ซึ่งหมายความว่าขั้นตอนเหล่านี้ Docker ไม่ได้ทำงานใหม่ แต่ว่าเรียกใช้ cache ที่มีอยู่มาแทน ซึ่งจุดนี้นี่แหละที่เราจะมาปรับให้ Dockerfile ของเราสามารถ build ได้เร็วขึ้น

 

การทำงานของ cache

ก่อนอื่นมาแวะดูการทำงานของ Docker build กันสักนิด ในการ build นั้น Docker จะมองคำสั่งแต่ละคำสั่งเป็น  layer โดยแต่ละ layer จะซ้อนทับต่อจากชั้นก่อนหน้าไปเรื่อยๆ อย่างใน Dockerfile ที่เราใช้อยู่ก็มี 5 layer


เรารู้แล้วว่า Docker มีการใช้ cache ในขั้นตอนของการสร้าง image ทีนี้เรามาจำลองการ build หลังจากที่โค้ดมีการเปลี่ยนแปลงกัน ในที่นี้จะเปลี่ยน 
background-color: #858694; เป็น background-color: yellow; ในไฟล์ src/component/Display.css ซึ่งจะทำให้ layer ที่ 3 ก็คือ COPY ./src /app/src มีการเปลี่ยนแปลงไป ในขั้นตอนนี้ Docker ก็จะไม่ได้ใช้ cache อีกต่อไป โดยผลลัพธ์น่าจะออกเป้นแบบด้านล่างนี้

แต่ว่าพอลอง build แล้วเราจะพบว่า Docker ไม่ได้ทำงานเหมือนรูปด้านบน

จะเห็นว่าขั้นตอนที่ 2 นั้นยังมาจาก cache อยู่ ส่วน 3 – 5 นั้นไม่ได้มาจาก cache 

สาเหตุที่เป็นแบบนี้มาจากการทำงานของ cache ที่มีเงื่อนไขก็คือ

  1. layer ก่อนๆต้องเหมือนเดิม โดยมองภาพรวมเป็นก้อนเดียว ไม่ใช่เพียงแค่ layer ที่อยู่ติดกัน หรือก็คือต้องไม่มีการเปลี่ยนแปลงใดๆเลยกับ layer ทุกชั้นก่อนหน้า

  2. layer นั้นๆต้องไม่เปลี่ยนแปลง

จากเงื่อนไขการใช้ cache นี้ทำให้การทำงานจริงๆ เป็นแบบด้านล่างก็คือ ถึงแม้จะเปลี่ยนเพียงแค่ layer 3 แต่ว่า 4 กับ 5 ก็ถือว่าถูกเปลี่ยนแปลงไปด้วย เนื่องจาก layer 3 มีการเปลี่ยนแปลงนั่นเอง

แค่สลับชีวิตก็เปลี่ยน

จากเรื่องการทำงานของ cache เราจะได้หลักการทำให้ Docker build เร็วที่สุดได้ด้วยการเรียงลำดับคำสั่งใหม่ โดยคำสั่งที่ไม่ค่อยเปลี่ยนแปลงก็ใส่ไว้เป็น layer แรกๆเท่าที่จะทำได้ เพื่อให้ Docker ใช้ cache ให้ได้มากที่สุด ทำให้ Dockerfile ของเราออกมาหน้าตาแบบด้านล่างนี้

FROM node:14-alpine
WORKDIR /app

COPY package.json ./
RUN npm install
COPY ./src /app/src

EXPOSE 3000
CMD [ "npm", "start" ]

โดยเราจะทำการ build หนึ่งรอบก่อนเพื่อให้ Docker ได้มี cache สำหรับ Dockerfile แบบใหม่

จากนั้นจะลองแก้โค้ดจุดเดิม คราวนี้เปลี่ยนเป็น background-color: red; แล้วก็ลอง build ดูอีกครั้งหนึ่ง

จะพบว่าตอนนี้ 2 – 4 นั้นเป็นการใช้ cache เรียบร้อยแล้ว มีเพียงคำสั่งที่ 5 เท่านั้นที่มีการเปลี่ยนแปลง

สรุปได้ว่า

เราสามารถเขียน Dockerfile โดยจัดเรียงคำสั่งต่างเพื่อทำให้ Docker ใช้ cache ได้อย่างมีประสิทธิภาพได้ ซึ่งอาจจะลดเวลาในการ build image ไปได้เยอะมากๆ

อย่างในวันนี้ Dockerfile เวอร์ชันแรก ใช้เวลาในการ build หลังจากมีการเลี่ยนแปลงโค้ด 88.8 วินาที แต่ในเวอร์ชันที่สองใช้เวลาเพียง 3.4 วินาที 

ที่เร็วขึ้นมากขนาดนี้ก็เพราะส่วนที่ใช้เวลานานที่สุดก็คือ npm install ซึ่งพอเราทำให้ Docker ใช้ cache ได้ ก็เลยไม่ต้องเสียเวลาในขั้นตอนนี้นั่นเอง 

สรุปของสรุปอีกทีก็คือเราต้องมีความเข้าใจขั้นตอนต่างๆใน Dockerfile ของเรา เพื่อที่จะเรียงลำดับคำสั่งให้ใช้ cache ได้อย่างมีประสิทธิภาพและยังคงทำงานได้ถูกต้อง ถ้าใครได้อ่านบทความนี้แล้วก็ลองกลับไปดู Dockerfile ของตัวเองกันได้ครับ หวังว่าทุกๆคนจะได้มีคุณภาพชีวิตที่ดีครับ 

 

ข้อมูลเพิ่มเติม

soranapoom.i

Author soranapoom.i

More posts by soranapoom.i

เราใช้คุกกี้เพื่อพัฒนาประสิทธิภาพ และประสบการณ์ที่ดีในการใช้เว็บไซต์ของคุณ คุณสามารถศึกษารายละเอียดได้ที่ นโยบายความเป็นส่วนตัว และสามารถจัดการความเป็นส่วนตัวเองได้ของคุณได้เองโดยคลิกที่ ตั้งค่า

ตั้งค่าความเป็นส่วนตัว

คุณสามารถเลือกการตั้งค่าคุกกี้โดยเปิด/ปิด คุกกี้ในแต่ละประเภทได้ตามความต้องการ ยกเว้น คุกกี้ที่จำเป็น

ยอมรับทั้งหมด
จัดการความเป็นส่วนตัว
  • คุกกี้ที่จำเป็น
    เปิดใช้งานตลอด

    ประเภทของคุกกี้มีความจำเป็นสำหรับการทำงานของเว็บไซต์ เพื่อให้คุณสามารถใช้ได้อย่างเป็นปกติ และเข้าชมเว็บไซต์ คุณไม่สามารถปิดการทำงานของคุกกี้นี้ในระบบเว็บไซต์ของเราได้
    รายละเอียดคุกกี้

  • คุกกี้สำหรับการติดตามทางการตลาด

    ประเภทของคุกกี้ที่มีความจำเป็นในการใช้งานเพื่อการวิเคราะห์ และ นำเสนอโปรโมชัน สินค้า รวมถึงหลักสูตรฟรี และ สิทธิพิเศษต่าง ๆ คุณสามารถเลือกปิดคุกกี้ประเภทนี้ได้โดยไม่ส่งผลต่อการทำงานหลัก เว้นแต่การนำเสนอโปรโมชันที่อาจไม่ตรงกับความต้องการ
    รายละเอียดคุกกี้

บันทึกการตั้งค่า