ข้ามไปยังเนื้อหา

ติดตั้งด้วย Docker

วิธีที่เร็วที่สุดในการได้ MongoDB จริง ๆ มาเล่นคือ Docker image mongo ทางการให้ server ที่สะอาดและแยกตัวแก่คุณในคำสั่งเดียว โดยไม่มีอะไรติดตั้งถาวรบนเครื่องของคุณและไม่มีอะไรต้องถอนการติดตั้งทีหลัง บทเรียนนี้พาคุณจาก “Docker กำลังทำงานอยู่” ไปสู่ “ฉันคุยกับ MongoDB ได้” — เริ่มด้วยคำสั่งบรรทัดเดียว แล้วตามด้วย docker-compose.yml เล็ก ๆ ที่คุณเก็บไว้ในโปรเจกต์ได้

คุณต้องการแค่ Docker Desktop (หรือ Docker engine) ที่ติดตั้งและทำงานอยู่ ทุกอย่างที่เหลือมาจาก image

คำสั่งนี้ดึง image ทางการ เริ่ม container ชื่อ mongo-dev เปิดเผยพอร์ต MongoDB เริ่มต้น 27017 ออกมายังเครื่องของคุณ เก็บข้อมูลไว้ใน named volume เพื่อให้ข้อมูลอยู่รอดข้าม restart และตั้ง username และ password ของ root:

Terminal window
docker run -d \
--name mongo-dev \
-p 27017:27017 \
-v mongo-data:/data/db \
-e MONGO_INITDB_ROOT_USERNAME=root \
-e MONGO_INITDB_ROOT_PASSWORD=secret \
mongo:7

มีบางอย่างในคำสั่งนั้นที่ควรทำความเข้าใจ:

  • -d รัน container ในเบื้องหลัง (detached) จะได้ไม่ยึด terminal ของคุณไว้
  • -p 27017:27017 map พอร์ต 27017 ของ container เข้ากับพอร์ตเดียวกันบน host ของคุณ นั่นคือที่ที่ MongoDB รับฟังโดยค่าเริ่มต้น
  • -v mongo-data:/data/db mount named volume ที่ /data/db ที่เป็นไดเรกทอรีที่ MongoDB เขียนไฟล์ลงไป volume อยู่นอก container ดังนั้นการลบและสร้าง container ใหม่จึงไม่ทำให้ข้อมูลของคุณหาย
  • -e MONGO_INITDB_ROOT_USERNAME / -e MONGO_INITDB_ROOT_PASSWORD สร้าง user ระดับ administrator ในครั้งแรกที่ container เริ่มต้นไดเรกทอรีข้อมูลที่ว่างเปล่า

สำหรับอะไรก็ตามที่เกินกว่าการทดสอบเร็ว ๆ, docker-compose.yml ดีกว่า: การตั้งค่าอยู่ในไฟล์ที่คุณ commit ได้ และคำสั่งเดียวก็ยกทุกอย่างขึ้นมา เวอร์ชันนี้รัน MongoDB และเพิ่ม mongo-express ที่เป็น web UI น้ำหนักเบาสำหรับเขี่ยดูข้อมูลของคุณใน browser:

services:
mongo:
image: mongo:7
container_name: mongo-dev
restart: unless-stopped
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: secret
volumes:
- mongo-data:/data/db
mongo-express:
image: mongo-express:latest
container_name: mongo-express
restart: unless-stopped
ports:
- "8081:8081"
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: secret
ME_CONFIG_MONGODB_URL: "mongodb://root:secret@mongo:27017/"
depends_on:
- mongo
volumes:
mongo-data:

ยก stack ทั้งหมดขึ้นมาจากไดเรกทอรีที่เก็บไฟล์นั้น:

Terminal window
docker compose up -d

เมื่อ stack ทำงานอยู่ คุณเปิด mongo-express ที่ http://localhost:8081 เพื่อเรียกดู database และ collection ใน browser service mongo-express เป็น optional ถ้าอยากได้แค่ database ก็ลบทิ้งได้

container รัน MongoDB และรับฟังบนพอร์ต 27017 พอร์ตที่คุณเปิดเผยส่งต่อ localhost:27017 เข้าไปในนั้น, named volume เก็บข้อมูลให้ปลอดภัยอยู่นอก container, และอะไรก็ตามที่พูดโปรโตคอล MongoDB — mongosh, Compass, หรือแอปพลิเคชันของคุณ — เชื่อมต่อผ่านพอร์ตนั้น

flowchart LR
  App["Your app / mongosh / Compass"] -->|"mongodb://localhost:27017"| Port["Host port 27017"]
  Port --> Container["mongo container"]
  Container -->|"writes to /data/db"| Volume["named volume: mongo-data"]
client ของคุณเชื่อมต่อผ่านพอร์ตที่เปิดเผยไปยัง container ซึ่งคงข้อมูลไว้ใน named volume

ตรวจว่า container ขึ้นมาแล้วด้วย docker ps:

Terminal window
docker ps

คุณควรเห็น row สำหรับ image mongo ที่มีสถานะ Up และการ map พอร์ต 0.0.0.0:27017->27017/tcp ทีนี้เชื่อมต่อด้วย shell client mongosh ติดมากับ image อยู่แล้ว คุณจึงรันได้เลยโดยไม่ต้องติดตั้งอะไรเพิ่ม:

Terminal window
docker exec -it mongo-dev mongosh "mongodb://root:secret@localhost:27017"

ถ้าคุณมี mongosh ติดตั้งบน host แทน ให้ชี้ไปที่พอร์ตที่เปิดไว้ตรง ๆ:

Terminal window
mongosh "mongodb://localhost:27017"

การเชื่อมต่อที่สำเร็จจะพาคุณไปที่ prompt test> จากที่นั่นการพิมพ์ db.runCommand({ ping: 1 }) แล้วได้ { ok: 1 } กลับมา ยืนยันว่า server ยังมีชีวิตและกำลังตอบสนอง

  • ความคงอยู่ของข้อมูลอยู่ใน volume ไม่ใช่ใน container ตราบใดที่คุณเก็บ volume mongo-data ไว้ คุณสามารถหยุด ลบ และสร้าง container ใหม่ได้โดยไม่สูญเสียอะไร การรัน docker volume rm mongo-data ต่างหากที่ลบข้อมูลจริง ๆ
  • root user ถูกสร้างเฉพาะตอน init ครั้งแรก ตัวแปร MONGO_INITDB_ROOT_* มีผลเมื่อไดเรกทอรีข้อมูลว่างเปล่า ถ้าไปแก้ทีหลังบน volume ที่มีข้อมูลอยู่แล้ว ค่าใหม่จะไม่มีผล user เดิมยังอยู่เหมือนเดิม
  • พอร์ต 27017 เป็นค่าเริ่มต้นของ MongoDB ถ้ามีอย่างอื่นจองพอร์ตนี้อยู่ ให้เปลี่ยนฝั่ง host ของการ map เช่น -p 27018:27017 และเชื่อมต่อไปที่ 27018
  • ปักหมุดเวอร์ชันหลัก อย่าง mongo:7 แทนที่จะเป็น mongo:latest เพื่อให้การอัปเดต image ไม่ทำให้คุณตกใจด้วยเวอร์ชัน server ที่ต่างออกไป
ตัวเลือกBenefitCost
รัน MongoDB ผ่าน Dockerล้างและสร้างใหม่ได้เร็ว ไม่ทิ้งอะไรถาวรบนเครื่อง และ environment ใกล้เคียง production ที่มักรัน container เหมือนกันในทีมต้องมี Docker engine ทำงานอยู่ตลอด และมี overhead เล็กน้อยของ container เทียบกับการรันตรง ๆ บน host
ติดตั้ง MongoDB บนเครื่องโดยตรงไม่มี layer ของ container คั่นกลาง เชื่อมต่อผ่าน localhost ตรง ๆreset หรือปรับเวอร์ชันยากกว่า และแต่ละเครื่องในทีมอาจลง version หรือ config ไม่ตรงกัน
  • ลืมปักหมุด image tag แล้วใช้ mongo:latest — เวลา pull image ใหม่ เวอร์ชัน server อาจเปลี่ยนแบบไม่ตั้งใจและพัง config หรือ behavior ที่เคยพึ่งพา ควรปักหมุดเวอร์ชันหลักอย่าง mongo:7 เสมอ
  • ลบ container ด้วย docker rm แล้วคิดว่าข้อมูลหายไปด้วย — ถ้า data อยู่ใน named volume การลบ container ไม่กระทบข้อมูล; กลับกัน คนที่ไม่ mount volume เลยแล้วแปลกใจว่าทำไม data หายทุกครั้งที่ restart container
  • เปิดพอร์ต 27017 แบบไม่ตั้ง password แล้วเข้าใจว่าเครื่อง dev “ไม่มีใครมาแตะอยู่แล้ว” — ถ้าเครื่องมีการ expose พอร์ตออก network ภายนอกโดยไม่ตั้งใจ (เช่น cloud VM) การไม่ตั้ง authentication เปิดช่องให้คนนอกต่อเข้ามาได้ตรง ๆ

💡 ตัวอย่างจากของจริง

CI pipeline ของหลายทีม — สร้างและทำลาย container mongo ใหม่ทุกครั้งที่รัน integration test แต่ละรอบ เพื่อให้ทุก test เริ่มจาก database ที่ว่างเปล่าเหมือนกันทุกครั้ง ไม่มี state ค้างข้ามรอบ

ทีม backend ที่ทำงานข้ามเครื่อง — commit ไฟล์ docker-compose.yml ไว้ในโปรเจกต์ เพื่อให้ทุกคนในทีม (และ CI) ได้ MongoDB เวอร์ชันเดียวกันเป๊ะด้วยคำสั่งเดียว แทนที่จะให้แต่ละคนติดตั้งเองแล้วเวอร์ชันไม่ตรงกัน

ทำไมต้อง mount named volume ไว้ที่ /data/db ตอนรัน container mongo?
ค่า default แล้ว MongoDB ฟังอยู่ที่พอร์ตไหน?
ตัวแปร MONGO_INITDB_ROOT_USERNAME และ PASSWORD มีผลตอนไหน?