การตั้งค่า dockerfile และ docker-compose เพื่อรัน Node.js และ MongoDB บน Docker Container

Docker Apr 10, 2023

ในบทความนี้ จะบันทึกวิธีการตั้งค่า dockerfile และ docker-compose เพื่อทดสอบและฝึกใช้งาน Docker และต่อยอดเป็น Microservices ในอนาคต ซึ่งผมเห็นว่า มีความน่าสนใจที่จะเอามาแบ่งปันประสบการณ์ตรงนี้ให้ทุกคนได้อ่านกันครับ

ในกรณีนี้ เราจะไม่ใช้ Node.js เป็น Runtime บนเครื่องของตัวเองเลย รวมถึง MongoDB ด้วย ทุกอย่างจะทำงานผ่าน Docker เท่านั้น จุดประสงค์ต้องการทดสอบการรันทุก Server โดยใช้ Docker Container

ตั้งค่าโปรเจ็กต์

ในโปรเจ็กต์ตัวอย่าง เรามีการสร้าง APIs เพื่อใช้งานเกี่ยวกับ ระบบจอดรถ ขอตั้งชื่อโปรเจ็กต์ว่า parking-lot-backend-app ละกันนะฮะ

ภายในโปรเจ็กต์ มีการตั้งค่าภายในไฟล์ .env เกี่ยวกับ MongoDB ดังนี้

DB_HOST=mongo
DB_PORT=27017
DB_NAME=<DB_NAME>
DB_USER=<DB_USERNAME>
DB_PASS=<DB_PASSWORD>

ต่อมา เริ่มสร้าง dockerfile กันก่อนดีกว่า

FROM node:12
# FROM เอาไว้เลือก Base Image จาก Docker Hub ที่ต้องการใช้เป็นสภาพแวดล้อม

LABEL maintainer="admin"

LABEL description="This dockerfile for install the parking-lot-backend."

WORKDIR /app
# WORKDIR คิือการกำหนด directory ของการทำงาน 
# เพื่อให้คำสั่งอื่นๆของ Docker ไปทำงานที่นั่น ซึ่งในที่นี้เป็น /app

COPY package.json ./
# คัดลอก package.json ไปใส่ที่ ./

COPY package-lock.json ./
# คัดลอก package-lock.json ไปใส่ที่ ./

RUN npm install
# ในที่นี้ คือ จาก ./ ไปหา ./

COPY ./ ./
# COPY คือคำสั่งที่คัดลอกโค้ดจาก directory ต้นทาง ไปหา ปลายทาง 
# ในที่นี้ คือ จาก ./ ไปหา ./

ENV NODE_ENV production

CMD ["npm", "run", "dev"]
# CMD คีอ การใส่คำสั่งเพื่อรันโปรแกรม จากตัวอย่างคือ คำสั่ง "npm run dev"

ลักษณะการเขียน Dockerfile จะเป็นการเขียนเพื่อเรียงลำดับการทำงานแบบบนลงล่าง รายละเอียดเพิ่มเติมศึกษาได้ที่นี่

สร้าง docker-compose.yml ขึ้นมา โดยมีรายละเอียดดังนี้

version: '3'
services:
  app:
    container_name: parking-lot
    restart: always
    build: .
    ports:
      - '80:3000'
    external_links: 
      - mongo
  mongo: 
    container_name: mongo
    image: mongo
    ports: 
    - '27017:27017'

จากในไฟล์ Docker Compose นี้ มีการกำหนดค่าต่างๆดังนี้
- version ของ Compose file format
- services คือ การประกาศ service ที่จะรันทั้งหมด
- container-name คือ การกำหนดชื่อ container ของแต่ละ service
- image คือชื่อของ Docker Image ที่จะใช้
- ports คือการกำหนด port โดยกำหนดแบบ <external_of_container>:<internal_of_container>
- external_links คือการกำหนด ว่า app จะทำงานร่วมกันกับ container ชื่ออะไร ถ้า container นั้นอยู่ใน Compose เดียวกัน คำสั่งนี้จะถูก ignore ไป

ในกรณีนี้ เราจะมี Service อยู่ 2 ตัว คือ parking-lot และ mongo ซึ่งจะเป็น server ให้กับ MongoDB ทำหน้าที่เป็นฐานข้อมูลของ app

Start Container

มาเช็ค Container ที่มีอยู่ในเครื่องก่อนทำการสร้าง ด้วย docker-compose

docker ps -a

ดูว่าไม่มี Container

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

จากนั้น เราทำการสร้าง Container โดยใช้คำสั่งนี้ที่ directory path ของโปรเจ็กต์

docker-compose up

เราจะได้ Result ออกมาเป็นแบบนี้

[+] Running 2/2
 ⠿ Container mongo        Created                                                                                     0.1s
 ⠿ Container parking-lot  Created                                                                                     0.1s
Attaching to mongo, parking-lot
parking-lot  |
parking-lot  | > [email protected] dev /app
parking-lot  | > nodemon ./bin/www
parking-lot  |
parking-lot  | [nodemon] 2.0.21
parking-lot  | [nodemon] to restart at any time, enter `rs`
parking-lot  | [nodemon] watching path(s): *.*
parking-lot  | [nodemon] watching extensions: js,mjs,json
parking-lot  | [nodemon] starting `node ./bin/www`
mongo        | {"t":{"$date":"2023-04-09T10:07:55.820+00:00"},"s":"I",  "c":"CONTROL",  "id":23285,   "ctx":"-","msg":"Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'"}
mongo        | {"t":{"$date":"2023-04-09T10:07:55.821+00:00"},"s":"I",  "c":"NETWORK",  "id":4915701, "ctx":"-","msg":"Initialized wire specification","attr":{"spec":{"incomingExternalClient":{"minWireVersion":0,"maxWireVersion":17},"incomingInternalClient":{"minWireVersion":0,"maxWireVersion":17},"outgoing":{"minWireVersion":6,"maxWireVersion":17},"isInternalClient":true}}}

เราจะเห็นว่า Container ของโปรเจ็กต์และของ mongo image ทำงานได้แล้วเรียบร้อย

ลองเช็ค Container อีกรอบ

CONTAINER ID   IMAGE                     COMMAND                  CREATED          STATUS          PORTS                      NAMES
be6b3a88e153   parking-lot-backend-app   "docker-entrypoint.s…"   20 seconds ago   Up 19 seconds   0.0.0.0:80->3000/tcp       parking-lot
244faa10158d   mongo                     "docker-entrypoint.s…"   20 seconds ago   Up 19 seconds   0.0.0.0:27017->27017/tcp   mongo

เราจะเห็นว่า ชื่อ Container ของโปรเจ็กต์จะมีชื่อตามที่เราตั้งใน docker-compose ไฟล์ ส่วน Image จะเหมือนกับชื่อ Directory

หลังจากนี้ เราสามารถรันโปรเจ็กต์ได้แล้ว และข้อมูลที่สร้างขึ้นมาก็สามารถเก็บไว้ที่ Container ของ mongo

การ Stop Container และ Start Container อีกครั้ง

เราสามารถหยุดการทำงานของ Container ทั้งสองได้โดยการกด control + c ที่หน้า Command Line ที่เรา Start docker-compose ไว้ก่อนหน้าได้

เมื่อกลับมาเช็ค ด้วย docker ps จะเห็นว่าไม่มี Container ที่ทำงานแล้ว

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

ซึ่ง Container ได้ถูกหยุดการทำงานไว้เท่านั้น แต่เราสามารถ Start Container ขึ้นมาได้อีกครั้ง ด้วยคำสั่ง

docker container start parking-lot mongo

จะเห็นชื่อ Container แสดงขึ้นมา ถือว่ากลับมาทำงานอีกครั้งเรียบร้อย

parking-lot
mongo

หรือว่าจะสั่งการรัน Container ด้วยวิธี docker-compose up ที่ Directory Path ก็ได้เช่นเดียวกัน

สรุป

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

อ้างอิง

Compose file versions and upgrading
Compose file reference

ช่วงขายของ

ตอนนี้เรามีบริการรับทำเว็บไซต์เพื่อจุดประสงค์ต่างๆ เช่น
- ร้านค้าออนไลน์
- โปรโมทบริษัท
- เว็บบล็อกสำหรับเขียนบทความ
- หน้าขายของแบบหน้าเดียว (Single Page)
และอื่นๆ โดยใช้ Wordpress เป็นโครงสร้างหลังบ้านและหน้าบ้าน ทำให้ดูแลรักษาง่ายในระยะยาว
คุณไม่ต้องมีแบบมาก่อน ไม่เป็นไร เรามีหน้าเว็บตัวอย่างมาให้คุณเลือกหลายสิบแบบ ราคาคุ้มค่า และส่งมอบงานไว สามารถเข้ามาดูรายละเอียด และสอบถาม-พูดคุยได้ที่เว็บไซต์ของ OneFastWeb ได้เลยครับ ขอบคุณครับ


Tags