Этот пост будет посвящен установке MongoDB, посмотрим на различные варианты в single-instance, replicaset.
MongoDB
- это документориентированная СУБД, для хранения информации в json-подобных структурах BSON
(Binary json). Монга написана на C++
, использует mmap и имеет javascript-like язык запросов.
Установка mongoDB
Процесс установки монги достаточно тривиальный, и не требует продолжительных подготовок. В этом разделе будем ставить сервис на одиночный сервер, под управлением RockyLinux 8.5.
Идем на сайт монги, копируем конфиг репозитория. Подключаемся на сервер, создаем новый репозиторий.:
[root@mongodb-single ~]# vim /etc/yum.repos.d/mongodb-6.repo
--
[mongodb-org-6.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/6.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc
После устанавливаем пакет:
[root@mongodb-single ~]# yum install mongodb-org
Запускаем сервис:
[root@mongodb-single ~]# systemctl enable mongod --now
По умолчанию, любой пользователь имеет доступ к функциям mongoDB и мы без проблем сможем подключиться к базе через клиент. Поэтому добавим супер-пользователя, и глобально включим авторизацию. Для этого через консоль подключаемся к монге (утилита - mongosh):
[root@mongodb-single ~]# mongosh
Внутри монги, переключаемся на базу - admin
:
use admin
И выполняем запрос на добавление админ-пользователя:
db.createUser(
{
user: "mongoadmin",
pwd: "password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
Отредактируем конфиг mongoDB:
[root@mongodb-single ~]# vim /etc/mongod.conf
--
# Директивы сокета, с которого монга слушает запросы
net:
port: 27017
bindIp: 0.0.0.0
# Включение авторизации
security:
authorization: enabled
Сохраняемся и перезапускаем сервис:
[root@mongodb-single ~]# systemctl restart mongod
Не забываем открыть порт на фаерволе:
[root@mongodb-single ~]# firewall-cmd --add-port=27017/tcp --permanent
[root@mongodb-single ~]# firewall-cmd --reload
Теперь если мы подключимся из под консоли и выполнил команду, то сервер попросит нас авторизоваться:
[root@mongodb-single ~]# mongosh
---
test> show dbs
MongoServerError: command listDatabases requires authentication
Чтобы авторизоваться на сервере, нужно выполнить несколько действий:
# Переключиться на admin базу
test> use admin
switched to db admin
# Авторизоваться в базе
admin> db.auth("mongoadmin", "password")
{ ok: 1 }
Ну и после можем просмотреть список текущий баз:
admin> show dbs
admin 100.00 KiB
config 108.00 KiB
local 72.00 KiB
Для подключения с локального компьютера, я буду использовать программу MongoDB Atlas
.
В клиенте указываем строку подключения, и коннектимся:
Удаление mongoDB
В процессе пока ковырялся с монгой, мне удалось несколько раз сломать ее. И по итогу ее приходилось удалять по нескольку раз. Ниже будут представлены комманды, для зачистки сервера от монго.
# Выключаем сервис
[root@mongodb-single ~]# systemctl disable --now mongod
Removed /etc/systemd/system/multi-user.target.wants/mongod.service.
# Затераем пакет и его зависимости
[root@mongodb-single ~]# yum erase $(rpm -qa | grep mongodb-org)
# Удаляем каталог монги в либах
[root@mongodb-single ~]# rm -rf /var/lib/mongo
# Удаляем логи
[root@mongodb-single ~]# rm -rf /var/log/mongodb/
Установка mongoDB (ReplicaSet)
mongoDB уже из коробки имеет фичи по redundancy и high availability, так называемый набор реплик - Replicaset
. Replicaset - это несколько экземпляров mongod
, c одинаковым набором данных. В таком кластере может быть только она главная нода (primary), и две второстепенные ноды (secondary). Все операции записи осуществляются основной (primary) нодой, вторичные ноды копируют себе oplog
(operation log) c основной ноды и применяют изменения к своим данным.
В случаи если основная нода стала недоступной, то экземпляры вторичных реплик проведут переизбрание основной ноды.
Если есть ограничение (например, по стоимости) на количество реализуемых экзепляров реплик. И в кластере мы имеем только одну основную и вторичную ноду. То, дабы не нарушать кворум кластере добавляется еще один экземпляр mongodb в роли арбитера. Артибер только участвует в перевыборе нового мастера и не хранит наборы данных.
В нашей исталяции мы будем использовать 3 сервера с mongoDB (1 - Primary, 2 - Secondary).
Server name | IP | Role |
---|---|---|
mongodb01 | 192.168.190.73 | Primary server |
mongodb02 | 192.168.190.74 | Secondary server |
mongodb03 | 192.168.190.75 | Secondary server |
На все три тачки подкивываем репозиторий от mongoDB:
(All servers)# vi /etc/yum.repos.d/mongo6.repo
(All servers)# yum install mongodb-org -y
Теперь прежде чем мы начнем инициализировать кластер, создадим двоих пользователей. Один пользователь mongo-admin
будем иметь права на создание пользователей и назначению их ролей. Второй пользователь mongo-root
будет иметь все привилегии.
Запускаем сервер монги на основном сервере, и подключаемся к консоли монги:
[root@mongodb01 ~]# systemctl enable --now mongod
Подключаемся к монге и создаем пользователей:
[root@mongodb01 ~]# mongosh
--
# Переключаемся на базу admin
test> use admin
# Создаем пользователя mongo-admin
db.createUser(
{
user: "mongo-admin",
pwd: "passw0rd",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
# Создаем пользователя mongo-root
db.createUser(
{
user: "mongo-root",
pwd: "passw0rd",
roles: [ { role: "root", db: "admin" } ]
}
)
Перейдем к созданию кластера. Для обеспечения безопасности взаимодействия между нодами, мы будем использовать механизм аутентификации по ключу. Создадим специальный файл, и раскидаем его на сервера. Создаем файл на основной ноде
# Каталог под хранение ключа
[root@mongodb01 ~]# mkdir -p /etc/mongodb/keys/
# Генерим ключ
[root@mongodb01 ~]# openssl rand -base64 756 > /etc/mongodb/keys/mongo-key
# Даем права на чтение только пользователю
[root@mongodb01 ~]# chmod 400 /etc/mongodb/keys/mongo-key
# Меняем владельца на mongo
[root@mongodb01 ~]# chown -R mongod:mongod /etc/mongodb
Созданный ключ копируем на второстепенные ноды:
[root@mongodb01 ~]# scp -r /etc/mongodb root@192.168.190.74:/etc
[root@mongodb01 ~]# scp -r /etc/mongodb root@192.168.190.75:/etc
Переключаемся на ноды 02, 03 и меняем владельца ключа:
(Secondary nodes)# chown -R mongod:mongod /etc/mongodb/
Отредактруем конфиг mongodb на серверах:
# На основной ноде
net:
port: 27017
bindIp: 127.0.0.1,192.168.190.73
security:
authorization: enabled
keyFile: /etc/mongodb/keys/mongo-key
replication:
replSetName: "replicaset01"
# На второй ноде
net:
port: 27017
bindIp: 127.0.0.1,192.168.190.74
security:
authorization: enabled
keyFile: /etc/mongodb/keys/mongo-key
replication:
replSetName: "replicaset01"
# На третьей ноде
net:
port: 27017
bindIp: 127.0.0.1,192.168.190.75
security:
authorization: enabled
keyFile: /etc/mongodb/keys/mongo-key
replication:
replSetName: "replicaset01"
В конфигурационном файле прописываем поля:
net
- здесь в значениях указывается порт и адрес, на котором монга слушает все соединения;security
- в этом поле мы включаем авторизацию, и указываем ключ для авторизации нод в кластере.replication
- этот блок описывает состояние нашего кластера, но в нашем случаи описание достаточно скудное. Мы указываем только название нашей реплики.
Перед запуском сервиса, не забываем открыть порт на фаерале:
(All servers)# firewall-cmd --add-port=27017/tcp --permanent
(All servers)# firewall-cmd --reload
Запускаем сервис на всех серверах:
(All servers)# systemctl enable --now mongod
Подключаемся к консоли монги, и авторизируемся из под пользователя mongo-root
, только у него есть права для работы с кластером.
[root@mongodb01 ~]# mongosh
---
# Переключаемся на базу admin
test> use admin
# Авторизуемся в базе
admin> db.auth("mongo-root", "passw0rd")
{ ok: 1 }
Проинициализируем кластер:
# Объявляем кластер
admin> rs.initiate()
{
info2: 'no configuration specified. Using a default configuration for the set',
me: '192.168.190.73:27017',
ok: 1
}
# Добавляем вторую ноду
replicaset01 [direct: primary] admin> rs.add("192.168.190.74:27017")
{
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1675081615, i: 1 }),
signature: {
hash: Binary(Buffer.from("11cc794f49ca144cc6de0813b5aa1f3630ee8638", "hex"), 0),
keyId: Long("7194420393778610182")
}
},
operationTime: Timestamp({ t: 1675081615, i: 1 })
}
# Добавляем третью ноду
replicaset01 [direct: primary] admin> rs.add("192.168.190.75:27017")
{
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1675081642, i: 1 }),
signature: {
hash: Binary(Buffer.from("b39074d22f4ff58cdf83294f3e21cd0617cc013a", "hex"), 0),
keyId: Long("7194420393778610182")
}
},
operationTime: Timestamp({ t: 1675081642, i: 1 })
}
Отлично, на этом все =)
Для просмотра статуса репликасета, можно воспользоваться командой:
replicaset01 [direct: primary] admin> rs.status()
Команды вернет нам длинный вывод в json, содержащий параметры репликасета и наши наборы реплик.
Для просмотра конфиги набора реплик, можно заюзать камонду:
replicaset01 [direct: primary] admin> rs.conf()
Для теста, давайте создадим базу, и пользователя с ролью на эту базу.
# Создаем базу:
replicaset01 [direct: primary] admin> use appdb
# Добавляем нового пользователя
replicaset01 [direct: primary] appdb> db.createUser( { user: "user_app", pwd: "pwdpwd", roles: [{ role: "readWrite", db: "appdb" }] })
{
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1675082639, i: 1 }),
signature: {
hash: Binary(Buffer.from("b9b427b60a90dea4942519bf6b52b5ed2a0c0785", "hex"), 0),
keyId: Long("7194420393778610182")
}
},
operationTime: Timestamp({ t: 1675082639, i: 1 })
}
Для теста, можем попробоваться подключится к кластеру через Altas. В новом подключении, я указываю все 3 сервера.
А во вкладке Authentication
указываю логин/пароль пользователя и базу:
Жмем Save & Connect
:
На этом все, задачу можно считать реализованной.
Я решил не делать из этой заметки простыню и написать про запуск монги в докере в следующей заметке. Как раз одном проекте уже назревает необходимость такой миграции.