Deploy a MongoDB Replica Set with Docker and Supergiant

Posted by Ben Hundley on July 19, 2016

Despite a number of annoying challenges, it is totally possible to run distributed databases at scale with Docker containers. This tutorial will show you how to deploy a MongoDB replica set in 5 steps using Docker containers, Kubernetes, and Supergiant.


NOTE: This tutorial was depricated when Components were removed in version 0.11.x. This tutorial is valid for Supergiant version =< 0.10.x.


About the Tools

Docker is much-loved for bundling applications with dependencies into containers. I’m going to assume you already have knowledge of Docker, or you wouldn’t be reading this tutorial. We’re going to use the official MongoDB container already on DockerHub.

Kubernetes solves many container orchestration challenges for us, including networking (for clustering) and external storage (for state and data persistence). However, the sequence of Kubernetes commands needed to deploy a clustered application with storage is far from straightforward. We’ll use Supergiant to solve these problems.

Supergiant solves Kubernetes complications by allowing pre-packaged and re-deployable application topologies. Or, in more specific terms, Supergiant lets you use Components, which are somewhat similar to a microservice. Components represent an almost-uniform set of Instances of software (e.g., Elasticsearch, MongoDB, your web application, etc.). They roll up all the various Kubernetes and cloud operations needed to deploy a complex topology into a compact entity that is easy to manage. If you don’t already have Supergiant running on AWS, you can do this pretty quickly from the Install Supergiant page.

So let’s get down to business. This tutorial will use the Supergiant’s API directly with cURL for clarity on all the configuration and inputs, and we’ll have a running replica set in just 5 steps.

Step 1: Create an App

An App allows you to group your components. For example, you might have an app named “my-site-production”, where one of the components is “my-mongodb”.

curl -XPOST $API_HOST/v0/apps -d '{
 "name": "test"
}'

Step 2: Create an Entrypoint

An Entrypoint represents a cloud load balancer (such as an ELB on AWS). When you create components that expose network ports, you can optionally allow external access by assigning them to entrypoints, which then gives the component a publicly-reachable address. This will allow us to communicate with MongoDB from anywhere outside of the Kubernetes cluster.

Note: we’ll do this for our tutorial, but if you don’t need external access, it is smarter to leave communication on the private network by just using the private address without an entrypoint.

curl -XPOST $API_HOST/v0/entrypoints -d '{
 "domain": “example.com"
}'

Step 3: Create a Component

The component contains only 2 attributes: name and custom_deploy_script. Custom Deploy Scripts allow components to extend the standard Supergiant deployment flow. The deploy script used here is supergiant/deploy-mongodb, which configures a replica set based on the component information.

curl -XPOST $API_HOST/v0/apps/test/components -d '{
 "name": "mongo",
 "custom_deploy_script": {
   "image": "supergiant/deploy-mongodb:latest",
   "command": [
     "/deploy-mongodb",
     "--app-name",
     "test",
     "--component-name",
     "mongo"
   ]
 }
}'

Step 4: Create a Release

A Release holds all the configuration for a component. You can think of it like a commit to a git repo. Creating new releases allows you to adjust configuration, and deploy changes when needed.

curl -XPOST $API_HOST/v0/apps/test/components/mongo/releases -d '{
 "instance_count": 3,
 "volumes": [
   {
     "name": "mongo-data",
     "type": "gp2",
     "size": 10
   }
 ],
 "containers": [
   {
     "image": "mongo",
     "command": [
       "mongod",
       "--replSet",
       "rs0"
     ],
     "cpu": {
       "min": 0,
       "max": 0.25
     },
     "ram": {
       "min": "256Mi",
       "max": "1Gi"
     },
     "mounts": [
       {
         "volume": "mongo-data",
         "path": "/data/db"
       }
     ],
     "ports": [
       {
         "protocol": "TCP",
         "number": 27017,
         "public": true,
         "per_instance": true,
         "entrypoint_domain": "example.com"
       }
     ]
   }
 ]
}'

Since the release is the real meat of the matter, I’ve highlighted the parts that can be adjusted without altering the actual topology. First, there’s the volumes section, in which the name, size, and type of EBS (hard drive) can be edited. Then, cpu and ram, both of which control the allotted min/max (or reserve/limit) range for each instance of the component. The mounts section corresponds to volumes, so make sure that the volume value matches the name used for the drive.

Step 5: Deploy

This will deploy the Component as outlined by the Release.

curl -XPOST $API_HOST/v0/apps/test/components/mongo/deploy

When the deploy finishes, you can retrieve the assigned address of each Instance of the component like so:

Request:

curl $API_HOST/v0/apps/test/components/mongo/releases/current/instances/0

Response:

{
 "id": "0",
 "base_name": "mongo-0",
 "name": "mongo-020160715200942",
 "status": "STARTED",
 "cpu": {
   "usage": 7,
   "limit": 250
 },
 "ram": {
   "usage": 36270080,
   "limit": 1073741824
 },
 "addresses": {
   "external": [
     {
       "port": "27017",
       "address": "supergiant-example-com-XXXXXXXXXX.us-east-1.elb.amazonaws.com:30682"
     }
   ],
   "internal": [
     {
       "port": "27017",
       "address": "mongo-0-public.test.svc.cluster.local:27017"
     }
   ]
 }
}

Using the external address of the first instance (highlighted above), we can connect to the MongoDB shell remotely (from your local computer for instance) like so:

mongo supergiant-example-com-XXXXXXXXXX.us-east-1.elb.amazonaws.com:30682

Your output upon connecting should look like this (the important part being the prompt, rs0:PRIMARY>, confirming the replica set is configured):

MongoDB shell version: 2.4.10
connecting to: supergiant-example-com-XXXXXXXXXX.us-east-1.elb.amazonaws.com:30682/test
...
rs0:PRIMARY>

Note:  if you’re looking to deploy larger, sharded MongoDB clusters, you could use the following layout:

  • Component for each shard (optionally as a replica set), just as defined above. Runs the mongod process (see command section of the container definition).

  • Component for the config server replica set. Runs mongod with the --configsvr option.

  • Component for the routing layer. Runs mongos.

View Deploy a Sharded Cluster in the MongoDB manual for an overview of the setup.

And there you have it -- a MongoDB replica set running as containers, with data stored reliably on detachable external drives.

This setup can be resized at any time (CPU, RAM, or disk; volumes can be resized), by creating a new release that defines the new resource allocations you want. Supergiant will then gently rebuild each container upon deploy.

comments powered by Disqus