Setup a MongoDB + Python Docker Dev Stack

May 14, 2019

MongoDB + Python

I only just recently jumped on the MongoDB bandwagon, but I really, really like it. To me, working with MongoDB feels so much more natural. It feels like working with code. MongoDB collections are arrays of objects, as opposed to a SQL DB where we kind of make it look like an object. Compared to SQL databases it is a much newer technology, but it is quickly gaining traction and becoming more and more robust.

With that said, it's nice to have a docker-compose template on hand to quickly spin up a MongoDB + Python Stack! That is exactly what we have here today. If you read my Setup a MySQL + Python Docker Dev Stack post, this will feel very similar.

MongoDB in Docker Compose

First of all, let's examine what just MongoDB looks like in docker compose. I'm going to go over only a very small portion of the potential configuration here. If you need more check out the ​official MongoDB docker image.​​​

version: '3'

services:

  mongo:
    image: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password
    networks:
      - app-tier

networks:
  app-tier:
    driver: bridge

YAML

Environmental Variables

Here, I am setting the initial root username with MONGO_INITDB_ROOT_USERNAME and the root password with MONGO_INITDB_ROOT_PASSWORD. That's really it for this one. You need to add any data locally and import it with the mongoimport tool.

Now, I could spin this up as is putting the above docker-compose.yml file in a directory and running:

docker-compose up -d
docker-compose exec mongo bash
Bash

Once you start that you will be in a shell in the docker mongo container. 

➜  connect-mongo docker-compose exec mongo bash
root@f65e7e65e52b:/# mongo
MongoDB shell version v4.0.8
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("1f2b96f1-42bb-4599-af76-70e26f849ad8") }
MongoDB server version: 4.0.8
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
        http://docs.mongodb.org/
Questions? Try the support group
        http://groups.google.com/group/mongodb-user

And that is how you know you are up and running!

 

Connect to the Database From a Python App

I am going to use my tried and true method here for building a python docker image. We can spin up a docker image for our python app by defining the packages we need in an environment.yml and building them. For more information on this process you can see my full tutorial at Develop a Python Flask App With Docker

For this particular example we need  a mysql connection library. I am using pymongo. I always add in ipython, so you'll see that there too.

name: connect
channels:
  - conda-forge
  - defaults
dependencies:
  - python=3.6
  - ipython
  - anaconda-client
  - pymongo
YAML

Here is the Dockerfile for reference. I create a conda environment, called connect (see Line 1 in the environment.yml configuration) and source it.

FROM continuumio/miniconda3:4.5.11

RUN apt-get update -y; apt-get upgrade -y
RUN apt-get update -y; apt-get upgrade -y; apt-get install -y vim-tiny vim-athena ssh

COPY environment.yml environment.yml

RUN conda env create -f environment.yml
RUN echo "alias l='ls -lah'" >> ~/.bashrc
RUN echo "source activate connect" >> ~/.bashrc

ENV CONDA_EXE /opt/conda/bin/conda
ENV CONDA_PREFIX /opt/conda/envs/connect
ENV CONDA_PYTHON_EXE /opt/conda/bin/python
ENV CONDA_PROMPT_MODIFIER (connect)
ENV CONDA_DEFAULT_ENV connect
ENV PATH /opt/conda/envs/connect/bin:/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Add the Python App to the Docker Compose Stack

Simply add your python app, with the command 'tail -f /dev/null' to ensure it does not exit. 

version: '3'

# Run as
# docker-compose build; docker-compose up -d
# Check with
# docker ps
# Then check the logs with
# docker logs --tail 50 $service_name
# docker-compose images
# docker-compose logs --tail 20 service_name

services:

  mongo:
    image: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password
    networks:
      - app-tier
    volumes:
      # Sample data comes from:
      # https://github.com/mistertandon/node-express-hbs/blob/master/movies_collection.json
      - ./mongo:/docker-entrypoint-initdb.d

  python_app:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - mongo
    networks:
      - app-tier
    command:
      tail -f /dev/null


networks:
  app-tier:
    driver: bridge
YAML

Restart your stack with your new configuration.

docker-compose restart

This time connect to your Python App with docker-compose exec python_app bash.

➜  connect-mongo docker-compose exec python_app bash
(connect) root@79bfb42b8be6:/# ipython
Python 3.6.7 | packaged by conda-forge | (default, Feb 28 2019, 09:07:38) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from pymongo import MongoClient                                                                                                                                                                     In [2]: from pprint import pprint                                                                                                                                                                                                   
In [3]: # https://docs.mongodb.com/manual/reference/connection-string/                                                                                                                                                                 

In [4]: client = MongoClient('mongodb://root:password@mongo:27017/')                                                                                                                                                                   

In [5]: db = client.movies                                                                                                                                                                                                             

In [6]: db.list_collection_names()                                                                                                                                                                                                     
Out[6]: ['movies']

In [7]: movies = db.movies                                                                                                                                                                                                             

In [8]: pprint(movies.find_one())                                                                                                                                                                                                      
{'_id': ObjectId('589cbda9c0b9fec62febf274'),
 'actors': ['Ryan Reynolds',
            'Morena Baccarin',
            'Ed Skrein',
            'T.J. Miller',
            'Gina Carano',
            'Leslie Uggams',
            'Stefan Kapičić',
            'Brianna Hildebrand'],
 'awards': {'nominations': 12,
            'text': 'wo Golden Globe Award nominations for Best Motion Picture '
                    '– Musical or Comedy and Best Actor – Motion Picture '
                    'Musical or Comedy.',
            'wins': 5},
 'countries': ['USA'],
 'director': 'Tim Miller',
 'genres': ['Comics character', 'Adventure', 'Action'],
 'imdb': {'id': 'tt1431045', 'rating': 8.1, 'votes': 585141},
 'metacritic': 92,
 'plot': 'Deadpool is a 2016 American superhero film directed by Tim Miller '
         'and written by Rhett Reese and Paul Wernick, based on the Marvel '
         'Comics character of the same name.',
 'poster': 'http://ia.media-imdb.com/images/M/MV5BMTgxOTY4Mjc0MF5BMl5BanBnXkFtZTcwNTA4MDQyMw@@._V1_SX300.jpg',
 'rated': 'R',
 'released': datetime.datetime(2016, 6, 18, 4, 0),
 'runtime': 108,
 'title': 'Deadpool',
 'tomato': {'consensus': 'Fast, funny, and gleefully profane, the '
                         'fourth-wall-busting Deadpool.',
            'fresh': 241,
            'image': 'certified',
            'meter': 99,
            'rating': 6.9,
            'reviews': 287,
            'userMeter': 90,
            'userRating': 4.3,
            'userReviews': 181719},
 'type': 'movie',
 'writers': ['Rhett Reese', 'Paul Wernick'],
 'year': 2016}

In [9]:  
Bash

Wrap Up

There we go! You've seen how easy it is to spin up a database, and use python to connect to it and start querying.

Happy teching!

Bioinformatics Solutions on AWS Newsletter 

Get the first 3 chapters of my book, Bioinformatics Solutions on AWS, as well as weekly updates on the world of Bioinformatics and Cloud Computing, completely free, by filling out the form next to this text.

Bioinformatics Solutions on AWS

If you'd like to learn more about AWS and how it relates to the future of Bioinformatics, sign up here.

We won't send spam. Unsubscribe at any time.