Linux 下部署 MongoDB:从安装、配置到生产环境使用

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 与开源,持续探索如何把技术做成产品,把产品转化为真实价值。

相关推荐
我不会插花弄玉1 小时前
11.Linux进程信号【由浅入深-Linux】
linux·进程·信号
画中有画2 小时前
自动化脚本中如何启动/打开app的某个页面
运维·自动化
Brilliantwxx2 小时前
【Linux】 进程(3)深度解析:从查看进程到进程状态
linux·服务器·网络·c++
我星期八休息2 小时前
Linux—五种IO模型与非阻塞IO
linux·运维·服务器·网络·数据库·网络协议
hweiyu003 小时前
Linux命令:column
linux·运维·服务器
Csxyzj3 小时前
kubernetes集群部署方法
java·linux·kubernetes
深念Y3 小时前
OnlyOffice 打开来自 Windows/WPS 的 Office 文档时,出现排版错乱、文字空白、字体显示异常。
linux·windows·debian·onlyoffice·字体·wps·office
ShineWinsu3 小时前
对于 C++:C++20中Concept(概念) 与 Coroutine(协程)的解析
linux·开发语言·网络·c++·c++20·epoll
日常筹谋记3 小时前
ATS选不对运维两行泪:数据中心市电与柴发切换场景的双电源自动转换开关选型笔记
运维·数据库·笔记