Using Docker redis image with flask

Writing a docker-compose which uses Flask, Postgres and Redis

Agenda

This is a follow up from our last post which created a Flask polls app which communcated with a Postgres database.

We had two services namely web and db.

Let’s add one more service called redis to the mix.

Our code would remain unchanged in this post. Check the last post to get code familiarity.

Docker services

Your directory structure would look like:

├── Dockerfile
├── README.md
├── __init__.py
├── app.py
├── db.py
├── docker-compose.yml
├── env.list
├── models.py
├── requirements.txt
├── settings.py
└── tox.ini

docker-compose.yml should look like:

version: '3'
services:
    web:
        build: .
        command: flask run --host=0.0.0.0 --port=8000
        ports:
            - 8000:8000
        environment:
            - FLASK_APP=app.py
        env_file:
            - env.list
        depends_on:
            - db
    db:
        image: postgres
        environment:
            - POSTGRES_USER=polls
            - POSTGRES_PASSWORD=hearmeroar
            - POSTGRES_DB=polls_db
        ports:
            - 5433:5432
        volumes:
            - flask_polls_data:/var/lib/postgresql/data
    cache:
        image: redis
        command: redis-server --appendonly yes
        volumes:
            - redis_data:/data

volumes:
    flask_polls_data:
    redis_data:

Service web and db are largely unchanged from last post.

We added redis image provided by Docker. We added a volume so that data persist beyond the lifetime of container.

Modify app.py to make it look like:

import json
import redis
from datetime import datetime
from flask import Flask, request

from .models import Question

app = Flask(__name__)

r = redis.Redis(host='cache', port=6379, db=0)


@app.route('/polls/questions/', methods=['GET', 'POST'])
def questions():
    r.incr('hits', amount=1)
    if request.method == 'POST':
        question_text = request.form['question_text']
        pub_date = datetime.strptime(request.form['pub_date'], '%Y-%m-%d')
        question = Question(question_text=question_text, pub_date=pub_date)
        question.save()
        rep = {'question_text': question.question_text, 'id': question.id, 'pub_date': question.pub_date.strftime('%Y-%m-%d')}
        return rep
    elif request.method == 'GET':
        questions = Question.select()
        l = []
        for question in questions:
            l.append({'question_text': question.question_text, 'id': question.id, 'pub_date': question.pub_date.strftime('%Y-%m-%d')})
        return json.dumps(l)


@app.route('/hits', methods=['GET'])
def hits():
    hits = int(r.get('hits').decode('utf-8'))
    return json.dumps({'hits': hits})

We added an endpoint which tells how many times the api has been consumed.

Ensure that redis is added to requirements.txt

Build the services:

docker-compose build

Start the services:

docker-compose up

Navigate to http://localhost:8000/polls/questions/ multiple times. Check http://localhost:8000/hits and you should see it increasing with every hit to questions api.

Stop the services

docker-compose down

This would destroy the containers. Start the services again

docker-compose down

Navigating to http://localhost:8000/hits would still give the correct hits which confirms that data is being persisted.

Thank you for reading the Agiliq blog. This article was written by Akshar on Oct 20, 2018 in FlaskDocker .

You can subscribe ⚛ to our blog.

We love building amazing apps for web and mobile for our clients. If you are looking for development help, contact us today ✉.

Would you like to download 10+ free Django and Python books? Get them here