Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

FERRET

Ferret, the mongo over postgres

MongoDB has lost its open-source appeal and is no longer suitable for many cases. In contrast, PostgreSQL offers robust, native JSON support and outperforms MongoDB as a document database.

Thus, FerretDB provides a mongo wire-protocol-compatible layer upon postgres, enabling MongoDB users to migrate smoothly to PostgreSQL’s superior platform. FERRET is an OPTIONAL module in Pigsty. It requires the documentdb extensions to work since v2.0.

Pigsty has packaged that and provides a mongo.yml template to help you deploy a FerretDB cluster with ease.

Configuration
    Configure ferret module, and use multiple ferret nodes.
Parameters
    Customize ferret components with 15 parameters
Administration
    Create, remove, expand, shrink, upgrade ferret cluster
Playbooks
    Ansible playbooks that can be used in this module
Monitoring
    Dashboards, metrics, record & alerting rules.
Usage
    How to use the mcli and configure backup repo

1 - Usage

Connect to FerretDB with client tools

Install Client Tools

You can use MongoDB’s command-line tool MongoSH to access FerretDB.

Use the pig command to add MongoDB repository, then install mongosh using yum or apt:

pig repo add mongo -u
yum install mongodb-mongosh
apt install mongodb-mongosh

Connect to FerretDB

You can access FerretDB using MongoDB connection strings with any MongoDB driver in any language. Here’s an example using the mongosh CLI tool:

$ mongosh
Current Mongosh Log ID:	67ba8c1fe551f042bf51e943
Connecting to:		mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.0
Using MongoDB:		7.0.77
Using Mongosh:		2.4.0

For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/

test>

Authentication

You can log in with different users. See FerretDB: Authentication for details.

mongosh 'mongodb://dbuser_meta:[email protected]:27017/meta'      # Business admin user
mongosh 'mongodb://dbuser_view:[email protected]:27017/meta'    # Read-only user

Quick Start

You can connect to FerretDB and use it as if it were a MongoDB cluster.

$ mongosh 'mongodb://dbuser_meta:[email protected]:27017/meta'

MongoDB commands are translated to SQL and executed in the underlying PostgreSQL:

use test                            // CREATE SCHEMA test;
db.dropDatabase();                  // DROP SCHEMA test;
db.createCollection('posts');       // CREATE TABLE posts(_data JSONB,...)
db.posts.insertOne({                // INSERT INTO posts VALUES(...);
    title: 'Post One',body: 'Body of post one',category: 'News',tags: ['news', 'events'],
    user: {name: 'John Doe',status: 'author'},date: Date()}
);
db.posts.find().limit(2).pretty();  // SELECT * FROM posts LIMIT 2;
db.posts.createIndex({ title: 1 })  // CREATE INDEX ON posts(_data->>'title');

If you’re not familiar with MongoDB, here’s a quick tutorial that works with FerretDB: Perform CRUD Operations with MongoDB Shell

To generate sample workload, you can use this simple test script with mongosh:

cat > benchmark.js <<'EOF'
const coll = "testColl";
const numDocs = 1000;

for (let i = 0; i < numDocs; i++) {  // insert
  db.getCollection(coll).insertOne({ num: i, name: "MongoDB Benchmark Test" });
}

for (let i = 0; i < numDocs; i++) {  // select
  db.getCollection(coll).find({ num: i });
}

for (let i = 0; i < numDocs; i++) {  // update
  db.getCollection(coll).updateOne({ num: i }, { $set: { name: "Updated" } });
}

for (let i = 0; i < numDocs; i++) {  // delete
  db.getCollection(coll).deleteOne({ num: i });
}
EOF

mongosh 'mongodb://dbuser_meta:[email protected]:27017' benchmark.js

You can check FerretDB’s supported MongoDB commands and known differences. For basic usage, these differences are usually not significant.

2 - Configure

describe the ferret cluster you want

FerretDB Cluster

Before deploying a Mongo (FerretDB) cluster, you need to define it in the inventory using the relevant parameters.

The following example uses the default single-node pg-meta cluster’s meta database as FerretDB’s underlying storage:

all:
  children:

    #----------------------------------#
    # ferretdb for mongodb on postgresql
    #----------------------------------#
    # ./mongo.yml -l ferret
    ferret:
      hosts:
        10.10.10.10: { mongo_seq: 1 }
      vars:
        mongo_cluster: ferret
        mongo_pgurl: 'postgres://mongod:[email protected]:5432/meta'

Here, mongo_cluster and mongo_seq are essential identity parameters. For FerretDB, mongo_pgurl is also required to specify the underlying PG location.

Note that the mongo_pgurl parameter requires a PostgreSQL superuser. In this example, a dedicated mongod superuser is defined for FerretDB.

Note that FerretDB’s authentication is entirely based on PostgreSQL. You can create other regular users using either FerretDB or PostgreSQL.


PostgreSQL Cluster

FerretDB 2.0+ requires an extension: DocumentDB, which depends on several other extensions. Here’s a template for creating a PostgreSQL cluster for FerretDB:

all:
  children:

    #----------------------------------#
    # pgsql (singleton on current node)
    #----------------------------------#
    # postgres cluster: pg-meta
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          - { name: mongod      ,password: DBUser.Mongo  ,pgbouncer: true ,roles: [dbrole_admin ] ,superuser: true ,comment: ferretdb super user }
          - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
          - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
        pg_databases:
          - {name: meta, owner: mongod ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ documentdb, postgis, vector, pg_cron, rum ]}
        pg_hba_rules:
          - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
          - { user: mongod      , db: all ,addr: world ,auth: pwd ,title: 'mongodb password access from everywhere' }
        pg_extensions:
          - documentdb, citus, postgis, pgvector, pg_cron, rum
        pg_parameters:
          cron.database_name: meta
        pg_libs: 'pg_documentdb, pg_documentdb_core, pg_cron, pg_stat_statements, auto_explain'  # add timescaledb to shared_preload_libraries

High Availability

You can use Services to connect to a highly available PostgreSQL cluster and deploy multiple FerretDB instance replicas with L2 VIP binding for FerretDB layer high availability.

ferret:
  hosts:
    10.10.10.45: { mongo_seq: 1 }
    10.10.10.46: { mongo_seq: 2 }
    10.10.10.47: { mongo_seq: 3 }
  vars:
    mongo_cluster: ferret
    mongo_pgurl: 'postgres://mongod:[email protected]:5436/test'
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.99
    vip_interface: eth1

3 - Parameter

customize FerretDB with 9-parameter

There are 9 parameters in the FERRET module.

Parameter Type Level Comment
mongo_seq int I mongo instance identifier, REQUIRED
mongo_cluster string C mongo cluster name, MONGO by default
mongo_pgurl pgurl C/I underlying postgres URL for ferretdb
mongo_ssl_enabled bool C mongo/ferretdb ssl enabled, false by default
mongo_listen ip C mongo listen address, empty for all addr
mongo_port port C mongo service port, 27017 by default
mongo_ssl_port port C mongo tls listen port, 27018 by default
mongo_exporter_port port C mongo exporter port, 9216 by default
mongo_extra_vars string C extra environment variables for MONGO server

Defaults

The default parameters are defined in roles/ferret/defaults/main.yml

# mongo_cluster:        #CLUSTER  # mongo cluster name, required identity parameter
# mongo_seq: 0          #INSTANCE # mongo instance seq number, required identity parameter
# mongo_pgurl: 'postgres:///'     # mongo/ferretdb underlying postgresql url, required
mongo_ssl_enabled: false          # mongo/ferretdb ssl enabled, false by default
mongo_listen: ''                  # mongo/ferretdb listen address, '' for all addr
mongo_port: 27017                 # mongo/ferretdb listen port, 27017 by default
mongo_ssl_port: 27018             # mongo/ferretdb tls listen port, 27018 by default
mongo_exporter_port: 9216         # mongo/ferretdb exporter port, 9216 by default
mongo_extra_vars: ''              # extra environment variables for mongo/ferretdb

mongo_cluster

name: mongo_cluster, type: string, level: C

mongo cluster name, required identity parameter.

default value is MONGO, but you should define it explicitly for production use.

Comply with regexp [a-z][a-z0-9-]*, it is recommended to use descriptive names and start with mongo-


mongo_seq

name: mongo_seq, type: int, level: I

mongo instance sequence number, unique integer among mongo cluster is required

You have to explicitly define the sequence number for each mongo instance. integer start from 0 or 1.


mongo_pgurl

name: mongo_pgurl, type: pgurl, level: C/I

underlying postgres URL for ferretdb connection.

no default value, you have to define it explicitly. This is the PostgreSQL database URL that FerretDB will use as its backend storage.

Format: postgres://username:password@host:port/database


mongo_ssl_enabled

name: mongo_ssl_enabled, type: bool, level: C

mongo/ferretdb ssl enabled flag.

default value is false. Set to true to enable SSL/TLS encryption for mongo connections.


mongo_listen

name: mongo_listen, type: ip, level: C

mongo listen address for binding.

default value is empty string '', which means listen on all available addresses. You can specify a specific IP address to bind to.


mongo_port

name: mongo_port, type: port, level: C

mongo service port for client connections.

default value is 27017, which is the standard MongoDB port. Change this if you need to avoid port conflicts.


mongo_ssl_port

name: mongo_ssl_port, type: port, level: C

mongo tls listen port for encrypted connections.

default value is 27018. This port is used when SSL/TLS is enabled for secure connections.


mongo_exporter_port

name: mongo_exporter_port, type: port, level: C

mongo exporter port for metrics collection.

default value is 9216. This port is used by the monitoring exporter to expose metrics for Prometheus.


mongo_extra_vars

name: mongo_extra_vars, type: string, level: C

extra environment variables for MONGO server.

default value is empty string ''. You can specify additional environment variables that will be passed to the FerretDB process.

4 - Administration

run administrative tasks

Create FerretDB Cluster

After defining the FerretDB cluster in the inventory, you can install it with:

./mongo.yml -l ferret   # Install MongoDB/FerretDB on ferret group

Since FerretDB uses PostgreSQL as its underlying storage, running this playbook multiple times is generally safe.


Remove FerretDB Cluster

To remove a Mongo/FerretDB cluster, run the mongo_purge subtask of mongo.yml playbook with the mongo_purge parameter:

./mongo.yml -e mongo_purge=true -t mongo_purge

5 - Playbook

Install ferretdb with playbooks

There’s a built-in playbook mongo.yml for installing FerretDB on nodes.


mongo.yml

mongo.yml: Install MongoDB/FerretDB on the target host.

This playbook consists of the following subtasks:

  • mongo_check : check mongo identity
  • mongo_dbsu : create os user mongod
  • mongo_install : install mongo/ferretdb rpm
  • mongo_purge : purge mongo/ferretdb
  • mongo_config: config mongo/ferretdb
  • mongo_cert : issue mongo/ferretdb ssl certs
  • mongo_launch : launch mongo/ferretdb service
  • mongo_register : register mongo/ferretdb to prometheus

6 - Monitor

FerretDB monitor dashboards and alerts

There is one dashboard for FERRET module for now.

Mongo Overview

Mongo Overview: Overview of a Mongo/FerretDB cluster