การ run Node JS ด้วย Docker
ตัวอย่างนี้จะพาไปดูขั้นตอนการนำ NodeJs Application เข้าไป run ใน docker ในตัวอย่างนี้เราจะนำตัวอย่าง To-Do Application ที่อยู่ใน image ชื่อว่า getting-start ของ docker โดยที่ขั้นตอนการทำงานกับ docker มีดังนี้
- Download To-Do application
- Build container image
- Start application container
- Update application ต้อง re-build image ใหม่
- Bind mounts volume
1. Download To-Do Application
อันดับแรกเราจะนำตัวอย่าง clone source code ด้วยคำสั่งนี้
git clone https://github.com/irobust/Sample-Todo-Application
หลังจากที่เราได้ source code มาแล้วนเราจะได้โครงสร้างของไฟล์แบบนี้
├── Sample-Todo-Application
│ ├── package.json
│ ├── src
│ | ├── ...
│ | ├── index.js
│ ├── spec
│ | ├── ...
2. Build container image
ขั้นตอนต่อไปคือการสร้าง Dockerfile เพื่อทำงานกับ NodeJs Application แบบนี้
- เลือก base image เป็น node:21-alpine ให้เปลี่ยนเป็น version ล่าสุด ณ ตอนที่คุณสร้างไฟล์นี้
FROM node:21-alpine
- การกำหนด WORKDIR คือการกำหนดให้ command ที่จะถูก run ทั้งหมดหลังจากนี้เกิดขึ้นใน folder /app
WORKDIR /app
- Copy source code ใน folder ปัจจุบัน(Sample-Todo-Application) เข้าไปใน image (ในขั้นตอนนี้อาจเลือก Bind Mounts แทนได้)
COPY . .
- ติดตั้ง package ที่จำเป็นต้องใช้ในการทำงานด้วยการ run yarn install คุณอาจใช้ npm install แทนก็ได้
RUN yarn install --production
- เปิด port 3000 และใช้ tcp protocol
EXPOSE 3000
- หลังจากนั้นก็ start todo application ด้วยการ run command node index.js
CMD ["node", "src/index.js"]
สุดท้ายเราจะได้ Dockerfile หน้าตาแบบนี้
FROM node:21-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
EXPOSE 3000
CMD ["node", "src/index.js"]
และ Dockerfile จะอยู่ใน path เดียวกับ package.json แบบนี้
├── Sample-Todo-Application
│ ├── Dockerfile
│ ├── package.json
│ ├── src
│ ├── spec
สุดท้ายให้สั่ง build image ด้วยคำสั่ง
docker build -t todo-app:1.0 .
3. Start application container
หลังจากที่เราได้ container image มาแล้วต่อไปให้นำ image นั้นมาสร้างเป็น container ด้วยคำสั่ง
docker run -d -p 3000:3000 todo-app:1.0
เราใส่ -d เข้าไปเพื่อให้ run container ใน detach mode หลังจากนั้นให้เข้าไปยังหน้าแรกของ application ที่ http://localhost:3000 เราจะได้ to-do application หน้าตาแบบนี้
หลังจากที่เราลอง add item เข้าไปจะเป็นดังรูป
4. Update application
ถ้าเราต้องการ update application ใหม่สิ่งที่เราต้องทำตือลบ image ตัวเก่าออกแล้ว pack ตัวใหม่ใส่เข้าไปแทน โดยจะมีขั้นตอนต่างๆ ดังนี้
- แก้ไข source code บรรทัดที่ 56 ในไฟล์ src/static/js/app.js ให้เป็นข้อความนี้
<p className="text-center">You have no todo items yet! Add one above!</p>
- ทำการ build image ตัวใหม่ (COPY code ชุดใหม่เข้าไปใส่ใน container image)
docker build -t todo-app:1.1 .
ถ้าต้องการให้ build image ใหม่ทั้งหมดโดยไม่ใช้ ข้อมูลจากใน cache เดิมเลยคือ
docker build --no-cache -t todo-app:1.1 .
- ถ้าคุณสั่ง docker run เลยเราจะเจอ error แบบนี้
docker: Error response from daemon: driver failed programming external connectivity on endpoint laughing_burnell (bb242b2ca4d67eba76e79474fb36bb5125708ebdabd7f45c8eaf16caaabde9dd): Bind for 0.0.0.0:3000 failed: port is already allocated.
เนื่องจากถ้าเรายัง run container ตัวเก่าค้างอยู่ port 3000 จะใช้งานไม่ได้เราต้องลบ container ตัวเก่าออกก่อน
docker ps
เราต้องสั่ง docker ps เพื่อนำค่าของ container id มาใส่ใน docker rm
docker rm -f [container-id]
- run container ใหม่ได้แล้ว
docker run -dp 3000:3000 todo-app:1.1
5. Bind mounts volume
เนื่องจากตอนนี้เราใช้ sqlite เป็น database และจัดเก็บไฟล์ไว้ใน path /etc/todos/todo.db ซึ่ง path นี้ถูกเก็บไว้ใน container นั่นหมายความว่าถ้าเราลบ container ออก ไฟล์ todo.db ก็จะหายไปด้วย ในการแก้ไขปัญหานี้เราจะต้องสร้าง volume และ mount เข้าไปใน container ด้วยขั้นตอนนี้
- สร้าง docker volume ใหม่ขึ่้นมา เราตั้งชื่อว่า todo-db
docker volume create todo-db
- Stop to-do application container
docker stop [container-id]
# หรือ
docker rm -f [container-id]
- run container ขึ้นมาใหม่ด้วยคำสั่ง run โดยเพิ่ม -v todo:/etc/todos หมายความว่าเราจะ mount volume ชื่อว่า todo-db เข้าไปใน path /etc/todos
docker run -dp 3000:3000 -v todo-db:/etc/todos todo-app:1.1
- ทดสอบลบ container ออกด้วยคำสั่ง
docker rm -f [container-id]
หลังจากนั้น run คำสั่ง docker run อีกครั้ง
docker run -dp 3000:3000 -v todo-db:/etc/todos todo-app:1.1
-
เข้าไปใน http://localhost:3000 ควรจะมี item ที่เราได้ add ไว้ก่อนจะลบ image ยังคงอยู่ในหน้าจอเหมือนเดิม เพราะ docker rm จะลบเฉพาะ container ไม่ได้ลบ volume
-
เข้าไปดูว่าจริงๆแล้ว file todo.db ถูกเก็บอยู่ที่ไหน
docker volume inspect todo-db
หลังจาก inspect เข้าไปใน volume เราจะพบที่อยู่ของ path โดยดูที่ Mountpoint
|
|