Skip to main content

Deploy FerretDB in Kubernetes using KubeDB Managed Postgres

· 7 min read
Alexander Fashakin
FerretDB Team

Deploy FerretDB in Kubernetes using KubeDB Managed Postgres

KubeDB – a popular Kubernetes database management solution – now provides support for FerretDB.

FerretDB is an open source document database that adds MongoDB compatibility to PostgreSQL. It lets you use your familiar MongoDB syntax and commands with your data stored in PostgreSQL backend.

Over the past few years, Kubernetes has become a popular option for deploying production-ready databases. Tools like KubeDB simplify the management and automation of database tasks in Kubernetes, including provisioning, monitoring, upgrading, automated scaling and backup, and failure detection.

This blog post will demonstrate how to run and deploy FerretDB in Kubernetes using KubeDB.

Prerequisites

Ensure to have the following set up.

Get cluster ID

To get the AppsCode license, you need the cluster ID. Run this command to get the cluster ID.

kubectl get ns kube-system -o jsonpath='{.metadata.uid}'

Install KubeDB

Use Helm to install KubeDB:

helm install kubedb oci://ghcr.io/appscode-charts/kubedb \
--version v2024.2.14 \
--namespace kubedb --create-namespace \
--set-file global.license=/path/to/the/license.txt \
--set global.featureGates.FerretDB=true \
--wait --burst-limit=10000 --debug

Be sure to include the AppsCode license path for the KubeDB installation.

Verify the installation:

$ kubectl get pods --all-namespaces -l "app.kubernetes.io/instance=kubedb"
NAMESPACE NAME READY STATUS RESTARTS AGE
kubedb kubedb-kubedb-autoscaler-5c97c8c7f9-lw64s 1/1 Running 0 11m
kubedb kubedb-kubedb-ops-manager-7b8fc4d7bf-28qk4 1/1 Running 0 11m
kubedb kubedb-kubedb-provisioner-6c89ddd5d8-fw24w 1/1 Running 0 11m
kubedb kubedb-kubedb-webhook-server-6fc6c8b44f-pwdvr 1/1 Running 0 11m
kubedb kubedb-sidekick-86c64c8f59-gvzd8 1/1 Running 0 11m

KubeDB provides several installed CRD Groups including FerretDB. Run kubectl get crd -l app.kubernetes.io/name=kubedb command to list them.

Deploy FerretDB with KubeDB Managed PostgreSQL

Create a namespace for all the FerretDB components.

kubectl create namespace ferretdemo

Next, create the FerretDB Custom Resource YAML:

apiVersion: kubedb.com/v1alpha2
kind: FerretDB
metadata:
name: ferret
namespace: ferretdemo
spec:
version: '1.18.0'
storageType: Durable
storage:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
backend:
externallyManaged: false
terminationPolicy: WipeOut

The YAML file will create a ferret resource in the ferretdemo namespace using KubeDB. At the moment, KubeDB only supports version FerretDB v1.18.0. Check here for recent versions

Save the config as ferret.yaml and apply it.

kubectl apply -f ferret.yaml

Once it is applied, the FerretDB resource is deployed with the all its objects.

Get the objects in the ferretdemo namespace:

$ kubectl get all -n ferretdemo
NAME READY STATUS RESTARTS AGE
pod/ferret-0 1/1 Running 0 4m42s
pod/ferret-pg-backend-0 2/2 Running 0 5m15s
pod/ferret-pg-backend-1 2/2 Running 0 5m10s
pod/ferret-pg-backend-arbiter-0 1/1 Running 0 5m1s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ferret ClusterIP 10.111.78.151 <none> 27017/TCP 5m18s
service/ferret-pg-backend ClusterIP 10.99.57.62 <none> 5432/TCP,2379/TCP 5m18s
service/ferret-pg-backend-pods ClusterIP None <none> 5432/TCP,2380/TCP,2379/TCP 5m18s
service/ferret-pg-backend-standby ClusterIP 10.108.28.132 <none> 5432/TCP 5m18s
NAME READY AGE
statefulset.apps/ferret 1/1 4m42s
statefulset.apps/ferret-pg-backend 2/2 5m15s
statefulset.apps/ferret-pg-backend-arbiter 1/1 5m1s
NAME TYPE VERSION AGE
appbinding.appcatalog.appscode.com/ferret kubedb.com/ferretdb 1.18.0 4m42s
appbinding.appcatalog.appscode.com/ferret-pg-backend kubedb.com/postgres 13.13 5m1s
NAME VERSION STATUS AGE
postgres.kubedb.com/ferret-pg-backend 13.13 Ready 5m18s

To be sure the ferret resource is ready, run this command:

$ kubectl get ferretdb -n ferretdemo ferret
NAME NAMESPACE VERSION STATUS AGE
ferret ferretdemo 1.18.0 Ready 9m6s

port-forward the Service

Before port forwarding, list the services created by KubeDB.

$ kubectl get service -n ferretdemo | grep ferret
ferret ClusterIP 10.111.78.151 <none> 27017/TCP 11m
ferret-pg-backend ClusterIP 10.99.57.62 <none> 5432/TCP,2379/TCP 11m
ferret-pg-backend-pods ClusterIP None <none> 5432/TCP,2380/TCP,2379/TCP 11m
ferret-pg-backend-standby ClusterIP 10.108.28.132 <none> 5432/TCP 11m

Next, forward the ferret Service to port 27017 on your local machine.

kubectl port-forward -n ferretdemo svc/ferret 27017

Get FerretDB credentials in Secret

You need the FerretDB credentials before connecting via mongosh. KubeDB creates and stores the ferret Service credentials as a Secret.

To get the details, run this command:

kubectl get secret -n ferretdemo | grep ferret

Using ferret-pg-backend-auth, get the user credentials.

echo $(kubectl get secret -n ferretdemo ferret-pg-backend-auth -o jsonpath='{.data.username}' | base64 -d)
echo $(kubectl get secret -n ferretdemo ferret-pg-backend-auth -o jsonpath='{.data.password}' | base64 -d)

This will print out the username and password credentials for the instance.

Connect to FerretDB via mongosh

Using the credentials, connect to FerretDB via mongosh using this format:

mongosh mongodb://<username>:<password>@<host>:27017/ferretdb?authMechanism=PLAIN'

Connect via mongosh:

mongosh 'mongodb://postgres:p.i~glw7q9mdbpQ2@localhost:27017/ferretdb?authMechanism=PLAIN'
Current Mongosh Log ID: 662699b8fa65a75337cb3ec7
Connecting to: mongodb://<credentials>@localhost:27017/ferretdb?authMechanism=PLAIN&directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.2.2
Using MongoDB: 7.0.42
Using Mongosh: 2.2.2
mongosh 2.2.4 is available for download: https://www.mongodb.com/try/download/shell
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
------
The server generated these startup warnings when booting
2024-04-22T17:09:13.234Z: Powered by FerretDB v1.18.0 and PostgreSQL 13.13 on aarch64-unknown-linux-musl, compiled by gcc.
2024-04-22T17:09:13.235Z: Please star us on GitHub: https://github.com/FerretDB/FerretDB.
2024-04-22T17:09:13.235Z: The telemetry state is undecided.
2024-04-22T17:09:13.235Z: Read more about FerretDB telemetry and how to opt out at https://beacon.ferretdb.io.
------
ferretdb>

Let's run some commands in the database. Start by inserting a document record into a weather collection as shown below.

db.weather.insertMany([
{
date: new Date("2024-04-22"),
location: {
city: "New York",
country: "USA",
coordinates: { lat: 40.7128, lon: -74.0060 }
},
weather: {
temperature: 18,
conditions: "Cloudy",
wind_speed: 12,
humidity: 80
},
remarks: "Possible light rain in the evening."
}
]);

Suppose you want to update the humidity level in New York where the wind speed was more than 10 km/h:

ferretdb> db.weather.updateMany(
... { "location.city": "New York", "weather.wind_speed": { $gt: 10 } },
... { $set: { "weather.humidity": 85 } }
... );
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
ferretdb> db.weather.find()
[
{
_id: ObjectId('66278976fba61a5fec8bad82'),
date: ISODate('2024-04-22T00:00:00.000Z'),
location: {
city: 'New York',
country: 'USA',
coordinates: { lat: 40.7128, lon: -74.006 }
},
weather: {
temperature: 18,
conditions: 'Cloudy',
wind_speed: 12,
humidity: 85
},
remarks: 'Possible light rain in the evening.'
}
]

FerretDB stores the data in the ferret-pg-backend PostgreSQL using mongosh. Let's exec into the Postgres database to view the record.

% kubectl exec -it -n ferretdemo ferret-pg-backend-0 -- bash -c "psql -d ferretdb"

In Postgres, set the SEARCH_PATH to ferretdb and list the record in the weather_36404793 table.

ferretdb=# set SEARCH_PATH to ferretdb;
SET
ferretdb=# \dt
List of relations
Schema | Name | Type | Owner
----------+-----------------------------+-------+----------
ferretdb | _ferretdb_database_metadata | table | postgres
ferretdb | weather_36404793 | table | postgres
(2 rows)
ferretdb=# SELECT * FROM weather_36404793;
_jsonb
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{"$s": {"p": {"_id": {"t": "objectId"}, "date": {"t": "date"}, "remarks": {"t": "string"}, "weather": {"t": "object", "$s": {"p": {"humidity": {"t": "int"}, "conditions": {"t": "string"}, "wind_speed": {"t": "int"}, "temperature": {"t": "int"}}, "$k": ["temperature", "conditions", "wind_speed", "humidity"]}}, "location": {"t": "object", "$s": {"p": {"city": {"t": "string"}, "country": {"t": "string"}, "coordinates": {"t": "object", "$s": {"p": {"lat": {"t": "double"}, "lon": {"t": "double"}}, "$k": ["lat", "lon"]}}}, "$k": ["city", "country", "coordinates"]}}}, "$k": ["_id", "date", "location", "weather", "remarks"]}, "_id": "66278976fba61a5fec8bad82", "date": 1713744000000, "remarks": "Possible light rain in the evening.", "weather": {"humidity": 85, "conditions": "Cloudy", "wind_speed": 12, "temperature": 18}, "location": {"city": "New York", "country": "USA", "coordinates": {"lat": 40.7128, "lon": -74.006}}}
(1 row)
ferretdb=#

Deploy FerretDB with an externally managed PostgreSQL

So far, we have shown how to set up FerretDB using KubeDB Managed PostgreSQL. However, if you prefer an external PostgreSQL server as your backend, this is entirely possible.

The YAML configuration provided below outlines how to integrate FerretDB with a PostgreSQL instance managed externally.

apiVersion: kubedb.com/v1alpha2
kind: FerretDB
metadata:
name: ferretdb-external
namespace: ferretdemo
spec:
version: "1.18.0"
authSecret:
externallyManaged: true
name: ha-postgres-auth
storageType: Durable
storage:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
backend:
externallyManaged: true
postgres:
service:
name: ha-postgres
namespace: ferretdemo
pgPort: 5432
terminationPolicy: WipeOut

spec.postgres.service contains the service details for the user's external PostgreSQL that exists within the cluster. spec.authSecret.name refers to the name of the authentication secret for accessing the user's external PostgreSQL database.

Support

This blog post shows you how to deploy a FerretDB instance in Kubernetes using KubeDB. Ensure to experiment and try it out. If you have any questions or just want to contact us, please do so via the FerretDB Slack channel here.