Dockerize ứng dụng VueJS, ReactJS

Tram Ho

Tiền Setup

Nhớ check là các bạn đã cài Docker và Docker-compose rồi nhé. Nếu chưa thì nhớ check lại phần cuối bài trước của mình để biết cách cài đặt nhé.

Setup

Các bạn clone source code ở đây nhé

Ở bài này ta sẽ chỉ cần quan tâm tới 2 folder trong source code bên trên đó là docker-vuedocker-react nhé

Ở 2 thư mục đó với tên tương ứng mình đã tạo sẵn cho các bạn 1 project VueJS và một project ReactJS

Dockerize Project VueJS

Đầu tiên chúng ta sẽ tiến hành dockerize project VueJS nhé

Build Image

Và vẫn như các bài trước để dockerize một project trước hết chúng ta cần phải cấu hình Dockerfile để định nghĩa Image với môi trường và những thứ cần thiết cho project

Cấu hình Dockerfile

Ở folder docker-vue các bạn tạo file tên là Dockerfile với nội dung như sau:

Ồ bài này sao lại có 2 cái FROM vậy nhỉ?

Như ở bài dockerize ứng dụng NodeJS phần những câu hỏi liên quan mình cũng đã giải thích là chúng ta có thể FROM nhiều lần trong 1 file Dockerfile nhé.

Thế tại sao bài này lại có. Bắt nguồn từ điều này: đối với project Vue hoặc React là dạng full frontend, không có tí backend nào, chúng chỉ được chạy trên trình duyệt. Mà khi ra tới trình duyệt, thì thứ trình duyệt hiểu chỉ là HTML, CSS, JS.

Do đó để Dockerize ứng dụng Vue/React việc của ta là chỉ cần lấy được những file build cuối cùng cần thiết để chạy ở trình duyệt còn những thứ khác có hay không có, không quan trọng 😄, làm như thế thì Image của chúng ta sẽ giảm được size xuống, giảm thiểu tối đa những thứ không cần thiết bên trong Image

Mình sẽ cùng nhau phân tích file Dockerfile trên để thấy những điều mình huyên thuyên bên trên nó là thế nào nhé 😉:

  • Ở file Dockerfile chúng ta chia làm 2 stage (giai đoạn) khi build image: build stageproduction stage
  • build stage ta bắt đầu từ image tên là node:13-alpine, nếu các bạn không biết nó là gì thì đọc bài dockerize ứng dụng NodeJS của mình nhé. Để đặt tên cho từng giai đoạn ta dùng từ khoá as nhé 😉
  • Trong build stage ta bắt đầu từ đường dẫn /app, sau đó copy toàn bộ file ở folder hiện tại ở môi trường ngoài, tức folder docker-vue vào bên trong đường dẫn ta set ở WORKDIR tức /app bên trong image.
  • Tiếp theo ta chạy npm install như thường lệ để cài dependencies và cuối cùng là build project
  • Ok build xong giờ tiến tới production stage: nơi ta định nghĩa cách chạy project
  • production stage ta bắt đầu với image tên là nginx…. đặt tên stage này là production-stage với từ khoá as
  • Thế nginx ở đây là cái gì thế ???? Project VueJS hay ReactJS khi chạy sẽ cần một webserver để có thể chạy được nó, và Nginx ở đây chính là webserver. Ở local có cần Nginx gì đâu nhỉ? Vì ở local khi chạy npm run dev thì các nhà phát triển VueJS đã thiết lập sẵn cho chúng ta 1 local webserver rồi nhé, nhưng khi chạy thật thì không nên dùng nhé, phải có 1 webserver xịn, và Nginx thì rất là xịn nhé 😄😄
  • Sau đó, phần này quan trọng nè, ta COPY từ build-stage lấy folder ở đường dẫn app/dist chính là “những file build cuối cùng cần thiết để chạy ở trình duyệt”, ta lấy folder đó và copy vào đường dẫn /usr/share/nginx/html, đây chính là nơi Nginx sẽ tìm tới và trả về cho user khi user truy cập ở trình duyệt
  • Và cuối cùng ta có CMD khởi động Nginx

Bài này có sự xuất hiện thêm của đối tượng lạ tên là Nginx có thể sẽ làm cho các bạn khó hiểu ngay từ bước đầu, nhưng “take it easy”, cứ bình tĩnh và tạm coi nó là “1 anh bạn nào đó” cần thiết để làm nhiệm vụ phục vụ VueJS đến user, vì tự bản thân Vue không “show hàng” cho user xem được nhé 😉

Build Image

Và để build image thì vẫn như một cái thường lệ từ các bài trước 😄, ta chạy command sau:

Nếu các bạn có thắc mắc command trên làm gì thì xem lại các bài trước trong series này nhé

Chạy project

Để chạy project ta lại “rất như thường lệ các bài trước” lại tại một file tên là docker-compose.yml với nội dung như sau:

Những thứ bên trên cũng được mình đã giải thích ở các bài trước rồi nhé các bạn 😉, Lại “rất như thường lệ” nếu các bạn không hiểu thì các bạn xem lại các bài trước nhé 😄😄

“TỪ! Ở trên 80 lấy ở đâu ra vậy anh zai viết blog hê”

Thì mặc định của Nginx khi bạn ý chạy thì bạn ý sẽ lắng nghe ở cổng 80 nhé các bạn 😉 , dù trong Dockerfile ta không có, cái đó được setup ở trong Nginx rồi nhé ta chưa cần quan tâm.

Cuối cùng là chạy project lên thôi nào. Lại “rất như thườ…..” (thôi không nói nữa), ta chạy command sau:

Sau đó mở trình duyệt ở địa chỉ localhost:5000 và xem nhé:

Docker vue

Cho bạn nào xem luôn bài này và không hiểu cổng 80 và 5000 nó là cái gì thì các bạn nên xem các bài trước trong series này nhé 😉

Dockerize project ReactJS

Với project ReactJS thì sự giống nhau là 96,69% so với VueJS nhé, điều duy nhất khác biệt đó là React khi build sinh ra project tên là build chứ không phải dist như Vue, nên file Dockerfile nom sẽ như sau nhé:

Phần này các bạn thử tự làm và xem kết quả có ra được ngon lành như Vue không nhé 😉

Có cách nào để không phải chia Dockerfile thành 2 stage?

Thì câu trả lời là có, về sau khi mình hiểu được cách này thì mình toàn dùng cách này cả 😄.

Bắt đầu thôi nào….👏👏

Trước hết ta sẽ cần lắc não một chút:

  • Như ở trên mục đích của chúng ta là cần phải build được project, sau đó lấy “những file build cuối cùng” tức là lấy được folder dist ở Vue hoặc build ở bên React và gửi nó tới Nginx và bảo “Nginx cậu show hàng hộ tớ nếu có user hỏi thăm đến tớ” 😂😂
  • Vậy vấn đề ở đây là làm cách nào có thể build được project mà không cần dùng thêm một stage như ở Dockfile, sau đó chuyển nó tới cho anh bạn thân Nginx là ok rồi 😉

Setup

Docker hỗ trợ chúng ta có thể tạo ra một “container tạm thời” (intermediate container, từ này dịch ra phải là trung gian mới đúng như nghe nó không hay 😄).

Container này sau khi làm xong nhiệm vụ thì sẽ tự được xoá đi.

Ta sẽ dùng container này để build project nhé 😉

Bắt đầu thôi nào…

Trước hết các bạn tắt project nếu đang chạy bằng docker-compose đi nhé:

Vẫn ở folder docker-vue chạy command sau:

Giải thích nè:

  • Ở câu lệnh trên ta chạy câu lệnh docker tạo ra 1 container với option –rm ý bảo “chạy xong chú tự xoá đi nhé”
  • Tiếp theo ta có option -v tức là volume, ồ volume là gì mới à nha. Ở bài đầu tiên mình đã nói tới rồi nhé, các bạn cứ bình tĩnh dần dần ta sẽ học nó nhiều hơn
  • Sau -v$(pwd):/app, ở đây ý ta bảo là đưa toàn bộ file ở folder hiện tại ở môi trường gốc ánh xạ vào trong đường dẫn /app trong Image ( $(pwd) trả về đường dẫn hiện tại) , việc này gọi đúng thuật ngữ thì là mount
  • Tiếp theo ta có option -w chính là WORKDIR nhé
  • Tiếp theo ta có node:13-alpine: tương đương với FROM:node:13-alpine
  • Sau đó là các command ta cần chạy để build project.

Các bạn chạy command trên nhé, có thể 1 lúc không thấy terminal in ra gì, đừng hoang mang nhé, 1 chút thôi là in ra cả một đống log đó 😄

Sau khi command trên chạy thành công thì các bạn sẽ thấy ở folder docker-vue xuất hiện cả folder node_modules và folder dist. Đây chính là điều mà volume trong Docker mang lại.

Volume giúp ánh xạ file ở môi trường ngoài vào trong Docker container, và ánh xạ này là ánh xạ 2 chiều, ngoài thay đổi thì trong thay đổi, trong thay đổi thì ngoài thay đổi theo. Đó là lí do vì sao khi command trên chạy xong ở bên ngoài ta lại có kết quả như vậy. Dần dần các bạn sẽ hiểu volume nó là gì nhé 😉

Ok vậy là giờ ta đã có folder dist rồi, nhiệm vụ tiếp theo là gửi nó tới nginx.

Các bạn sửa lại file docker-compose.yml như sau:

Ở trên ta đã thay tên image bằng tên của image của Nginx, đồng thời ta dùng từ khoá volumes để ánh xạ nội dung bên trong folder dist vào trong folder /usr/share/nginx/html nơi Nginx cần. (nhớ là nội dung bên trong dist chứ không có folder dist đâu nhé)

Các bạn chú ý trong docker khi ta ánh xạ (hay gọi chính xác là mapping dùng cho port hay mount dùng cho volume), biêủ thức sẽ chia làm 2 vế thì vế trái luôn là ở môi trường gốc (bên ngoài), vế phải là bên trong container nhé

Và chú ý là khi ánh xạ volumes thì vế bên phải (nơi container) đường dẫn phải là đường dẫn tuyệt đối nhé.

Cuối cùng là ta chạy lại project xem sao nào:

Các bạn mở trình duyệt và sẽ lại thấy điều tương tự như trước đó ta đã thấy nhé 😄

Ta thử chui vào container xem có gì nhé, các bạn mở terminal khác tại folder docker-vue và chạy command sau:

Và các bạn sẽ thấy như sau
Docker

Review

Tại sao với Vue hay React mình lại chọn cách này??

Các bạn để ý thấy là cuối cùng ở file docker-compose khi chạy ta dùng image nginx là image đã được build sẵn, chứ không còn dùng image learning-docker:vue nữa. Mà image learning-docker:vue cần phải build mới có thể dùng được. Do đó mỗi khi code Vue của ta thay đổi thì ta cần build lại Image. Tức là ta không cần dùng đến file Dockerfile nữa 😉

Còn bây giờ dùng cách này ta không cần build lại image nữa. Chạy npm install thì hiển nhiên dù có hay không có Docker ta vẫn phải chạy để cài dependencies rồi, chạy npm run build thì cũng là hiển nhiên phải chạy để build project dù có hay không có Docker rồi. Điều khác biệt chút chút là giờ ta chạy nó với command:

Và cuối cùng là khởi động project được luôn


KHÔNGGGGGGG 😭😭, dùng cách này tự nhiên ở môi trường gốc bên ngoài của tôi lại có node_modulesdist, nó làm môi trường gốc của tôi không còn “trinh trắng” nữa. Cái gì bên trong Docker thì hay cứ ở bên trong đó đi…

Nếu việc ta mount từ folder bên ngoài vào trong container làm bên ngoài xuất hiện thêm nhiều file làm các bạn thấy không muốn thì các bạn có thể quay lại cách build Image với 2 stages như đầu bài ta đã làm.

Các bạn tuỳ chọn cách làm mà các bạn thấy thích hợp nhất nhé.

Nhưng các bạn ạ, cái gì “trong trắng” quá chưa hẳn tốt, vì thế mà có một số bộ phận thanh niên hiện nay có khẩu vị mặn đó là “fall in love” với các chị hơn tuổi từng trải 😂😂

Lúc nào cũng dùng cách này có được không?

Thì cách này theo mình thấy dùng được cho các project khi chạy hoặc build không cần cấu hình nhiều, các project chuyên về frontend, không dính dáng tí backend nào, kiểu react, vue, angular, ember,… đều chơi được

Còn các project có backend thì thường ta sẽ cần setup nhiều bước và nhiều thứ lằng nhằng nên cách này sẽ khó đáp ứng được

Kết bài

May quá cũng viết được một bài tạm gọi là đỡ dài dòng 😂😂

Ở bài này các bạn đã biết được cách để dockerize project VueJS và ReactJS như thế nào, và cách làm cũng rất là tương tự với những project “chuyên” frontend khác. Các bạn có thể tìm một project nào đó (Angular chẳng hạn) và thử dockerize xem nhé 😉

Qua bài này có một số nội dung quan trong như sau:

  • Cách chia quá trình build Image thành nhiều giai đoạn (stage) và cách COPY các tài nguyên giữa các stage đó
  • Cách khởi tạo “container tạm thời” để thực hiện một số tác vụ cần ít thao tác cấu hình
  • Cơ bản chút chút về volumes để mount (ánh xạ) tài nguyên giữa môi trường gốc (bên ngoài) vào bên trong container
  • Cùng với đó là chút chút về Nginx là gì, sau này ta sẽ dùng Nginx làm webserver/proxy khá là nhiều đó nhé 😉

Cám ơn các bạn đã theo dõi series của mình, nếu có gì thắc mắc các bạn cứ comment cho mình biết nhé.

Source code bài này mình để ở đây (nhánh complete-tutorial nhé)

Hẹn gặp lại các bạn ở các bài sau ^^

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo