DEV Community

Cover image for สร้าง Docker Image ลีนๆ ด้วย Multi-stage Builds
mixth for Zarewoft

Posted on

1 3

สร้าง Docker Image ลีนๆ ด้วย Multi-stage Builds

Firstly published on 2018-01-18 in Medium.

สวัสดีครับ 😀
บล็อกนี้เป็นบล็อกแรกสำหรับเรื่อง Docker เลยครับ โดยผมตั้งใจว่าจะมาเล่าผลลัพธ์จากประสบการณ์การฝึกใช้งาน Docker ทั้งเรื่องง่ายๆ เรื่องที่เสียเวลา เรื่องที่เจ็บมาเยอะๆ ให้ทุกท่านอ่านกันครับ


"ขนาดไม่ใช่เรื่องสำคัญ" คงไม่จริงแน่ๆ สำหรับการใช้งาน Docker เพราะเมื่อขนาดใหญ่ขึ้น เราก็เสียค่า storage สำหรับเก็บ image ใน registry มากขึ้น ตอนรัน container ก็ต้องใช้ disk ของเครื่อง host มากขึ้นอีก

การลดขนาดของ docker image มีหลากหลาย practice ที่เราควรทำครับ เช่น การไม่พยายามสร้าง layer ใหม่ที่ไม่จำเป็นด้วย RUN, การจัดวาง sequence ของ command ใน Dockerfile
วันนี้ผมจะพาท่านๆมารู้จักกับ multi-stage builds ซึ่งผมได้ความรู้มาจากการลองผิดลองถูก อ่านบทความต่างๆ แล้วทดลองใช้กับงานจริงครับ

Multi-stage Builds

ผมมักชอบที่จะรัน test และ build บน docker เลย เพื่อการันตีว่าแอพผ่านการ test ก่อนจะ build บน environment ที่เหมือนกันครับ แต่ในบางครั้งการ build บน docker ก็ทำให้มี file ที่ไม่จำเป็นมากมายเกิดขึ้นใน image เรา ถ้าเราเอาตัวนี้ไปใช้จริงก็คงจะเป็น image ที่หนาเกินไป

ยกตัวอย่างเช่น build gulp สำหรับ frontend แอพ ถ้าเอาแบบเอี่ยมๆเลย เราก็ต้องใช้ FROM node แล้วมา npm install แล้วค่อยใช้ gulp อีกที

ซึ่งมันไม่จำเป็นมากๆเลยที่จะเอาทั้งหมดนี้ไปไว้ใน image ใช่ไหมครับ เพราะสุดท้ายแล้วเราแค่จะ serve static file เอง มันคงจะดีไม่น้อย ถ้าเราใช้ image หนึ่งอันมารันทั้งหมดนี้ แล้วเอาผลลัพธ์ไปใส่อีก image ใช่มะ?

Multi-stage builds คือ concept แบบที่เราว่าเลยครับ กล่าวคือ การสร้าง stage นึง แล้วใช้เป็นแค่ทางผ่านแล้วเอาไฟล์ไปใช้อีก stage นึงครับ

วิธีการใช้งาน

ระบุ name ให้กับ image ที่เราสร้างในกระบวนการในบรรทัด FROM

FROM <IMAGE> AS <NAME>
Enter fullscreen mode Exit fullscreen mode

เวลาเราจะ COPY file จาก stage เดิม ให้ใส่ parameter ชื่อ from เพิ่มเข้าไป

COPY --from=<NAME> <ORIGIN_PATH> <DEST_PATH>
Enter fullscreen mode Exit fullscreen mode
# Using node as intermediate to build
FROM node:8.9.3 as build-image
LABEL maintainer Narat S <narat.s@hbot.io>
WORKDIR /home/node/app
COPY . ./
RUN npm install
RUN npm run build
# Using nginx as a final image to run app
FROM nginx:1.13.7-alpine
WORKDIR /usr/share/nginx/html
COPY --from=build-image /home/node/app/public .
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
view raw Dockerfile hosted with ❤ by GitHub
ตัวอย่าง multi-stages builds โดยการ npm install, run build แอพ ก่อนจะสร้าง image nginx สำหรับ serve

ในตัวอย่างข้างต้นคือเราใช้ image node มา build app เสร็จแล้ว serve ด้วย nginx ครับ ถ้าอยาก validate ดูว่าถูกต้องไหม ลองสั่ง docker history <IMAGE_HASH> ดูได้ครับ
แต่หากเราไม่อยากตั้งชื่อให้มันจริงๆ ก็ใส่เป็น index ก็ได้นะ (0, 1, 2, …) โดยเรียงจาก FROM ด้านบนสุดมาเรื่อยๆครับ (แต่… มันตั้งชื่อได้ก็ตั้งให้มันเถิด)

# This will be referred as 0
FROM <NAME>
...
# This will be referred as 1
FROM <NAME>
...
FROM <NAME>
COPY --from=0 /home/node/app .
view raw Dockerfile hosted with ❤ by GitHub

ลองดูนะครับว่าเราสามารถใช้เทคนิคนี้ในการทำให้ image ของเราเล็กลง หรือใช้งานได้สะดวกขึ้นอย่างไงบ้าง

หากมีส่วนใดผิดพลาด ไม่ถูกต้อง แจ้งได้เลยครับ :)

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

DEV is better (more customized, reading settings like dark mode etc) when you're signed in!

Okay