MongoDB 是目前非常常见的 NoSQL 文档数据库,在日志系统、内容平台、用户画像、AI 应用、爬虫、配置中心等场景里都能看到它。
和 MySQL 最大的区别之一,是 MongoDB 保存的数据天然更接近 JSON:
json
{
"name": "JavaPub",
"age": 28,
"tags": ["Go", "AI", "Web3"],
"profile": {
"website": "https://javapub.net.cn",
"github": "Rodert"
}
}
因此,对于字段变化比较频繁的数据,MongoDB 使用起来会非常方便。
这篇文章从一台刚安装好的 Linux 服务器开始,完整演示:
text
Linux
↓
安装 MongoDB
↓
启动服务
↓
修改配置
↓
创建管理员
↓
开启账号认证
↓
配置远程访问
↓
防火墙放行
↓
数据库 CRUD
↓
备份 / 恢复
↓
Docker Compose 部署
↓
生产环境优化
文中会使用大量命令,基本可以直接复制执行。
截至 2026 年 8 月,MongoDB 官方文档显示 8.3 是最新 minor release;如果追求相对稳妥的生产环境,也可以继续使用 MongoDB 8.0 系列。本文原生安装部分以 MongoDB 8.0 Community Edition 为例。
一、MongoDB 是什么?
MongoDB 是一个面向文档的数据库。
传统 MySQL 中的数据可能是:
sql
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
age INT,
email VARCHAR(255)
);
插入:
sql
INSERT INTO users(name, age, email)
VALUES ('JavaPub', 28, 'hello@example.com');
MongoDB 则更加接近:
javascript
db.users.insertOne({
name: "JavaPub",
age: 28,
email: "hello@example.com"
})
甚至可以直接嵌套:
javascript
db.users.insertOne({
name: "JavaPub",
age: 28,
social: {
github: "Rodert",
website: "https://javapub.net.cn"
},
skills: [
"Go",
"Java",
"Python",
"Docker"
]
})
不需要先定义非常严格的数据表结构。
二、MongoDB 中几个最基本的概念
如果你之前主要使用 MySQL,可以这样理解:
| MySQL | MongoDB |
|---|---|
| Database | Database |
| Table | Collection |
| Row | Document |
| Column | Field |
| Primary Key | _id |
| SQL | MQL |
| JOIN | $lookup |
例如:
text
Database
└── javapub
├── users
├── articles
├── comments
└── orders
其中:
text
javapub
是数据库。
text
users
是 Collection。
一条数据:
json
{
"_id": "...",
"name": "JavaPub",
"age": 28
}
就是 Document。
三、部署前先检查 Linux 系统
先看系统版本:
bash
cat /etc/os-release
Ubuntu 可能看到:
text
NAME="Ubuntu"
VERSION="24.04 LTS (Noble Numbat)"
ID=ubuntu
VERSION_CODENAME=noble
查看 CPU:
bash
lscpu
查看架构:
bash
uname -m
常见:
text
x86_64
或者:
text
aarch64
查看内存:
bash
free -h
例如:
text
total used free
Mem: 7.7Gi 1.2Gi 5.8Gi
Swap: 2.0Gi 0B 2.0Gi
查看磁盘:
bash
df -h
查看内核:
bash
uname -a
只看 Kernel Version:
bash
uname -r
这里特别提醒一下:MongoDB 官方在 8.2 的发布说明中提到,特定 Linux 6.19 到 7.0.13 内核范围曾存在与其 TCMalloc 的兼容问题;如果你使用非常新的 Linux 内核,部署前最好核对当前版本说明。
四、Ubuntu 安装 MongoDB
MongoDB 官方提供自己的 APT 软件源。
不要直接想当然地执行:
bash
apt install mongodb
Ubuntu 自带仓库里的 mongodb 包并不是 MongoDB 官方维护的 mongodb-org 包,MongoDB 官方文档也明确提醒二者可能冲突。
我们使用官方:
text
mongodb-org
五、Ubuntu 24.04 安装 MongoDB 8.0
1. 更新软件包
bash
sudo apt update
安装基础工具:
bash
sudo apt install -y curl gnupg
2. 导入 MongoDB GPG Key
执行:
bash
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
检查:
bash
ls -lh /usr/share/keyrings/mongodb-server-8.0.gpg
3. 添加 MongoDB 软件源
Ubuntu 24.04 的代号是:
text
noble
执行:
bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" \
| sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
这是 MongoDB 官方 Ubuntu 24.04 安装文档给出的仓库配置方式。
查看:
bash
cat /etc/apt/sources.list.d/mongodb-org-8.0.list
六、Ubuntu 22.04 的区别
如果你的服务器是:
text
Ubuntu 22.04
代号是:
text
jammy
那么使用:
bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" \
| sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
Ubuntu 20.04:
text
focal
对应:
bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/8.0 multiverse" \
| sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
MongoDB 8.0 官方支持 Ubuntu 24.04、22.04 和 20.04 的 64 位 LTS 版本。
七、更新 APT
添加源以后:
bash
sudo apt update
查看 MongoDB:
bash
apt-cache policy mongodb-org
如果软件源正常,应该可以看到:
text
mongodb-org:
Candidate: ...
八、正式安装 MongoDB
执行:
bash
sudo apt install -y mongodb-org
安装完成以后:
bash
mongod --version
例如:
text
db version v8.0.x
查看 MongoDB Shell:
bash
mongosh --version
查看命令路径:
bash
which mongod
bash
which mongosh
通常类似:
text
/usr/bin/mongod
/usr/bin/mongosh
九、MongoDB 安装了哪些东西?
查看:
bash
dpkg -l | grep mongo
通常能够看到类似:
text
mongodb-org
mongodb-org-server
mongodb-org-mongos
mongodb-org-tools
mongodb-mongosh
其中最重要的几个:
text
mongod
MongoDB 数据库服务器
mongosh
MongoDB Shell
mongodump
数据库备份
mongorestore
数据库恢复
mongoexport
导出 JSON / CSV
mongoimport
导入 JSON / CSV
十、MongoDB 默认配置文件在哪里?
默认配置:
text
/etc/mongod.conf
直接查看:
bash
cat /etc/mongod.conf
或者:
bash
sudo vim /etc/mongod.conf
常见内容:
yaml
storage:
dbPath: /var/lib/mongodb
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
net:
port: 27017
bindIp: 127.0.0.1
processManagement:
timeZoneInfo: /usr/share/zoneinfo
这里几个配置非常重要。
十一、MongoDB 默认数据目录
默认:
text
/var/lib/mongodb
查看:
bash
sudo ls -lah /var/lib/mongodb
查看磁盘占用:
bash
sudo du -sh /var/lib/mongodb
十二、MongoDB 默认日志目录
日志:
text
/var/log/mongodb/mongod.log
查看最后 100 行:
bash
sudo tail -n 100 /var/log/mongodb/mongod.log
实时查看:
bash
sudo tail -f /var/log/mongodb/mongod.log
按错误过滤:
bash
sudo grep -i error /var/log/mongodb/mongod.log
十三、启动 MongoDB
执行:
bash
sudo systemctl start mongod
查看状态:
bash
sudo systemctl status mongod
如果正常:
text
Active: active (running)
十四、设置开机启动
执行:
bash
sudo systemctl enable mongod
也可以一步完成:
bash
sudo systemctl enable --now mongod
检查:
bash
systemctl is-enabled mongod
正常:
text
enabled
十五、常用 systemctl 命令
启动:
bash
sudo systemctl start mongod
停止:
bash
sudo systemctl stop mongod
重启:
bash
sudo systemctl restart mongod
查看状态:
bash
sudo systemctl status mongod
查看日志:
bash
sudo journalctl -u mongod
最后 100 行:
bash
sudo journalctl -u mongod -n 100
实时日志:
bash
sudo journalctl -u mongod -f
十六、确认 27017 端口
MongoDB 默认:
text
27017
检查:
bash
sudo ss -lntp | grep 27017
或者:
bash
sudo lsof -i :27017
可能看到:
text
LISTEN 0 4096 127.0.0.1:27017
注意:
text
127.0.0.1
意味着:
MongoDB 当前只能从服务器本机连接。
这其实是非常安全的默认值。
十七、第一次连接 MongoDB
执行:
bash
mongosh
默认相当于:
bash
mongosh mongodb://127.0.0.1:27017
如果连接成功:
text
test>
查看当前数据库:
javascript
db
结果:
text
test
查看数据库:
javascript
show dbs
十八、MongoDB 最基础 CRUD
切换数据库:
javascript
use javapub
注意 MongoDB 在数据库没有真实数据之前,可能不会真正创建这个数据库。
插入一条用户数据
javascript
db.users.insertOne({
name: "JavaPub",
age: 28,
email: "hello@example.com"
})
结果类似:
javascript
{
acknowledged: true,
insertedId: ObjectId("...")
}
查询
javascript
db.users.find()
格式化:
javascript
db.users.find().pretty()
按条件查询
javascript
db.users.find({
name: "JavaPub"
})
插入多条
javascript
db.users.insertMany([
{
name: "Alice",
age: 20
},
{
name: "Bob",
age: 25
},
{
name: "Tom",
age: 30
}
])
十九、范围查询
年龄大于 20:
javascript
db.users.find({
age: {
$gt: 20
}
})
大于等于:
javascript
db.users.find({
age: {
$gte: 20
}
})
小于:
javascript
db.users.find({
age: {
$lt: 30
}
})
组合:
javascript
db.users.find({
age: {
$gte: 20,
$lte: 30
}
})
二十、修改数据
修改:
javascript
db.users.updateOne(
{
name: "JavaPub"
},
{
$set: {
age: 29
}
}
)
增加字段:
javascript
db.users.updateOne(
{
name: "JavaPub"
},
{
$set: {
website: "https://javapub.net.cn"
}
}
)
二十一、删除
删除一条:
javascript
db.users.deleteOne({
name: "Tom"
})
删除多条:
javascript
db.users.deleteMany({
age: {
$lt: 18
}
})
危险操作:
javascript
db.users.deleteMany({})
这会清空 Collection。
生产环境不要随手执行。
二十二、创建索引
假设经常按 email 查询:
javascript
db.users.createIndex({
email: 1
})
唯一索引:
javascript
db.users.createIndex(
{
email: 1
},
{
unique: true
}
)
查看:
javascript
db.users.getIndexes()
查看执行计划:
javascript
db.users.find({
email: "hello@example.com"
}).explain("executionStats")
二十三、生产环境第一件事:创建管理员账号
如果 MongoDB 只监听:
text
127.0.0.1
安全风险相对有限。
但是如果准备开放网络访问,绝对不要:
text
裸奔 MongoDB
先创建管理员。
进入:
bash
mongosh
切换:
javascript
use admin
创建用户:
javascript
db.createUser({
user: "mongoAdmin",
pwd: "Replace-With-A-Very-Strong-Password",
roles: [
{
role: "root",
db: "admin"
}
]
})
查看:
javascript
db.getUsers()
退出:
javascript
exit
二十四、开启 MongoDB 用户认证
修改:
bash
sudo vim /etc/mongod.conf
增加:
yaml
security:
authorization: enabled
例如完整:
yaml
storage:
dbPath: /var/lib/mongodb
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
net:
port: 27017
bindIp: 127.0.0.1
security:
authorization: enabled
检查 YAML 缩进。
然后:
bash
sudo systemctl restart mongod
查看:
bash
sudo systemctl status mongod
二十五、开启认证以后怎么登录?
不能再直接操作业务数据库。
登录:
bash
mongosh \
"mongodb://mongoAdmin:Replace-With-A-Very-Strong-Password@127.0.0.1:27017/admin"
也可以:
bash
mongosh \
--host 127.0.0.1 \
--port 27017 \
-u mongoAdmin \
-p \
--authenticationDatabase admin
然后终端会让你输入密码。
这种方式比直接把密码写进 Shell History 更安全。
二十六、不要让应用使用 root 用户
这也是非常重要的一点。
不要让你的:
text
Go
Java
Node.js
Python
应用连接 MongoDB 时直接使用:
text
mongoAdmin
应该给每个业务创建自己的用户。
例如:
javascript
use javapub
创建:
javascript
db.createUser({
user: "javapub_app",
pwd: "Replace-With-Another-Strong-Password",
roles: [
{
role: "readWrite",
db: "javapub"
}
]
})
应用只能读写:
text
javapub
数据库。
二十七、应用连接字符串
连接:
text
mongodb://用户名:密码@服务器:27017/数据库?authSource=数据库
例如:
text
mongodb://javapub_app:YOUR_PASSWORD@127.0.0.1:27017/javapub?authSource=javapub
管理员:
text
mongodb://mongoAdmin:YOUR_PASSWORD@127.0.0.1:27017/admin
二十八、密码里有特殊字符怎么办?
假如密码里包含:
text
@
:
/
#
%
不能直接放进 URI。
例如:
text
abc@123
需要 URL Encode:
text
abc%40123
否则:
text
mongodb://user:abc@123@127.0.0.1:27017
解析可能直接出错。
二十九、开启远程访问
MongoDB 默认通常:
yaml
bindIp: 127.0.0.1
如果应用和 MongoDB 不在一台服务器,就需要调整。
修改:
bash
sudo vim /etc/mongod.conf
例如服务器:
text
10.0.0.10
建议:
yaml
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.10
这样只监听:
text
本机
+
内网地址
这是我更加推荐的生产方案。
三十、为什么不推荐直接 0.0.0.0?
你也会在很多教程看到:
yaml
bindIp: 0.0.0.0
它表示:
text
监听所有 IPv4 网络接口
虽然使用方便,但如果云服务器:
text
27017
也同时对公网开放,那安全风险会明显增加。
因此更推荐:
yaml
bindIp: 127.0.0.1,10.0.0.10
配合:
text
VPC / 内网
安全组
防火墙
账号密码
TLS
使用。
三十一、修改 bindIp 后重启
执行:
bash
sudo systemctl restart mongod
检查:
bash
sudo ss -lntp | grep 27017
例如:
text
127.0.0.1:27017
10.0.0.10:27017
三十二、Ubuntu UFW 开放 MongoDB
先查看:
bash
sudo ufw status
假如应用服务器 IP:
text
10.0.0.20
只允许该 IP:
bash
sudo ufw allow from 10.0.0.20 to any port 27017 proto tcp
查看:
bash
sudo ufw status numbered
三十三、不推荐这么干
不要直接:
bash
sudo ufw allow 27017/tcp
如果服务器拥有公网 IP,这可能相当于:
text
允许整个互联网访问 MongoDB
除非外层云安全组已经严格限制。
三十四、CentOS / Rocky Linux / AlmaLinux 防火墙
如果使用 firewalld:
bash
sudo firewall-cmd --state
开放端口:
bash
sudo firewall-cmd \
--permanent \
--add-port=27017/tcp
重新加载:
bash
sudo firewall-cmd --reload
查看:
bash
sudo firewall-cmd --list-ports
不过生产环境依然推荐做 IP 白名单,而不是直接公开整个端口。
三十五、RHEL / Rocky / AlmaLinux 安装 MongoDB
MongoDB 8.0 官方支持:
text
RHEL 8
RHEL 9
CentOS Stream 8/9
Rocky Linux 8/9
AlmaLinux 8/9
对应兼容环境。
以 Rocky Linux 9 为例。
添加 MongoDB Repository
创建:
bash
sudo vim /etc/yum.repos.d/mongodb-org-8.0.repo
写入:
ini
[mongodb-org-8.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://pgp.mongodb.com/server-8.0.asc
这是 MongoDB 官方 RHEL 9 / Rocky 9 安装文档使用的仓库结构。
三十六、安装
执行:
bash
sudo yum install -y mongodb-org
或者:
bash
sudo dnf install -y mongodb-org
启动:
bash
sudo systemctl enable --now mongod
查看:
bash
sudo systemctl status mongod
三十七、检查 SELinux
查看:
bash
getenforce
可能看到:
text
Enforcing
如果你修改了:
text
端口
数据目录
日志目录
就需要额外注意 SELinux 上下文。
不要为了省事直接长期执行:
bash
setenforce 0
生产环境应该正确配置 SELinux,而不是把安全机制整个关掉。
三十八、自定义 MongoDB 数据目录
例如服务器有大容量磁盘:
text
/data
创建:
bash
sudo mkdir -p /data/mongodb
修改所有者:
bash
sudo chown -R mongodb:mongodb /data/mongodb
查看:
bash
ls -ld /data/mongodb
然后修改:
bash
sudo vim /etc/mongod.conf
从:
yaml
storage:
dbPath: /var/lib/mongodb
改成:
yaml
storage:
dbPath: /data/mongodb
三十九、迁移已有数据
如果原目录已有数据,不要直接切目录。
先停服务:
bash
sudo systemctl stop mongod
复制:
bash
sudo rsync -av \
/var/lib/mongodb/ \
/data/mongodb/
修改权限:
bash
sudo chown -R mongodb:mongodb /data/mongodb
修改配置:
yaml
storage:
dbPath: /data/mongodb
启动:
bash
sudo systemctl start mongod
查看:
bash
sudo systemctl status mongod
日志:
bash
sudo tail -f /var/log/mongodb/mongod.log
四十、修改日志目录
创建:
bash
sudo mkdir -p /data/logs/mongodb
授权:
bash
sudo chown -R mongodb:mongodb /data/logs/mongodb
配置:
yaml
systemLog:
destination: file
logAppend: true
path: /data/logs/mongodb/mongod.log
重启:
bash
sudo systemctl restart mongod
四十一、一份比较完整的 mongod.conf
可以参考:
yaml
storage:
dbPath: /data/mongodb
systemLog:
destination: file
logAppend: true
path: /data/logs/mongodb/mongod.log
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.10
security:
authorization: enabled
processManagement:
timeZoneInfo: /usr/share/zoneinfo
如果配置 Replica Set:
yaml
replication:
replSetName: rs0
完整:
yaml
storage:
dbPath: /data/mongodb
systemLog:
destination: file
logAppend: true
path: /data/logs/mongodb/mongod.log
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.10
security:
authorization: enabled
replication:
replSetName: rs0
processManagement:
timeZoneInfo: /usr/share/zoneinfo
四十二、查看 MongoDB Server 状态
进入:
bash
mongosh
执行:
javascript
db.serverStatus()
查看连接:
javascript
db.serverStatus().connections
例如:
javascript
{
current: 12,
available: 838848,
totalCreated: 103
}
查看内存:
javascript
db.serverStatus().mem
查看网络:
javascript
db.serverStatus().network
四十三、查看当前操作
执行:
javascript
db.currentOp()
或者:
javascript
db.currentOp({
active: true
})
可以帮助排查:
text
慢查询
长时间运行任务
阻塞
四十四、查看数据库大小
切换:
javascript
use javapub
执行:
javascript
db.stats()
详细:
javascript
db.stats(1024 * 1024)
单位近似 MB。
查看 Collection:
javascript
db.users.stats()
四十五、MongoDB 备份:mongodump
MongoDB 自带专门的备份工具。
备份:
bash
mongodump \
--uri="mongodb://mongoAdmin:PASSWORD@127.0.0.1:27017/admin" \
--out=/backup/mongodb
更推荐不要直接在命令里暴露密码。
可以交互:
bash
mongodump \
--host=127.0.0.1 \
--port=27017 \
-u=mongoAdmin \
--authenticationDatabase=admin \
--out=/backup/mongodb
四十六、只备份一个数据库
例如:
bash
mongodump \
--uri="mongodb://USER:PASSWORD@127.0.0.1:27017/javapub?authSource=javapub" \
--db=javapub \
--out=/backup/mongodb
目录:
text
/backup/mongodb
└── javapub
├── users.bson
├── users.metadata.json
├── articles.bson
└── articles.metadata.json
四十七、压缩备份
推荐:
bash
mkdir -p /backup
然后:
bash
mongodump \
--uri="mongodb://USER:PASSWORD@127.0.0.1:27017/javapub?authSource=javapub" \
--archive=/backup/javapub.archive \
--gzip
查看:
bash
ls -lh /backup/
四十八、MongoDB 恢复
如果是目录:
bash
mongorestore \
--uri="mongodb://USER:PASSWORD@127.0.0.1:27017/javapub?authSource=javapub" \
/backup/mongodb/javapub
压缩 Archive:
bash
mongorestore \
--uri="mongodb://USER:PASSWORD@127.0.0.1:27017/javapub?authSource=javapub" \
--archive=/backup/javapub.archive \
--gzip
四十九、恢复时覆盖已有 Collection
可以:
bash
mongorestore \
--drop \
--archive=/backup/javapub.archive \
--gzip \
--uri="mongodb://USER:PASSWORD@127.0.0.1:27017/javapub?authSource=javapub"
注意:
text
--drop
会先删除目标 Collection。
生产环境慎用。
五十、写一个每天自动备份脚本
创建:
bash
sudo mkdir -p /opt/scripts
脚本:
bash
sudo vim /opt/scripts/backup-mongodb.sh
写入:
bash
#!/bin/bash
set -e
BACKUP_DIR="/backup/mongodb"
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
FILE="${BACKUP_DIR}/mongodb-${DATE}.archive.gz"
mkdir -p "${BACKUP_DIR}"
mongodump \
--uri="${MONGODB_URI}" \
--archive="${FILE}" \
--gzip
echo "backup success: ${FILE}"
授权:
bash
sudo chmod +x /opt/scripts/backup-mongodb.sh
五十一、不要把数据库密码硬编码进脚本
不要这样:
bash
MONGODB_URI="mongodb://admin:123456@127.0.0.1:27017/admin"
至少可以放环境变量:
bash
export MONGODB_URI='mongodb://...'
执行:
bash
/opt/scripts/backup-mongodb.sh
更正式的生产系统应配合:
text
Secret Manager
Vault
Kubernetes Secret
Docker Secret
systemd EnvironmentFile
管理。
五十二、删除 7 天以前的备份
脚本增加:
bash
find "${BACKUP_DIR}" \
-type f \
-name "*.archive.gz" \
-mtime +7 \
-delete
完整:
bash
#!/bin/bash
set -e
BACKUP_DIR="/backup/mongodb"
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
FILE="${BACKUP_DIR}/mongodb-${DATE}.archive.gz"
mkdir -p "${BACKUP_DIR}"
mongodump \
--uri="${MONGODB_URI}" \
--archive="${FILE}" \
--gzip
find "${BACKUP_DIR}" \
-type f \
-name "*.archive.gz" \
-mtime +7 \
-delete
echo "backup success: ${FILE}"
五十三、配置 Crontab
执行:
bash
crontab -e
每天凌晨 3 点:
cron
0 3 * * * /opt/scripts/backup-mongodb.sh >> /var/log/mongodb-backup.log 2>&1
查看:
bash
crontab -l
五十四、Docker 部署 MongoDB
除了系统安装,我自己也很喜欢用 Docker 跑数据库,尤其是:
text
开发
测试
内部服务
快速部署
先确认:
bash
docker version
五十五、最简单 Docker 启动
执行:
bash
docker run -d \
--name mongodb \
-p 27017:27017 \
mongo
查看:
bash
docker ps
日志:
bash
docker logs -f mongodb
但是这种方式有一个大问题:
text
没有持久化
容器删除以后数据管理会比较麻烦。
五十六、Docker 持久化版本
创建:
bash
mkdir -p /data/mongodb
启动:
bash
docker run -d \
--name mongodb \
--restart unless-stopped \
-p 27017:27017 \
-v /data/mongodb:/data/db \
mongo
五十七、Docker 配置管理员账号
可以使用:
bash
docker run -d \
--name mongodb \
--restart unless-stopped \
-p 27017:27017 \
-v /data/mongodb:/data/db \
-e MONGO_INITDB_ROOT_USERNAME=mongoAdmin \
-e MONGO_INITDB_ROOT_PASSWORD='YOUR_STRONG_PASSWORD' \
mongo
连接:
bash
mongosh \
"mongodb://mongoAdmin:YOUR_STRONG_PASSWORD@127.0.0.1:27017/admin"
五十八、Docker Compose 部署 MongoDB
我更加推荐 Compose。
创建:
bash
mkdir -p /opt/mongodb
进入:
bash
cd /opt/mongodb
创建:
bash
vim docker-compose.yml
写入:
yaml
services:
mongodb:
image: mongo:8.0
container_name: mongodb
restart: unless-stopped
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: mongoAdmin
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
volumes:
- ./data:/data/db
- ./backup:/backup
command:
- mongod
- --auth
- --bind_ip_all
五十九、创建 .env
bash
vim .env
写:
env
MONGO_ROOT_PASSWORD=Replace-With-A-Strong-Password
权限:
bash
chmod 600 .env
启动:
bash
docker compose up -d
查看:
bash
docker compose ps
日志:
bash
docker compose logs -f mongodb
六十、进入 MongoDB Docker 容器
执行:
bash
docker exec -it mongodb bash
然后:
bash
mongosh \
-u mongoAdmin \
-p \
--authenticationDatabase admin
也可以直接:
bash
docker exec -it mongodb \
mongosh \
-u mongoAdmin \
-p \
--authenticationDatabase admin
六十一、Docker Compose 推荐不要直接暴露公网
如果应用本身也运行在 Docker:
yaml
services:
mongodb:
image: mongo:8.0
container_name: mongodb
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: mongoAdmin
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
volumes:
- ./data:/data/db
networks:
- backend
app:
image: myapp:latest
depends_on:
- mongodb
networks:
- backend
networks:
backend:
这里甚至可以:
text
不写 ports
也就是说 MongoDB 不映射:
text
27017
到宿主机公网。
应用直接:
text
mongodb:27017
访问。
这通常更加安全。
六十二、Docker Compose Healthcheck
还可以增加健康检查:
yaml
services:
mongodb:
image: mongo:8.0
container_name: mongodb
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: mongoAdmin
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
volumes:
- ./data:/data/db
healthcheck:
test:
[
"CMD",
"mongosh",
"--quiet",
"--eval",
"db.adminCommand('ping')"
]
interval: 10s
timeout: 5s
retries: 5
查看:
bash
docker inspect mongodb
六十三、MongoDB Ping 测试
Mongo Shell:
javascript
db.adminCommand({
ping: 1
})
返回:
javascript
{
ok: 1
}
六十四、Go 连接 MongoDB
如果你做 Go 后端:
安装驱动:
bash
go get go.mongodb.org/mongo-driver/v2/mongo
示例:
go
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
func main() {
uri := os.Getenv("MONGODB_URI")
if uri == "" {
log.Fatal("MONGODB_URI is empty")
}
ctx, cancel := context.WithTimeout(
context.Background(),
10*time.Second,
)
defer cancel()
client, err := mongo.Connect(
options.Client().
ApplyURI(uri),
)
if err != nil {
log.Fatal(err)
}
defer func() {
if err := client.Disconnect(
context.Background(),
); err != nil {
log.Println(err)
}
}()
if err := client.Ping(
ctx,
nil,
); err != nil {
log.Fatal(err)
}
fmt.Println(
"MongoDB connected",
)
}
环境变量:
bash
export MONGODB_URI='mongodb://javapub_app:PASSWORD@127.0.0.1:27017/javapub?authSource=javapub'
运行:
bash
go run main.go
六十五、Go 插入数据
定义:
go
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
Email string `bson:"email"`
Tags []string `bson:"tags"`
}
插入:
go
collection := client.
Database("javapub").
Collection("users")
user := User{
Name: "JavaPub",
Age: 28,
Email: "hello@example.com",
Tags: []string{
"Go",
"AI",
"Web3",
},
}
result, err := collection.InsertOne(
ctx,
user,
)
if err != nil {
log.Fatal(err)
}
fmt.Println(
"inserted:",
result.InsertedID,
)
六十六、Go 查询
引入:
go
import "go.mongodb.org/mongo-driver/v2/bson"
查询:
go
var user User
err := collection.FindOne(
ctx,
bson.M{
"name": "JavaPub",
},
).Decode(&user)
if err != nil {
log.Fatal(err)
}
fmt.Printf(
"%+v\n",
user,
)
六十七、Go 更新
go
filter := bson.M{
"name": "JavaPub",
}
update := bson.M{
"$set": bson.M{
"age": 29,
},
}
result, err := collection.UpdateOne(
ctx,
filter,
update,
)
if err != nil {
log.Fatal(err)
}
fmt.Println(
"modified:",
result.ModifiedCount,
)
六十八、Go 删除
go
result, err := collection.DeleteOne(
ctx,
bson.M{
"name": "JavaPub",
},
)
if err != nil {
log.Fatal(err)
}
fmt.Println(
"deleted:",
result.DeletedCount,
)
六十九、Python 连接 MongoDB
安装:
bash
pip install pymongo
代码:
python
import os
from pymongo import MongoClient
uri = os.environ["MONGODB_URI"]
client = MongoClient(uri)
db = client["javapub"]
users = db["users"]
result = users.insert_one({
"name": "JavaPub",
"age": 28,
"tags": [
"Go",
"AI",
"Web3"
]
})
print(result.inserted_id)
七十、Node.js 连接 MongoDB
安装:
bash
npm install mongodb
代码:
javascript
const { MongoClient } = require("mongodb");
const uri = process.env.MONGODB_URI;
const client = new MongoClient(uri);
async function main() {
await client.connect();
console.log(
"MongoDB connected"
);
const db =
client.db("javapub");
const users =
db.collection("users");
const result =
await users.insertOne({
name: "JavaPub",
age: 28,
tags: [
"Go",
"AI",
"Web3"
]
});
console.log(
result.insertedId
);
await client.close();
}
main().catch(console.error);
七十一、MongoDB Replica Set 是什么?
单机部署:
text
App
↓
MongoDB
一旦 MongoDB 机器挂了:
text
整个数据库不可用
生产系统通常使用 Replica Set:
text
┌── Secondary
│
App ─ Primary ┼── Secondary
│
└── Secondary
其中:
text
Primary
负责主要写请求
Secondary
复制 Primary 数据
如果 Primary 故障,可以重新选举。
七十二、最简单的单节点 Replica Set
开发环境有时候为了使用:
text
Transaction
Change Stream
会配置单节点副本集。
修改:
bash
sudo vim /etc/mongod.conf
增加:
yaml
replication:
replSetName: rs0
重启:
bash
sudo systemctl restart mongod
登录:
bash
mongosh
初始化:
javascript
rs.initiate()
查看:
javascript
rs.status()
七十三、指定副本集成员
比如服务器:
text
10.0.0.10
可以:
javascript
rs.initiate({
_id: "rs0",
members: [
{
_id: 0,
host: "10.0.0.10:27017"
}
]
})
连接字符串:
text
mongodb://USER:PASSWORD@10.0.0.10:27017/javapub?replicaSet=rs0
七十四、三节点 Replica Set 示例
假设:
text
mongo1 10.0.0.11
mongo2 10.0.0.12
mongo3 10.0.0.13
三台机器:
yaml
replication:
replSetName: rs0
分别启动。
登录其中一台:
bash
mongosh --host 10.0.0.11
执行:
javascript
rs.initiate({
_id: "rs0",
members: [
{
_id: 0,
host: "10.0.0.11:27017"
},
{
_id: 1,
host: "10.0.0.12:27017"
},
{
_id: 2,
host: "10.0.0.13:27017"
}
]
})
查看:
javascript
rs.status()
七十五、副本集连接字符串
应用应该连接多个节点:
text
mongodb://USER:PASSWORD@10.0.0.11:27017,10.0.0.12:27017,10.0.0.13:27017/javapub?replicaSet=rs0
这样驱动可以发现 Primary 切换。
七十六、排查 MongoDB 启动失败
第一步永远是:
bash
sudo systemctl status mongod
然后:
bash
sudo journalctl -u mongod -n 200
再看:
bash
sudo tail -n 200 /var/log/mongodb/mongod.log
七十七、常见问题:Permission denied
比如:
text
Permission denied
先检查:
bash
ls -ld /data/mongodb
正常应该属于:
text
mongodb mongodb
修复:
bash
sudo chown -R mongodb:mongodb /data/mongodb
日志:
bash
sudo chown -R mongodb:mongodb /data/logs/mongodb
七十八、常见问题:Address already in use
日志出现:
text
Address already in use
检查:
bash
sudo ss -lntp | grep 27017
或者:
bash
sudo lsof -i :27017
可能已经有:
text
另一个 MongoDB
Docker MongoDB
其他程序
占用了端口。
七十九、查看 Docker 是否占用 27017
bash
docker ps \
--format 'table {{.Names}}\t{{.Ports}}'
如果看到:
text
0.0.0.0:27017->27017/tcp
说明 Docker 已经用了这个端口。
八十、常见问题:远程无法连接
先看:
bash
sudo ss -lntp | grep 27017
如果:
text
127.0.0.1:27017
说明 bindIp 没改。
检查:
bash
grep -A 5 '^net:' /etc/mongod.conf
应该类似:
yaml
net:
port: 27017
bindIp: 127.0.0.1,10.0.0.10
八十一、从另一台机器测试端口
可以:
bash
nc -vz 10.0.0.10 27017
成功:
text
Connection to 10.0.0.10 27017 port [tcp/*] succeeded!
如果失败,要继续排查:
text
MongoDB bindIp
Linux Firewall
云服务器安全组
VPC 路由
公网 / 内网 IP
八十二、生产环境不要只看"能不能连接"
MongoDB 真正上线时,建议至少考虑下面这些:
text
1. 用户认证
2. 最小权限
3. 内网访问
4. 防火墙
5. 云安全组
6. 数据备份
7. Replica Set
8. 磁盘空间监控
9. CPU / 内存监控
10. 慢查询
11. 日志
12. TLS
13. 数据恢复演练
尤其是:
有备份,不代表能恢复。
一定要定期实际执行:
bash
mongorestore
验证。
八十三、推荐的生产拓扑
对于一个普通中小型项目,我更加推荐:
text
Internet
│
▼
Nginx / API
│
▼
Application
│
│ Private Network
▼
MongoDB
而不是:
text
Internet
│
▼
MongoDB :27017
数据库原则上不应该直接面向公网用户。
八十四、生产环境安全组示例
MongoDB Server:
text
10.0.0.10
Application:
text
10.0.0.20
安全组规则只允许:
text
Source:
10.0.0.20
Protocol:
TCP
Port:
27017
而不是:
text
0.0.0.0/0
27017
八十五、推荐部署方式怎么选?
如果是:
text
本地学习
可以:
bash
docker run
如果:
text
开发 / 测试环境
推荐:
text
Docker Compose
如果:
text
普通生产服务器
可以:
text
APT / YUM
+
systemd
如果:
text
高可用正式业务
考虑:
text
Replica Set
+
监控
+
自动备份
+
TLS
+
内网
如果不想自己维护:
text
MongoDB Atlas
也是另一条路线。
八十六、一套 Ubuntu 快速安装命令
如果就是一台 Ubuntu 24.04 测试服务器,前面所有安装步骤可以浓缩成:
bash
sudo apt update
sudo apt install -y \
curl \
gnupg
curl -fsSL \
https://pgp.mongodb.com/server-8.0.asc \
| sudo gpg \
-o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
echo \
"deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" \
| sudo tee \
/etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update
sudo apt install -y \
mongodb-org
sudo systemctl \
enable \
--now \
mongod
sudo systemctl \
status \
mongod
然后:
bash
mongosh
测试:
javascript
db.adminCommand({
ping: 1
})
如果:
javascript
{
ok: 1
}
说明 MongoDB 已经正常运行。
八十七、一套生产环境部署思路
真正生产使用时,可以按照:
text
Step 1
安装 MongoDB
↓
Step 2
规划独立数据盘
/data/mongodb
↓
Step 3
创建管理员
mongoAdmin
↓
Step 4
开启 authorization
↓
Step 5
给应用创建独立 readWrite 用户
↓
Step 6
只监听内网地址
127.0.0.1,10.x.x.x
↓
Step 7
安全组仅允许应用服务器
↓
Step 8
配置 Replica Set
↓
Step 9
mongodump 定时备份
↓
Step 10
监控磁盘、连接数、CPU、内存、慢查询
八十八、最后总结
Linux 部署 MongoDB 本身并不复杂。
真正基础的安装可能只有几条:
bash
apt install mongodb-org
启动:
bash
systemctl start mongod
连接:
bash
mongosh
但如果是生产环境,真正重要的往往不是:
text
MongoDB 能不能启动
而是:
text
谁可以访问?
服务暴露在哪里?
密码和权限是否合理?
机器挂了怎么办?
磁盘满了怎么办?
数据删错了怎么办?
备份真的能恢复吗?
Primary 挂了怎么办?
所以一套相对完整的 MongoDB 部署,应该至少包含:
text
MongoDB
│
├── 安装
│
├── systemd
│
├── 数据目录
│
├── 日志
│
├── Authentication
│
├── 最小权限
│
├── bindIp
│
├── Firewall
│
├── Backup
│
├── Restore
│
├── Replica Set
│
└── Monitoring
对于个人项目、小型项目或者内部系统:
text
Docker Compose
+
持久化 Volume
+
用户认证
+
内网访问
+
定时备份
基本已经能够覆盖很多需求。
而一旦 MongoDB 承载核心业务,就应该进一步考虑:
text
Replica Set
TLS
监控告警
异地备份
恢复演练
容量规划
数据库部署从来不是:
把服务跑起来就结束了。
真正可靠的数据库系统,是在服务器故障、网络异常、操作失误甚至数据损坏发生以后,依然有办法把业务恢复回来。
现在是最好的时代。中国有全世界最高性价比的制造业,有发达的网络和全球物流。
只要你愿意,你几乎可以买到这个世界上任何地方生产的、任何你想要的商品。你可以用很低的成本,撬动全球的资源为你服务。
不过,真正稀缺的,从来不是商品,而是注意力、判断力,以及把事情做成的能力。
所以,这是最好的时代,也是最坏的时代。
我是王仕宇,关注 AI、Web3 与开源,持续探索如何把技术做成产品,把产品转化为真实价值。