在[資料庫]使用 Docker 構築不同 MongoDB 架構 (一) 提到 MongoDB 可能有以下架構:
因為 Standalone 是最簡單的 MongoDB 架構,所以我們直接用 Docker 架設 Standalone MongoDB,來介紹「當使用 Docker 架設 MongoDB 要注意的事項」。
開始之前先列舉幾個要點,請先放在心中:
當看完本篇可以試著找出它們的出現在哪?
本系列文的專案放在:https://github.com/eugenechen0514/demo_mongo_cluster
本系列文使用只 Docker Compose File 來設定 MongoDB 叢集。我們假設已安裝 Docker,還沒安裝請到 Docker Desktop 下載安裝。
為了專注建立 MongoDB 叢集,我們容器的 Network Mode 都是假設為
host
,使用其它模式(見: Day 30- 三周目 - Docker network 暨完賽回顧) 會需要有更多的設定,所以我們不使用。
Standalone 架構只有一個 MongoDB 的實體,存取資料的資料庫只有一個, Mongo Client 只要直接連到它就可以使用。
我們的資料夾目錄如下,並假設工作目錄在 demo_mongo_cluster (也就是 /Users/eugenechen/Documents/Projects/demo_mongo_cluster)
我們可以在 demo_mongo_cluster 工作目錄下執行以下操作
建立 MongoDB 容器並且在背景執行容器
docker-compose -f docker-compose-standalone.yml up -d
就會在背景執行 (-d
) 一個 Standalone MongoDB。
第一次執行應該會像這樣
紅線上相當於執行指令 docker pull mongo:4.2
,下載 mongo:4.2
的映像檔到本機;紅線下是建立並執行容器。
停止執行容器
docker-compose -f docker-compose-standalone.yml stop
請注意,此操作是停止容器運作導致 MongoDB process(行程) 停止,類似 kill process 非正常關閉 MongoDB,在有讀寫的情況下會有無法預期的情況發生。安全的 關閉 MongoDB 要連入資料庫
use admin
db.shutdownServer()
先關 MongoDB ,再停止容器會比較安全。
重新執行容器(在背景運作)
docker-compose -f docker-compose-standalone.yml start
停止並刪除容器
docker-compose -f docker-compose-standalone.yml down
因為我們使用 MongoDB 4.2 (mongo:4.2
) ,所以 Mongo Shell 建議也要使用同樣的版本號,否則可能會有不可預期的事。
官方的 mongo:4.2
映像檔本身就放了所有的工具,像是 mongo
, mongoimport
, ... 等 (見:MongoDB Package Components。因此我們只需要直接使用就可以了。在終端機輸入:
docker run --rm -it --network host mongo:4.2 bash
就會建立一個 暫時的 容器且進入(或稱執行)一個具有 MongoDB shell 終端機,接下來就有 mongo
可以用了。
不要被長長的指令嚇到了,分開看就一目瞭然
A (docker run
) :讀入某個映像檔,建立容器並執行。
B (--rm
) :容器停止後自動刪除,也就是不能再用 docker start
重新執行容器。
C (-it
):這是 -i/--interactive
, -t/--tty
的合併,簡單來說就是開啟可互動式終端機。
D (--network host
):容器的網路模式用 host
,可以想像容器「寄生」在本機上,所以 127.0.0.1
就是指本機。此模式下,若容器內部開啟任何 PORT 就如同在本機開啟。
E (mongo:4.2
):映像檔名是 mongo
,tag(標籤)是 4.2
,就是用 MongoDB 4.2 版本。
F (bash
): 當 docker run
執行容器時要執行的 command (指令)。 bash
就是指執行容器內 /bin/bash
的程式。
全部合起來看就像是:在 本機端 開啟一個 具有 MongoDB tools 且 暫時的 終端機。
接下來,我們詳細說明 Standalone 組態。有二個地方需要關注:
version: '3'
services:
database:
image: mongo:4.2
container_name: mongo4
network_mode: host
command: mongod --dbpath /data/db --port 27041 --config /resource/mongod.yml
volumes:
- ./standalone/config/mongod.yml:/resource/mongod.yml
- /Users/eugenechen/Documents/Projects/demo_mongo_cluster/standalone/data:/data/db
network_mode: host
database
的網路模式是 host
,當容器內部開啟任何 PORT 就如同在本機開啟。
command: mongod --dbpath /data/db --port 27041 --config /resource/mongod.yml
command
是容器執行時要執行的指令。
它後面接的 mongod
有三個常用的參數:
--dbpath
是指定 MongoDB 存放資料的資料夾。--port
是 MongoDB 要開啟(監聽)的 PORT。--config
指定 MongoDB Config file。我們注意到:路徑應該要是在容器內的路徑,不是指本機端的路徑。
volumes:
這是把本機端的檔案/資料夾掛載到容器內的 File System。這方法在 docker 中叫 bind mounts,可以讓本機端和容器共享資料,我們透過此方法就可以把 MongoDB 的資料留在本機端,不會因為刪除容器而資料同時刪除。
- /Users/eugenechen/Documents/Projects/demo_mongo_cluster/standalone/data:/data/db
的格式是 A:B
, A 是本機端的路徑,B 是容器內的路徑。當容器建立完成掛載,這兩個路徑就可以共享資料。如果在容器中寫資料到 /data/db
中,從本機端的 /Users/eugenechen/Documents/Projects/demo_mongo_cluster/standalone/data
也會看的到。
MongoDB 雖然執行在容器中,但我們有指定資料庫位置到 /data/db
中,且它被 bind (綁定) 在 /Users/eugenechen/Documents/Projects/demo_mongo_cluster/standalone/data
中,所以當容器刪除 (docker-compose down
) 資料依然會留在本機端。下次重新建立 MongoDB 容器時 (docker-compose up
),可以指向同樣的資料庫位置,就可以繼續使用以前的資料。
bind mounts
也可以用在檔案上,我們指定本機端的 ./standalone/config/mongod.yml
(相對目錄) 掛載到容器中的 /resource/mongod.yml
, mongod
就可以用 --config /resource/mongod.yml
讀入 MongoDB 組態檔。
net:
bindIpAll: true
storage:
engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 0.2
這裡完整的 MongoDB 組態見 Configuration File Options,我們只用幾個重要的設定
bindIp
/ bindIpAll
此設定哪些 Client IP 可以連入 MongoDB 中,預設是 localhost
也就是本機而已。我們假設 Client IP 可能來自不同的主機,所以用 net.bindIpAll: true
指定任意 Client IP 都可以連入。
engine
storage.engine
有 wiredTiger
/ inMemory
可以選擇,不論選哪個都要小心設定 「可以使用的 cacheSizeGB
/ inMemorySizeGB
大小」。因為 Mongo 沒有假設它會執行在容器中,它會依照硬體配置計算預設值,所以當一台機器用 Docker 架兩台以上 Mongo 就要小心過度配置記憶體大小。因此,當使用 Docker 時,我們就 一定 要設定大小。
若使用 Vagrant 這類的虛擬機器,也最好設定記憶體大小。
筆者有切身經驗,因為沒有設定大小導致狂斷線或有時會連不進去。
一般 OS 建立連線(socket) 時會開啟檔案,若是 OS 所設定的開檔數不夠大,就會出現
Too many open files
之類的錯誤訊息,這設定會影響到 MongoDB 可以開啟的連線數。
順帶一提,除了 OS 層級的連線限制,MongoDB 也提供 net.maxIncomingConnections 限制最大連線數。
根據 Docker 文件 Set ulimits in container,它說預設的值是由 Docker Daemon 決定。我們可以用
docker run --rm mongo:4.2 sh -c "ulimit -n"
# 1048576
查到 Docker 建立容器時預設的開檔限制。
我們可以在建立容器時修改開檔上限,使用 docker run --ulimit
docker run --ulimit nofile=1024:1024 --rm mongo:4.2 sh -c "ulimit -n"
# 1024
若是使用 Docker Compose File,加入 ulimits
version: '3'
services:
database:
image: mongo:4.2
container_name: mongo4
...略
ulimits:
nofile:
soft: 20000
hard: 40000
檢驗是否有修改成功
docker exec mongo4 sh -c "ulimit -n"
# 20000
筆者發現 Docker Daemon 預設的開檔數本來就很大,目前還沒遇到需要修改的必要,但請讀者留心有這限制。
我們透過建立 Standalone MongoDB 來引入 Docker 的組態應該如何設定和使用。
讀者可以回想以下要點,是否找到答案呢?