Dockerize a Flask, Celery, and Redis Application with Docker Compose

blog/cards/dockerize-a-flask-celery-and-redis-application-with-docker-compose.jpg

Learn how to install and use Docker to run a multi-service Flask, Celery and Redis application in development with Docker Compose.

After this tutorial, you’ll understand what the benefits of using Docker are and will be able to:

  • Install Docker on all major platforms in 5 minutes or less
  • Clone and run an example Flask app that uses Celery and Redis
  • Know how to write a Dockerfile
  • Run multiple Docker containers with Docker Compose

Also, there’s a free email course to learn a bit about Docker at the bottom of this post.

What Is Docker and Why Is It Useful?

Docker allows you to package up an application or service with all of its dependencies into a standardized unit. This unit is typically labeled as a Docker image.

Everything the application needs to run is included. The Docker image contains the code, runtime, system libraries and anything else you would install on a server to make it run if you weren’t using Docker.

To get a better idea of how Docker will affect you on a day to day basis as a software developer I highly recommend you read one of my previous blog posts which will save you from years of turmoil by using Docker.

Installing Docker

The code base we’ll be working with is compatible with Docker 17.06 and Docker Compose 1.14, and I’m sure it will continue to work with future versions of Docker, so feel free to install the latest versions of both.

This guide expects you to have Docker already installed. If you’re at ground 0 then you may want to sign up for the free Docker email course at the bottom of this post, because it covers a myriad of ways to install Docker on Mac, Windows and Linux.

Otherwise, feel free to check out Docker’s documentation on installing Docker if you want to get going right now. To help you out, I’ve also written a comparison guide on Docker for Mac / Windows vs Docker Toolbox.

Ensure Docker and Docker Compose Are Working

Before continuing on you should see what I see, or something very similar:

docker --version
> Docker version 17.06.0-ce, build 02c1d87

docker-compose --version
> docker-compose version 1.14.0, build c7bdf9e

Creating the Flask Application

We’re going to be using the open source version of the application in my Build a SAAS App with Flask course.

The open source version only covers a tiny fraction of what the course covers, but it will be more than enough to exercise how to use Docker in development.

Clone the Project

git clone https://github.com/nickjj/build-a-saas-app-with-flask

Open the Project in Your Favorite Code Editor

# Move into the project's directory
cd build-a-saas-app-with-flask

# Open the project with your favorite editor (mine is Sublime)
subl .

Feel free to use whatever editor you want, but if you like Sublime Text 3 and you want to configure it for Python, Docker and more then check out my post on 25 Sublime Text 3 Packages for Polyglot Programmers.

Dockerize the Flask Application

There’s a few things we need to do to Dockerize the application.

Logging

In order for logs to function properly, Docker expects your application or process to log to STDOUT. Lucky for us, Flask does this by default.

Docker Specific Files

The root of the project has a few files that are related to Docker:

nick@oriath:/tmp/bsawf (master) ⚡ ls -la
-rwxrwxr-x  1 nick nick    643 Jun 10 12:57 docker-compose.yml
-rwxrwxr-x  1 nick nick    346 Jun 10 12:57 Dockerfile
-rw-rw-r--  1 nick nick     19 Jun 10 12:57 .dockerignore
-rwxrwxr-x  1 nick nick     31 Jun 10 12:57 .env

The only file that’s necessary to add is the Dockerfile but you’ll find that most web applications that are Docker-enabled will have the others.

Dockerfile

Let’s start off with the Dockerfile because to talk about the other files will require having a little bit of knowledge about how Docker images get built.

You can think of this file as your Docker image blueprint or recipe. When you run the docker build command it will execute each line from top to bottom.

It’s going to run all of these commands in the context of the Docker image.

To get a better understanding of this file, then check out my shiny new Dive Into Docker course (which is even more up to date than this article).

FROM python:2.7-slim
MAINTAINER Nick Janetakis <nick.janetakis@gmail.com>

ENV INSTALL_PATH /snakeeyes
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

RUN pip install --editable .

CMD gunicorn -b 0.0.0.0:8000 --access-logfile - "snakeeyes.app:create_app()"

At this point we could build the image and you’d be able to access the Flask app, but let’s avoid doing that for now.

.dockerignore

Let’s first look at the next file which is the .dockerignore file.

.git
.dockerignore

When we copied in all of the files from our current directory into the Docker image with the COPY . . command, it’s going to copy literally everything.

That’s not the best idea in the world because if your project is a git repo you’re going to have a TON of extra data. You should strive to have the smallest Docker images you can within reason.

The .dockerignore file is very similar to a .gitignore file. It lets you black list certain folders or files from being included.

In our case, we’re ignoring the git folder but we’re also excluding the .dockerignore file itself because it’s not part of our Flask application.

docker-compose.yml

Docker Compose is an official tool supplied by Docker. At its core, it’s a utility that lets you “compose” Docker commands and manage multiple containers in an easy way.

Let’s take a glance at the docker-compose.yml file:

version: '2'

services:
  redis:
    image: 'redis:3.0-alpine'
    command: redis-server --requirepass devpassword
    volumes:
      - 'redis:/data'
    ports:
      - '6379:6379'

  website:
    build: .
    command: >
      gunicorn -b 0.0.0.0:8000
        --access-logfile -
        --reload
        "snakeeyes.app:create_app()"
    environment:
      PYTHONUNBUFFERED: 'true'
    volumes:
      - '.:/snakeeyes'
    ports:
      - '8000:8000'

  celery:
    build: .
    command: celery worker -l info -A snakeeyes.blueprints.contact.tasks
    volumes:
      - '.:/snakeeyes'

volumes:
  redis:

Dive Into Docker covers everything in great detail if you want to see how all of this ties together. Often times knowing the “why” is more important than seeing how it’s done. That is what enables you to apply things on your own.

.env

This file isn’t technically part of Docker, but it’s used by Docker Compose.

By default Docker Compose will look for an .env file in the same directory as your docker-compose.yml file.

We can set various environment variables here, and you can even add your custom environment variables here too if your application uses ENV variables.

COMPOSE_PROJECT_NAME=snakeeyes

By setting the COMPOSE_PROJECT_NAME to snakeeyes, Docker Compose will automatically prefix our Docker images, containers, volumes and networks with snakeeyes.

Run the Flask Application

You can run everything by typing: docker-compose up --build. Docker Compose has many different sub-commands and flags. You’ll definitely want to check them out on your own.

After the up command finishes, open up a new terminal tab and check out what was created on your behalf.

Docker Images

Run docker images:

snakeeyes_celery     latest              ...         229.1 MB
snakeeyes_website    latest              ...         229.1 MB
redis                3.0-alpine          ...         13.27 MB
python               2.7-slim            ...         184 MB

Docker Compose automatically pulled down Redis and Python for you, and then built the website and celery images for you.

Docker Containers

Run docker-compose ps:

Name                        State   Ports          
----------------------------------------------------------
snakeeyes_celery_1    ...   Up                             
snakeeyes_redis_1     ...   Up      0.0.0.0:6379->6379/tcp
snakeeyes_website_1   ...   Up      0.0.0.0:8000->8000/tcp

Docker Compose automatically named the containers for you, and it appended a _1 because it’s running 1 instance of the Docker image. Docker Compose supports scaling but that goes beyond the scope of this tutorial.

We can also see which ports the services are using.

There’s a lot more to go over but the above is enough to get rolling.

Viewing the Site

If you installed Docker through the Docker Toolbox then you’ll need to make 1 change to the config/settings.py file.

Check out the SERVER_NAME = 'localhost:8000' value.

You will need to change localhost to your Docker Machine IP address instead.

Chances are that will be 192.168.99.100 but if it’s not, you can find your Docker Machine IP by running docker-machine ip.

Then you can check it out in your browser by going to http://localhost:8000. Again, as a reminder, if you’re using Docker Toolbox then access your Docker Machine IP address instead.

At this point you have a Dockerized Flask application running. Congrats!

By the way, if you tried to submit the contact form and you received a CSRF token error then check out how to fix this problem. Spoiler alert: it’s a bug with Chrome.

Shutting Things Down

You’ll want to goto your Docker Compose terminal tab and press CTRL+C. Then for good measure, type docker-compose stop. Sometimes Compose bugs out and won’t stop all of your containers automatically.

You could also optionally run docker-compose rm -f to clean up your stopped containers. I tend to do this all the time.

Conclusion

Docker is awesome. Now you can run your projects on other platforms without having to worry about dependencies and platform specific gotchas.

You can even deploy your projects to production with minimal fuss.

You can learn much more about Flask by checking out the Build a SAAS App with Flask course.

Or, if you’re ready to master Docker, then check out the Dive Into Docker course.

Free Intro to Docker Email Course

Over 5 days you'll get 1 email per day that includes video and text from the premium Dive Into Docker course. By the end of the 5 days you'll have hands on experience using Docker to serve a website.


Comments