這次要把一套 Graylog 從 6 升到 7,Graylog 7 需要 MongoDB 7.0,但這套環境的 MongoDB 還停在 5.0,而且是兩台組成的 replica set。MongoDB 不能跨版本直接跳,要 5.0 → 6.0 → 7.0 一版一版升,每一版都要升完程式、再調整 FCV(Feature Compatibility Version)。
過程中踩到幾個地雷,其中最麻煩的是 apt 顯示安裝成功,mongod 其實根本起不來。這篇把整理好的 SOP 記錄下來,也補上官方文件裡要注意的地方。
環境與原則
| 項目 | 內容 |
|---|---|
| 作業系統 | Ubuntu 22.04 |
| 節點 | mongo1(192.168.10.41,PRIMARY)、mongo2(192.168.10.42,SECONDARY) |
| replica set 名稱 | rs0 |
| 升級路徑 | 5.0 → 6.0 → 7.0 |
原則:
- 兩台不能同時升:先升 SECONDARY,驗證正常後,PRIMARY 先 stepdown 交出角色再升
- 每一版都要調 FCV:升完程式、整個 replica set 都正常之後,才把 FCV 調到新版本,再進行下一版的升級
- 6.0 起用
mongosh:舊的mongo指令在 6.0 移除了 - 7.0 的 setFCV 要加
confirm: true
注意:兩台組成的 replica set,停掉任何一台,剩下那台就會失去多數票,PRIMARY 會自動退成 SECONDARY,整個 replica set 變成無法寫入。所以這次是停掉 Graylog 做維護,不是不停機升級。要真正做到滾動升級不中斷,replica set 至少要有三個投票成員(或兩台加一個 arbiter)。
升級前必讀的地雷
地雷一:storage.journal.enabled 已移除
從 4.0 時代沿用下來的 /etc/mongod.conf,通常會有這段:
storage:
journal:
enabled: true
MongoDB 從 6.1 起 journaling 一律開啟,移除了 storage.journal.enabled 選項(以及 --journal、--nojournal 參數),7.0 也一樣。設定檔裡還有這段的話,mongod 會直接起不來:
Unrecognized option: storage.journal.enabled
6.0 還認得這個選項,所以 5.0 → 6.0 時不會出事,到 6.0 → 7.0 才會爆。升 7.0 之前務必先把它拿掉。
地雷二:apt install 成功不代表 mongod 有起來
apt install 過程中會試著重新啟動 mongod,就算 mongod 起不來,apt 本身還是可能顯示成功。每次安裝完一定要檢查 systemctl is-active mongod 和 mongod --version,不要跳過。
地雷三:stepdown 之後要確認角色真的換了
rs.stepDown() 回傳後不代表選舉已經完成,動手前先用 db.hello().isWritablePrimary 確認自己已經不是 PRIMARY。
準備工作
確認目前狀態(兩台)
lsb_release -a
mongod --version | head -1
systemctl is-active mongod
// mongosh 或 mongo 內執行
rs.status().members.forEach(m => print(m.name, m.stateStr, m.health))
rs.printSecondaryReplicationInfo() // 確認 SECONDARY 沒有落後
db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })
注意:升級前 FCV 必須等於目前的版本。要升 6.0,FCV 要先是 5.0;要升 7.0,FCV 要先是 6.0。如果 5.0 的 FCV 還停在 4.4(從 4.4 升上來後忘了調),要先執行 db.adminCommand({ setFeatureCompatibilityVersion: "5.0" })。
開檔數限制
MongoDB 官方建議 nofile 至少 64000。用套件安裝的 mongod 是由 systemd 啟動,/etc/security/limits.conf 對它無效,實際的限制以 systemd unit 的 LimitNOFILE 為準(官方套件預設已設 64000)。確認方式:
cat /proc/$(pidof mongod)/limits | grep -i 'open files'
備份
在 PRIMARY 上做:
mkdir -p /var/backups/mongo
mongodump --host 192.168.10.41:27017 --out /var/backups/mongo/backup-$(date +%Y%m%d-%H%M%S)
ls -la /var/backups/mongo/
# 設定檔也備份
cp /etc/mongod.conf /var/backups/mongo/mongod.conf.$(hostname)
有開帳號驗證的話,加上 -u、--authenticationDatabase admin。如果是虛擬機,升級前另外做一份快照,回復最快。
停止 Graylog
# 兩台都停
systemctl stop graylog-server
第一階段:5.0 → 6.0
加入 6.0 套件庫(兩台)
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | \
gpg --dearmor -o /usr/share/keyrings/mongodb-server-6.0.gpg
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" \
| tee /etc/apt/sources.list.d/mongodb-org-6.0.list
# 停用 5.0 套件庫
sed -i 's/^deb/# deb/' /etc/apt/sources.list.d/mongodb-org-5.0.list
apt update
apt list --upgradable 2>/dev/null | grep mongo
apt-key 已經不建議使用,這裡改用 signed-by 指定金鑰檔。
如果之前有用 apt-mark hold 鎖住版本(建議要鎖,避免日常更新時意外升級),升級前要先解開:
apt-mark showhold
apt-mark unhold mongodb-org mongodb-org-server mongodb-org-mongos mongodb-org-tools
升級 SECONDARY(mongo2)
systemctl stop mongod
apt install -y mongodb-org
systemctl start mongod
sleep 10
# 必做驗證
systemctl is-active mongod # 預期 active
mongod --version | head -1 # 預期 db version v6.0.x
# 失敗的話查原因
journalctl -u mongod --no-pager -n 30
mongodb-org 是整組的中繼套件,會一併升級 server、mongos、tools,並裝上 mongosh。
確認 replica set
mongosh --host 192.168.10.41 --eval 'rs.status().members.forEach(m => print(m.name, m.stateStr))'
兩個成員都要是 PRIMARY 或 SECONDARY,不能有 (not reachable/healthy)。
PRIMARY stepdown 後升級(mongo1)
# 交出 PRIMARY
mongosh --host 192.168.10.41 --eval 'rs.stepDown(60)'
# 確認已經不是 PRIMARY
mongosh --host 192.168.10.41 --quiet --eval 'db.hello().isWritablePrimary' # 預期 false
systemctl stop mongod
apt install -y mongodb-org
systemctl start mongod
sleep 10
systemctl is-active mongod
mongod --version | head -1 # 預期 v6.0.x
設定 FCV 為 6.0
到目前的 PRIMARY(stepdown 後應該是 mongo2)執行:
mongosh --host 192.168.10.42 --eval 'db.adminCommand({ setFeatureCompatibilityVersion: "6.0" })'
mongosh --host 192.168.10.42 --eval 'db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 })'
確認是 6.0 才能繼續。這時候先不要啟動 Graylog,等升到 7.0 再說。
第二階段:6.0 → 7.0
移除 storage.journal.enabled(兩台,必做)
在安裝 7.0 之前完成,否則 apt 安裝時重新啟動 mongod 就會失敗。
# 先看現況
grep -n -A2 'journal' /etc/mongod.conf
# 備份
cp /etc/mongod.conf /etc/mongod.conf.bak-$(date +%Y%m%d-%H%M%S)
用編輯器把 journal: 與底下的 enabled: true 兩行刪掉,改完 storage 區段應該只剩:
storage:
dbPath: /var/lib/mongodb
# 確認沒有 journal 設定了
grep -n 'journal' /etc/mongod.conf || echo "OK:沒有 journal 設定"
設定檔是 YAML,縮排錯了 mongod 一樣起不來,建議手動編輯,改完再確認一次。
加入 7.0 套件庫(兩台)
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | \
gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" \
| tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sed -i 's/^deb/# deb/' /etc/apt/sources.list.d/mongodb-org-6.0.list
apt update
apt list --upgradable 2>/dev/null | grep mongo
升級 SECONDARY(這時是 mongo1)
剛才 stepdown 過,角色已經對調,先確認誰是 SECONDARY 再動手:
mongosh --quiet --eval 'db.hello().isWritablePrimary' # 在要升級的那台,預期 false
systemctl stop mongod
apt install -y mongodb-org
systemctl start mongod
sleep 10
systemctl is-active mongod # 預期 active
mongod --version | head -1 # 預期 v7.0.x
如果 is-active 回 failed,九成是 journal 設定沒拿掉,用 journalctl -u mongod -n 30 確認。
確認 replica set
mongosh --host 192.168.10.41 --eval 'rs.status().members.forEach(m => print(m.name, m.stateStr))'
PRIMARY stepdown 後升級(這時是 mongo2)
mongosh --quiet --eval 'db.hello().isWritablePrimary' # 預期 true,確認是 PRIMARY
mongosh --quiet --eval 'rs.stepDown(60)'
mongosh --quiet --eval 'db.hello().isWritablePrimary' # 預期 false
systemctl stop mongod
apt install -y mongodb-org
systemctl start mongod
sleep 10
systemctl is-active mongod
mongod --version | head -1 # 預期 v7.0.x
設定 FCV 為 7.0
連到目前的 PRIMARY:
db.adminCommand({ setFeatureCompatibilityVersion: "7.0", confirm: true })
db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 }) // 預期 "7.0"
從 7.0 起 setFCV 一定要加 confirm: true,沒加會直接回錯誤,這是官方刻意的設計,提醒你調整 FCV 之後要降版會比較麻煩。
鎖定版本
apt-mark hold mongodb-org mongodb-org-server mongodb-org-mongos mongodb-org-tools mongodb-mongosh
第三階段:啟動 Graylog
# 兩台都做
systemctl start graylog-server
sleep 30
journalctl -u graylog-server --no-pager -n 30
curl -s http://localhost:9000/api/system/lbstatus # 預期 ALIVE
server.conf 裡的 mongodb_uri 如果有寫 replicaSet=rs0 和兩台主機,就不用改。
復原方式
每個階段之間都可以停在當時的版本,真的出問題時:
從備份還原
# 兩台的 Graylog 先停
systemctl stop graylog-server
# 在 PRIMARY 還原,replica set 會自動同步到 SECONDARY
mongorestore --host 192.168.10.41 --drop /var/backups/mongo/backup-YYYYMMDD-HHMMSS
注意:FCV 調到 7.0 之後要降版,官方程序比較繁瑣(要先把 FCV 降回 6.0,再換回 6.0 的程式),而且部分 7.0 才有的資料格式必須先處理。如果升級後很快就發現問題,用升級前的虛擬機快照或備份回復通常比較快。所以我才會在每個階段都先確認一切正常,再調 FCV。
預估時間
| 階段 | 時間 |
|---|---|
| 備份 | 10 分鐘 |
| 5.0 → 6.0 | 15~20 分鐘 |
| 6.0 → 7.0 | 15~20 分鐘 |
| 驗證與啟動 Graylog | 10 分鐘 |
| 總計 | 約 1 小時 |
資料量越大,備份與 mongod 啟動檢查的時間會越長,Graylog 的 MongoDB 只存設定與中繼資料,通常很快。
升級完成檢查清單
- 兩台的
mongod --version都是 7.0.x rs.status()兩個成員都正常(一台 PRIMARY、一台 SECONDARY)- FCV 是
7.0 - 兩台的 graylog-server 都是 active
- Graylog 網頁介面可以登入
- 原有的 stream、input、看板、使用者都還在
- 新訊息能正常寫入(看 input 的流量)
結論
MongoDB 升級最怕的是「以為成功了」:apt 回傳成功、指令沒報錯,結果 mongod 其實沒起來。我的習慣是每一步都驗證:is-active、--version、rs.status(),三個都對了才往下走。
另外兩台的 replica set 其實並不理想,停一台就整組不能寫入。這次升級完之後,也建議加一台 arbiter 或第三個成員,下次維護才能真的不停機。
參考資料
- MongoDB 文件:Upgrade a Replica Set to 6.0
https://www.mongodb.com/docs/manual/release-notes/6.0-upgrade-replica-set/ - MongoDB 文件:Upgrade a Replica Set to 7.0
https://www.mongodb.com/docs/manual/release-notes/7.0-upgrade-replica-set/ - MongoDB 文件:Compatibility Changes in MongoDB 7.0
https://www.mongodb.com/docs/manual/release-notes/7.0-compatibility/ - MongoDB 文件:setFeatureCompatibilityVersion
https://www.mongodb.com/docs/manual/reference/command/setFeatureCompatibilityVersion/ - Graylog 文件:Compatibility Matrix
https://go2docs.graylog.org/current/downloading_and_installing_graylog/compatibility_matrix.htm



