一、环境
mongodb 3.4.24
二、安装
添加运行 mongodb 的用户 mongo,避免直接使用 root 带来安全隐患
groupadd -g 1608 mongo
useradd -u 1608 -g mongo mongo
下载源码包
wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.4.24.tgz
解压源码包
tar -xf mongodb-linux-x86_64-rhel70-3.4.24.tgz -C /usr/local/
准备 mongodb 配置文件
mkdir /data/mongodb/{data,logs} -p
mkdir /usr/local/mongodb/conf
添加到环境里面
vim /etc/profile
export MONGODB_HOME=/usr/local/mongodb
export PATH=$MONGODB_HOME/bin:$PATH
三、集群搭建
此次搭建为 mongo * 1、3 shard * 3、1 config * 3
目录及配置使用
configsvr 的三个节点的数据目录和日志目录
/home/mongodb/config1/data
/home/mongodb/config1/log
/home/mongodb/config2/data
/home/mongodb/config2/log
/home/mongodb/config3/data
/home/mongodb/config3/log
/home/mongodb/shard11/data
/home/mongodb/shard11/log
/home/mongodb/shard12/data
/home/mongodb/shard12/log
/home/mongodb/shard13/data
/home/mongodb/shard13/log
/home/mongodb/shard21/data
/home/mongodb/shard21/log
/home/mongodb/shard22/data
/home/mongodb/shard22/log
/home/mongodb/shard23/data
/home/mongodb/shard23/log
/home/mongodb/shard31/data
/home/mongodb/shard31/log
/home/mongodb/shard32/data
/home/mongodb/shard32/log
/home/mongodb/shard33/data
/home/mongodb/shard33/log
mongos 节点的日志目录
/home/mongodb/mongos/log
搭建 configsvr 副本集
1. 准备单节点配置文件和数据目录,以单节点方式启动进程。
net:
bindIp: 0.0.0.0
port: 21001
unixDomainSocket: {enabled: false}
processManagement: {fork: true, pidFilePath: /home/mongodb/config1/configsvr.pid}
storage:
dbPath: /home/mongodb/config1/data/
directoryPerDB: true
engine: wiredTiger
wiredTiger:
collectionConfig: {blockCompressor: snappy}
engineConfig: {directoryForIndexes: true, journalCompressor: snappy}
indexConfig: {prefixCompression: true}
systemLog: {destination: file, logAppend: true, logRotate: reopen, path: /home/mongodb/config1/log/configsvr.log}
启动进程mongod -f config1.conf
- 连接单节点,执行配置命令。
执行如下命令,修改副本集配置信息。var cf=db.getSiblingDB('local').system.replset.findOne();
cf['members'][0]['host']='127.0.0.1:21001';
cf['members'][1]['host']='127.0.0.1:21002';
cf['members'][2]['host']='127.0.0.1:21003';
cf['members'][0]['hidden']=false;
cf['members'][1]['hidden']=false;
cf['members'][2]['hidden']=false;
cf['members'][0]['priority']=1;
cf['members'][1]['priority']=1;
cf['members'][2]['priority']=1;
db.getSiblingDB('local').system.replset.remove({});
db.getSiblingDB('local').system.replset.insert(cf)
执行如下命令,清理内置账号。(新搭建的无需此操作)
db.getSiblingDB('admin').dropAllUsers();
db.getSiblingDB('admin').dropAllRoles();
执行如下命令,更新 mongos 和 shard 信息。db.getSiblingDB('config').mongos.remove({});
先查询 config.shards 表中的多个 shard 的_id 信息,用于下面语句的_id 的查询条件。逐个更新每条记录。db.getSiblingDB('config').shards.update({'_id' : 'shard_1'},{$set: {'host': 'shard_1/127.0.0.1:27001,127.0.0.1:27002,127.0.0.1:27003'}})
db.getSiblingDB('config').shards.update({'_id' : 'shard_2'},{$set: {'host': 'shard_2/127.0.0.1:27004,127.0.0.1:27005,127.0.0.1:27006'}})
db.getSiblingDB('config').shards.update({'_id' : 'shard_3'},{$set: {'host': 'shard_3/127.0.0.1:27007,127.0.0.1:27008,127.0.0.1:27009'}})
db.getSiblingDB('config').mongos.find({});
db.getSiblingDB('config').shards.find({});
执行如下命令,关闭单节点进程
db.getSiblingDB('admin').shutdownServer();
3. 搭建 configsvr 副本集
准备副本集配置文件和目录,将 configsvr1 节点的 dbPath 文件拷贝到其他两个节点目录下。
cp -aR /home/mongodb/config1/data /home/mongodb/config2/data
cp -aR /home/mongodb/config1/data /home/mongodb/config3/data
修改 configsvr- 1 节点配置文件,增加副本集配置属性
net:
bindIp: 0.0.0.0
port: 21001
unixDomainSocket: {enabled: false}
processManagement: {fork: true, pidFilePath: /home/mongodb/config1/configsvr.pid}
replication: {replSetName: config}
sharding: {archiveMovedChunks: false, clusterRole: configsvr}
storage:
dbPath: /home/mongodb/config1/data/
directoryPerDB: true
engine: wiredTiger
wiredTiger:
collectionConfig: {blockCompressor: snappy}
engineConfig: {directoryForIndexes: true, journalCompressor: snappy}
indexConfig: {prefixCompression: true}
systemLog: {destination: file, logAppend: true, logRotate: reopen, path: /home/mongodb/config1/log/configsvr.log}
启动进程mongod -f config1.conf
修改 configsvr- 2 节点配置文件,增加副本集配置属性 复制 config1 配置文件,修改端口信息、数据和日志文件的路径
启动进程(configsvr3 类似)mongod -f config2.conf
mongod -f config3.conf
等待选主成功。
./mongo –host 127.0.0.1 –port 21001
执行命令 rs.status(),查看是否已存在主节点 Primary。
- 准备单节点配置文件和目录,以单节点方式启动进程。
net:
bindIp: 0.0.0.0
port: 27001
unixDomainSocket: {enabled: false}
processManagement: {fork: true, pidFilePath: /home/mongodb/shard11/log/shard11.pid}
storage:
dbPath: /home/mongodb/shard11/data/
directoryPerDB: true
engine: wiredTiger
wiredTiger:
collectionConfig: {blockCompressor: snappy}
engineConfig: {directoryForIndexes: true, journalCompressor: snappy}
indexConfig: {prefixCompression: true}
systemLog: {destination: file, logAppend: true, logRotate: reopen, path: /home/mongodb/shard11/log/shard11.log}
mongod -f shard11.conf
- 连接单节点,修改副本集配置信息
连接命令 /mongo --host 127.0.0.1 --port 27001
执行如下命令,修改副本集配置信息。var cf=db.getSiblingDB('local').system.replset.findOne();
cf['members'][0]['host']='127.0.0.1:27001';
cf['members'][1]['host']='127.0.0.1:27002';
cf['members'][2]['host']='127.0.0.1:27003';
cf['members'][0]['hidden']=false;
cf['members'][1]['hidden']=false;
cf['members'][2]['hidden']=false;
cf['members'][0]['priority']=1;
cf['members'][1]['priority']=1;
cf['members'][2]['priority']=1;
db.getSiblingDB('local').system.replset.remove({});
db.getSiblingDB('local').system.replset.insert(cf)
db.getSiblingDB('admin').dropAllUsers();
db.getSiblingDB('admin').dropAllRoles();
var vs = db.getSiblingDB('admin').system.version.find();
while (vs.hasNext()) {var curr = vs.next();
if (curr.hasOwnProperty('configsvrConnectionString')) {db.getSiblingDB('admin').system.version.update({'_id' : curr._id}, {$set: {'configsvrConnectionString': 'config/127.0.0.1:21001,127.0.0.1:21002,127.0.0.1:21003'}});
}
}
执行如下命令,关闭单节点进程。db.getSiblingDB('admin').shutdownServer();
- 搭建 shardsvr1 副本集。
准备副本集配置文件和目录,将 shardsvr1 节点的 dbPath 文件拷贝到其他两个节点目录下。
cp -aR /home/mongodb/shard11/data /home/mongodb/shard12/data
cp -aR /home/mongodb/shard11/data /home/mongodb/shard13/data
修改 shardsvr1- 1 节点配置文件,增加副本集配置属性。
net:
bindIp: 0.0.0.0
port: 27001
unixDomainSocket: {enabled: false}
processManagement: {fork: true, pidFilePath: /home/mongodb/shard11/log/shard11.pid}
replication: {replSetName: shard_1}
sharding: {archiveMovedChunks: false, clusterRole: shardsvr}
storage:
dbPath: /home/mongodb/shard11/data/
directoryPerDB: true
engine: wiredTiger
wiredTiger:
collectionConfig: {blockCompressor: snappy}
engineConfig: {directoryForIndexes: true, journalCompressor: snappy}
indexConfig: {prefixCompression: true}
systemLog: {destination: file, logAppend: true, logRotate: reopen, path: /home/mongodb/shard11/log/shard11.log}
启动进程 mongod -f shard11.conf
复制 shardsvr1- 1 节点配置文件为 shard12.conf、shard13.conf
,修改 shardsvr1-2、shardsvr1- 3 节点文件 修改端口,数据和日志的存储路径
启动进程mongod -f shard12.conf
mongod -f shard13.conf
等待选主成功。
./mongo –host 127.0.0.1 –port 27001
执行命令 rs.status(),查看是否已存在主节点 Primary。
shardsvr2、shardsvr3 步骤省略,参考 shardsvr1 搭建步骤
mongos 节点搭建
准备 mongos 节点的配置文件和目录。/home/mongodb/mongos/log
配置文件
net:
bindIp: 0.0.0.0
port: 20000
unixDomainSocket: {enabled: false}
processManagement: {fork: true, pidFilePath: /home/mongodb/mongos/log/mongos.pid}
sharding: {configDB: 'config/127.0.0.1:21001,127.0.0.1:21002,127.0.0.1:21003'}
systemLog: {destination: file, logAppend: true, logRotate: reopen, path: /home/mongodb/mongos/log/mongos.log}
启动 mongo 节点mongos -f mongos.conf
mongodb shard 节点和 config 节点的数据恢复
- 将实例的备份文件下载到服务器上,例:configsvr 的数据一个,三个分片的数据
- mongodb 服务全部停止,config1 上面的原本数据删除,将备份文件拷贝进去,测试启动 config1 是否成功
- 将 config1 拷贝到副本集里面,启动副本集,正常启动后,依照上述方法将分片数据替换后启动
mongo 安全
对于搭建好的 mongodb 副本集加分片集群,为了安全,启动安全认证,使用账号密码登陆
默认的 mongodb 是不设置认证的。只要 ip 和端口正确就能连接,这样是不安全的。mongodb 官网上也说,为了能保障 mongodb 的安全可以做以下几个步骤:
使用新的端口,默认的 27017 端口如果一旦知道了 ip 就能连接上,不太安全
设置 mongodb 的网络环境,最好将 mongodb 部署到公司服务器内网,这样外网是访问不到的。公司内部访问使用 vpn 等
开启安全认证。认证要同时设置服务器之间的内部认证方式,同时要设置客户端连接到集群的账号密码认证方式
环境以上述环境为例:
对副本集执行访问控制需要配置两个方面:
副本集和共享集群的各个节点成员之间使用内部身份验证,可以使用密钥文件或 x.509 证书。密钥文件比较简单,本文介绍的也是使用密钥文件,官方推荐如果是测试环境可以使用密钥文件,但是正是环境,官方推荐 x.509 证书。原理就是,集群中每一个实例彼此连接的时候都检验彼此使用的证书的内容是否相同。只有证书相同的实例彼此才可以访问
使用客户端连接到 mongodb 集群时,开启访问授权。对于集群外部的访问。如通过可视化客户端,或者通过代码连接的时候,需要开启授权。
下面开始说明:
1、生成密钥文件
1.1 在 keyfile 身份验证中,副本集中的每个 mongod 实例都使用 keyfile 的内容作为共享密码,只有具有正确密钥文件的 mongod 或者 mongos 实例可以连接到副本集。密钥文件的内容必须在 6 到 1024 个字符之间,并且在 unix/linux 系统中文件所有者必须有对文件至少有读的权限。
1.2 可以用任何方式生成密钥文件例如:
第一条命令是生成密钥文件,第二条命令是使用 chmod 更改文件权限,为文件所有者提供读权限
openssl rand -base64 756 > /usr/local/mongodb/conf/KeyFile.file
chmod 400 /usr/local/mongodb/conf/KeyFile.file
2、将密钥复制到集群中的每台机器的指定位置
2.1 一定要保证密钥文件一致。文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置
3、预先创建好一个管理员账号和密码然后将集群中的所有 mongod 和 mongos 全部关闭
账号可以在集群认开启认证以后添加。但是那时候添加比较谨慎。只能添加一次,如果忘记了就无法再连接到集群。建议在没开启集群认证的时候先添加好管理员用户名和密码然后再开启认证再重启
连接任意一台机器的 mongos
mongo --port 20000
添加用户
use admin;
db.createUser(
{
user:"root",
pwd:"cFCD37datarrubb99211ca",
roles:[{role:"root",db:"admin"}]
}
)
然后依次连接到每一台机器上执行。
killall mongod
killall mongos
然后删除每个 mongod 实例存储数据存储路径下面的 mongod.lock(如果后面启动不报错可以不处理); 也可以连接到每台的端口
执行命令db.getSiblingDB('admin').shutdownServer();
3.1 可以发现。集群多少有的节点都关闭了。没开启认证的集群如果开启认证需要集群宕机几分钟。当然也有热启动的方式,官方文档中有介绍
说明:可以先开启认证重启后再添加用户。但是只能在 admin 库添加一次,所以如果忘记了,或者权限分配不恰当就无法再更改,所以建议先添加用户再开启认证重启,并且集群不建议在每个单节点添加用户,并且建议单节点关闭初始添加账号的权限,详情见 enableLocalhostAuthBypass)
4、使用访问控制强制重新启动复制集的每个成员
4.1 依次在每台机器上的 mongod(注意是所有的 mongod 不是 mongos)的配置文件中加入下面一段配置。
如 config server,shard1,shard2,shard3 都加入下面的配置文件
security:
keyFile: /usr/local/mongodb/conf/KeyFile.file
authorization: enabled
4.2 依次在每台机器上的 mongos 配置文件中加入下面一段配置。
security:
keyFile: /usr/local/mongodb/conf/KeyFile.file
解释:
mongos 比 mongod 少了 authorization:enabled 的配置。原因是,副本集加分片的安全认证需要配置两方面的,副本集各个节点之间使用内部身份验证,用于内部各个 mongo 实例的通信,只有相同 keyfile 才能相互访问。所以都要开启 keyFile: /usr/local/mongodb/conf/KeyFile.file
然而对于所有的 mongod,才是真正的保存数据的分片。mongos 只做路由,不保存数据。所以所有的 mongod 开启访问数据的授权 authorization:enabled。这样用户只有账号密码正确才能访问到数据
重启每个 mongo 示例
5、连接 mongodb 集群
如果用 mongo sell 脚本连接
mongo –port 20000
use admin
db.auth(“your account”,”your password”)
如果返回 1 表示连接成功,然后你就可以访问自己的数据库