Running MongoDB with persistent storage

MongoDB is a good example of an application that would benefit from running in an AWS Nitro Enclave and using Anjuna Nitro Runtime’s persistent storage features.

In this example, you simplify a MongoDB inside an AWS Nitro Enclave setup and ignore TLS configuration and encryption. You will focus on running a MongoDB server with persistent storage to learn how to work with persistent storage with AWS Nitro Enclaves.

Build the required tools for block mounts support

Run the following commands to build the tools required to support block mounts:

$ cd /opt/anjuna/nitro/drbd/
$ ./parent-drbd-setup.sh --build

Create a persistent volume disk file

To create a fresh new volume disk file to save the persistent data, run the following commands:

$ cd /opt/anjuna/nitro/drbd/
# Create a 2048 MB disk file for the volume
$ ./parent-drbd-setup.sh --mem 2048 --disk-create ~/nitro-disk.img

# start the parent listener
$ ./parent-drbd-setup.sh --start ~/nitro-disk.img

Install MongoDB Shell

Before running the MongoDB server, you will download a tool that will allow you to interact with the MongoDB server.

Create a file at /etc/yum.repos.d/mongodb-org-5.0.repo. You will need root access to write that file so that you can run sudo vim /etc/yum.repos.d/mongodb-org-5.0.repo.

Copy the following contents into the file and save it:

[mongodb-org-5.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/5.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-5.0.asc

Now you can install the MongoDB Shell:

$ sudo yum install -y mongodb-org-shell

Building the enclave

In this section you build a MongoDB enclave that uses a block mount.

Create an enclave configuration file and name it enclave-config.yaml. This file configures MongoDB to bind to all IPs, sets a default username and password for the database, and mounts the volume to /data/db, where Mongo expects the DB files to be.

version: 1.7

# Run mongodb, bind to all IPs
command: [docker-entrypoint.sh, mongod, --auth, --port=27017, --bind_ip=0.0.0.0]

# Set a default MongoDB username and password
environment:
- MONGO_INITDB_ROOT_USERNAME=anjuna
- MONGO_INITDB_ROOT_PASSWORD=anjuna

# Set a persistent block mount
mounts:
  - type: block
    name: db-volume
    mountPath: /data/db

Build and run the enclave:

$ echo "Building enclave..."

# Build the enclave using the mongo:latest Docker image,
# enclave-config.yaml as the enclave configuration file,
# and save it to mongo-nitro.eif
$ anjuna-nitro-cli build-enclave --docker-uri mongo:latest --enclave-config-file enclave-config.yaml --output-file mongo-nitro.eif

# Start the network agent
$ anjuna-nitro-netd-parent --expose 27017 --daemonize
$ sleep 3

# Start the enclave you just created
$ anjuna-nitro-cli run-enclave --cpu-count 2 --memory 4096 --eif-path mongo-nitro.eif --debug-mode

The number of vCPU cores must be an even number due to hyperthreading.

If the agent is already running, it should be killed before starting the enclave.

Connecting to the database

After a few seconds of initialization, you should be able to connect to the MongoDB. Now you will connect and add some data. If you are unable to connect, wait a few more seconds and try again.

$ mongo -u anjuna -p anjuna 'mongodb://localhost'
> use demo
> db.data.insert({"hello_world":1})
> db.data.findOne()
> exit

You have added some data and you are able to query it. Now you can make sure the data is staying persistent. To do so, you can terminate the enclave and run it again.

$ anjuna-nitro-cli terminate-enclave --all
$ pkill -f anjuna-nitro-netd-parent
$ /opt/anjuna/nitro/drbd/parent-drbd-setup.sh --stop
$ ./parent-drbd-setup.sh --start ~/nitro-disk.img
$ anjuna-nitro-netd-parent --expose 27017 --daemonize
$ anjuna-nitro-cli run-enclave --cpu-count 2 --memory 4096 --eif-path mongo-nitro.eif --debug-mode

After 20-30 seconds, you should be able to connect to the DB and fetch the data you inserted before terminating the enclave:

$ mongo -u anjuna -p anjuna 'mongodb://localhost'
> use demo
> db.data.findOne()
> exit

You should be able to see the entry you created before: { "_id" : ObjectId("…​"), "hello_world" : 1 }.

Congratulations! You have successfully set up an AWS Nitro Enclave with a persistent storage volume.