iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Software Development

從零開始構建能理解語義的 Linebot 架構系列 第 27

MongoDB 概念及部署: 使用 Docker 設置含初始資料庫與用戶驗證的 MongoDB 服務

  • 分享至 

  • xImage
  •  

概述

  • 本文將介紹如何使用 Docker Compose 設置一個 MongoDB服務。此服務將包含一個初始資料庫並啟用使用者驗證。這可以幫助我們更方便的在開發和測試階段管理MongoDB,並使我們開發的應用程式和MongoDB互動。
  • 內容會提供兩個可執行MongoDB 服務的Docker-Compose及其他設定檔案:
    • 1.基本設置: 最簡單可連線的設定
    • 2.設定了root 使用者, 初始資料庫以及使用者驗證的設置

使用Docker部署MongoDB

啟動一個基本可用的MongoDB服務相對簡單,只要使用MongoDB官方提供的Image,設定對應的連接阜(Port)、使用者(User)、以及要存放資料的位置(如果想要保存在Host主機上的話)即可。
以下以專案名稱:nextpage為例:

基本設置

我們使用 MongoDB 6.0.4 的官方 image 來建立一個 service:

docker-compose.yml

version: "2"
services:
mongodb:
image: mongo:6.0.4
container_name: mongodb
restart: unless-stopped
volumes:
- MONGO_VOLUMES:/data/db
ports:
- 27017:27017
volumes:
MONGO_VOLUMES:
  • 以上範例將Mongodb標準的連接阜: 27017從Container內導出到本機(host),並且掛載(mount)了一個叫MONGO_VOLUMES的volume來保存Mongodb的資料。
  • 這樣在重新啟動Mongodb容器後,資料不會消失,而是會保存在Host主機上的一個路徑中。這個路徑由Docker指定,是用來存放這個容器資料的位置。

Firewall / AWS EC2 Security Group

  • 為了要讓遠端機器連進MongoDB,Firewall也要打開對應的in bound policy,例如,在AWS EC2上,可以在Security Group中設置以下Rule:

https://ithelp.ithome.com.tw/upload/images/20241011/20105227WL23cXhEdu.png
圖: Inbound Rule: TCP 27017

這樣就啟動了一個可連線的MongoDB。
但除了基本的連線環境外,對於專案的使用來說,還需要進一步的設定,主要包含以下兩個方面:

  • 1.驗證/安全設定
    • 需要設定使用者權限,只容許具有權限的User做特定的操作
  • 2.初始設定
    • 我們希望在啟動MongoDB時,自動把專案所需要的Database、Collection,User等設定都建立起來,以便後續的開發和測試。

下面進一步介紹如何進行這些設定:

設定了root 使用者, 初始資料庫,以及使用者驗證的設置

這部分會對MongoDB服務做以下設定:

  • 讓MongoDB以authentication enabled模式啟動,驗證User在Database的操作。
  • 設定一個初始Database:nextpage,並新增一個具備Read / Rrite這個Database權限的User。
  • 設定具備root權限的User
    要達成上述需求,除了docker-compose.yml外,還需要新增資料夾及相關的script。

檔案結構

整個檔案結構如下:

├── docker-compose.yml
├── mongodb
│   └── initdb.d
│       └── nextpage.js
  • Database的內容需要寫script來建立,並且掛載到容器內的docker-entrypoint-initdb.d目錄,使Container在啟動時去執行它。
  • 如果容器的docker-entrypoint-initdb.d目錄下存在script檔案,在啟動MongoDB時,會自動use MONGO_INITDB_DATABASE指定的資料庫,並執行scrip內的指令。

下面說明把Script 掛載進Container的方式:

掛載Script,讓Container啟動時自動執行

掛載點: docker-entrypoint-initdb.d

  • MongoDB也像一些其他資料庫的Docker image一樣,提供docker-entrypoint-initdb.d這個接口,來讓容器啟動時執行一些初始化script。

設定方式: 使用volumes

  • 把想要在容器啟動時執行的動作寫成Script檔案: nextpage.js(建立Collection, 建立root以外的User並設定權限等),並且把檔案放到路徑: /mongodb/initdb.d

以我們專案使用的例子來說,可在docker-compose如下設定:

…
volumes:
- ./mongodb/initdb.d/:/docker-entrypoint-initdb.d/
…
  • 上述設定把Host的nextpage.js所在的路徑:/mongodb/initdb.d mount 到 容器的路徑:/docker-entrypoint-initdb.d。這樣在容器啟動執行MongoDB時,就會自動執行被mount進去/docker-entrypoint-initdb.d下面的nextpage.js。

docker-compose.yml

  • 綜上所述,我們的docker-compose如下:
version: "2"

services:
  mongodb:
    image: mongo:6.0.4
    container_name: mongodb
    restart: unless-stopped
    environment:
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=root
      - MONGO_INITDB_DATABASE=nextpage
    volumes:
      - ./mongodb/initdb.d/:/docker-entrypoint-initdb.d/
      - MONGO_VOLUMES:/data/db
    ports:
     - 27017:27017
volumes:
  MONGO_VOLUMES:

其中:

  • ./mongodb/initdb.d/
    • 是我們要掛載到容器內的docker-entrypoint-initdb.d/的路徑。
  • MONGO_INITDB_DATABASE
    • 建立初始Database: nextpage
    • MongoDB會在啟動docker時建立一個以此環境變數命名的空的Database
  • MONGO_INITDB_ROOT_USERNAME / MONGO_INITDB_ROOT_PASSWORD
    • 建立一個具備Read / Write 這個Database 的權限的 user,以及具備 root 權限的 user。
    • authentication enabled

為什麼要先建立root權限的User?

  • 我們在docker-compose 必須設定root權限的User,這樣MongoDB才會以authentication enabled 的模式啟動 (等同於使用指令: mongod — auth),也就是所有操作都會驗證User的權限
  • root權限User的Authentication Database會是admin這個Database。所以如果要用這個root登入,連線的connection string必須指定authSourceadmin

例如:

mongodb://root:root@Server的URL:27017/nextpage?serverSelectionTimeoutMS=5000&connectTimeoutMS=10000&authSource=admin&authMechanism=SCRAM-SHA-256

Authentication Database

  • MongoDB是把User建立在某一個資料庫上的。這個User所在的資料庫,被稱作Authentication Database
  • MongoDb會把Authentication Database + User當作User權限驗證的唯一識別,並且存在admin這個database的collection: system.users
  • 我們在連線到MongoDB要驗證時,必須要指定User name, password, 並且連到這個User所在的Authentication Database。

database: admin及 Authentication Database的關聯

  • MongoDB會預先建立的Database之一
  • 每個Database中被建立的User資料,會存在admin的collection: system.users 裡面。
  • system.users中的每筆資料包含了userId(由MongoDB生成), user name, password, 以及這個user的Authentication Database

Script: nextpage.js

  • 我們在 mongodb/initdb.d/nextpage.js 中:
    • 建立 action_recordfood_record 這兩個 Collection,來存放我們專案要紀錄的使用者訓練及飲食紀錄。
    • 建立一個具備 Read / Write database: 的權限的User: developer

下面是mongodb/initdb.d/nextpage.js 的內容

db.createCollection("action_record");
db.createCollection("food_record");
// 已經在MONGO_INITDB_DATABASE指定過資料庫名稱,所以預設就是使用`nextpage`這個Database,
// 不用加上use nextpage
db.createUser({
 user: "developer",
 // 在mongo shell 操作時可以用passwordPrompt, 輸入完指令後自己打密碼進去
 // 這邊因為是給測試用docker自動執行的指令,所以直接指定密碼 (cleartext password)
 pwd: "1qaz2wsx..",
 // 任何額外資訊
 customData: { name: "Henry" },
 roles: [
  // 針對當前db(nextpage)的role可以直接用字串指定role name
  "readWrite",
  // 針對其他db的role需要用 object: {role: "role name", db: "db name"}
  // Note: db: "" 代表for 所有database
  { role: "clusterAdmin", db: "admin" },
  { role: "readAnyDatabase", db: "admin" },
 ]
},)

Script檔案格式

  • docker可接受.js.sh的腳本檔案。
  • 如果是js檔案,將在 MongoDB 啟動時被 mongo (版本 5.0 以前) 或 mongosh (版本 5.0 以後) 執行。
  • 如果沒有指定MONGO_INITDB_DATABASE,則會在test這個database上執行。
  • User 和 Role,以及他們和資源的關係如下說明:

MongoDB的Role-Based Access Control

  • 在MongoDB的權限管理分成User和Role,每個User可以被賦予一個或多個Role,而Role的內容則指定了可用的資源,以及可對資源做的操作:

可用的資源

  • 指的就是Database及Collection

可對資源做的操作

  • MongoDB稱之為Privilege Actions, 可見官方提供的完整列表

Role的種類

  • MongoDB的Role又分成Built-in自訂Role,及其他種類:

  • 1.Built-in Role

    • 根據對象資源大致分為 Database administration Role 及 一般(非admin)database的Built-in role
    • 例如readWrite這個Role包含了對某個Database的資料讀取 / 修改權限。
    • 所有Built-in Role列表可參考官方連結
  • 2.Admin相關 Role:只針對admin這個database的Role。

  • 3.其他:

    • 像是備份資料庫, 建立索引等更細部的功能的Role。

總結

本篇文章說明如何以Docker啟動一個MongoDB服務:

  • 在docker-compose設置環境變數:
    • 指定js script
    • 建立root user
    • 建立專案使用的Database
    • 掛載Volumes,將Host上的目錄掛載到Container內的/docker-entrypoint-initdb.d/,目的是將我們寫的script掛載到Container,讓他啟動時自動執行初始設定。
  • 初始設定
    • 在script內建立需要的Collection及User
    • 需要以賦予Role的方式指定User的權限

至此,我們在EC2上執行的基礎設施: Kafka, MongoDB,以及我們開發的BotServer程式都已經設置完成。
下一篇將說明OpenAI的基礎觀念,以及API的實作。
本文修改自作者的blog文章: [Mongo] 如何使用Docker Compose設置一個包含初始資料庫和使用者驗證的MongoDB Service


上一篇
使用 Spring Boot 開發 Backend Bot Server: 使用 Spring Data 連接 MongoDB
下一篇
OpenAI 概念介紹與實作:核心概念與 Chat Completion 的應用
系列文
從零開始構建能理解語義的 Linebot 架構30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言