เรียนรู้ multi-stage docker ด้วยการ deploy react ขึ้น production กันเถอะ
หลังจากที่อู้จากการเขียน blog ภาคต่อของ มาจับ React ยัดใส่ Container กันเถอะ! มาเป็นเวลาก็ถึงเวลาอันสมควรแล้วที่จะพา react ของเราขึ้นสู่โปรดัคชั่น อย่างง่าย ๆ ด้วยการทำ multi-stage docker ว่าแต่ multi-stage docker นี่มันคืออะไรกันนะ?
Multi-stage build คืออะไร และมีประโยชน์อย่างไร?
เรื่องที่จัดการยากสุด ๆ สำหรับการ docker นั้นคือเรื่องขนาด docker images ซึ่งในกรณีของ react นั้นสามารถมี images ขนาดใหญ่ถึง 1 GB ถ้าหากบอกว่าสามรถทำให้ขนาด images ขนาดเหลือเพียง 15 MB ได้จะเชื่อกันหรือเปล่า!
โดยเราสามารถลดขนาดของ docker images ให้เหลือเพียง 15 MB ได้โดยการใช้ multi-stage build ไงล่ะ แล้วการทำ multi-stage build คืออะไรล่ะ อธิบายอย่างง่าย ๆ คือการที่เรานำสิ่งของที่ถูกสร้างบางส่วนจาก images ที่หนึ่งไปใส่ในอีก images หนึ่งนั่นเองถ้าถึงตรงนี้แล้วยังไม่ค่อยเข้าใจ ไม่เป็นไรเดี๋ยวพาไปลุยของจริงกันเลยดีกว่า
เตรียมตัวก่อนทำ Multi-stage build docker
- Create React App
- Docker CE 17.05+
ทำการติดตั้ง create-react-app
$ npm install -g create-react-app
ทำการติดตั้ง Docker ซึ่งขั้นตอนของแต่ละ OS มีความแตกต่างกัน แนะนำให้ศึกษาขั้นตอนการติดตั้งผ่านลิงค์ข้างล่าง
มาเริ่มทำ Multi-stage build กันเลย!
หลังจากติดตั้งทุกอย่างสำเร็จแล้วก็ทำการ generate react project ขึ้นมา
$ create-react-app react-multistage
$ cd react-multistage
หลังจากนั้นทำการสร้าง Dockerfile
ขึ้นมาภายในโปรเจคแล้วใส่ instruction ตาม code ด้านล่าง
# Dockerfile
# 1st Stage
FROM node:10.15.1 AS builderRUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json .
COPY yarn.lock .
RUN yarn install --ignore-platform
COPY . .
RUN yarn build# 2nd Stage
FROM nginx:1.14.2-alpineCOPY --from=0 /usr/src/app/build /usr/share/nginx/html
WORKDIR /usr/share/nginx/htmlCMD ["nginx", "-g", "daemon off;"]
จากนั้นทำการ build images ด้วยคำสั่ง
$ docker build -f Dockerfile -t react-multistage:latest .
จาก Dockerfile เบื้องต้นนั้นสามารถอ่าน instruction คร่าว ๆ ได้ดังนี้
- ขั้นที่ 1 — สร้าง production build ของ react เก็บไว้ที่
/usr/src/app/build
ของ image แรก - ขั้นที่ 2 — คัดลอกเพียง production build จาก image แรกไปไว้ใน folder
/usr/share/nginx/html
ของ image ที่สองซึ่ง image ที่สองนั้นคือ nginx ซึ่งทำหน้าที่ในการเสิร์ฟ production build
หลังจากนั้นเราก็จะได้ docker image ที่เก็บเพียงแค่ production build ไม่มี code และ node modules ของโปรเจคเราอยู่เลย ทำให้มีความโล่งมาก ๆ
ทดสอบด้วยการใช้ docker run ว่าสามารถเปิดใช้งาน docker images นั้นได้จริงไหม ด้วยคำสั่งด้านล่างเพื่อเปิด port 80 หรือ HTTP
$ docker run --rm -p 80:80 react-multistage:latest
ผลลัพธ์:
สรุป
- multi-stage build นั้นช่วยลดขนาดของ image สุดท้ายได้อย่างมหาศาล
- ในกรณีของภาษาที่ compiled เป็น binary เช่น golang สามารถคัดลอก binary ไปเพื่อใช้รันบน image เปล่า ๆ ได้ ทำให้ code ก่อน compile นั้นไม่ถูกเก็บบน docker image แน่นอนว่าแปลว่า code ไม่หลุดแน่ๆ
- ลดจำนวนของ Dockerfile ภายใน project ขนาดใหญ่ ๆ ได้โดยสามารถเลือก build แต่ละ stage เพื่อใช้งานได้ ไม่จำเป็นต้อง build ทั้งหมด
ขอจบเพียงเท่านี้
Happy coding ❤
ศึกษาเพิ่มเติม code ได้ที่ React Multistage Docker Github Repository