Deploy a Python Flask app with Docker and AWS Elastic Beanstalk

Nadaa Taiyab
8 min readMay 10, 2018

--

I recently built and deployed my very first web app, the Progressive Equity Calculator, using Flask, Pandas, Docker, and Elastic Beanstalk. This blog post is an easy intro to understanding Docker and a beginner’s step-by-step guide to deploying an app with Docker and AWS Elastic Beanstalk. My target audience is other Docker newbies who are trying to wrap their heads around the key concepts.

What is Docker?

Image Credit: https://www.docker.com/what-container

First, let me tell you why Docker is awesome.

Docker is a way to run an entire environment on your computer in just a few seconds. It’s like a mini, light-weight virtual machine, but with some important differences. A virtual machine is trying to simulate an entire computer but Docker is just a secure isolated process. A “process” is basically a program running on your computer. Running a Docker container is like running a program, which is why it starts up in seconds.

Instead of installing all your dependencies on your hard drive, you can run a Docker container with all the packages you need already set up. You can also give the Docker container permission to access specific files on your hard drive and then run those files in the container. This is called “bind mounting” a Docker volume. Any changes you make to the files in those folders (using any IDE you want) are instantly synced to your Docker container environment. Pretty cool!

When you are done for the day, you can stop your Docker container and easily fire it back up again later from its corresponding Docker image. (I’ll explain what Docker images are later in this article.) If someone else wants to work on your project, you can send them the Docker image and they will have the exact development environment without installing a single package themselves. Amazing!

There are also tens of thousands of pre-built Docker images available on Docker Hub that you can use immediately.

More Reasons to Use Docker

  1. Fast and Codified Dev Environment Setup — Once you’ve created the Docker image, you can just share it and/or the Dockerfile with your team and no one needs to install anything (except Docker, of course!). With your Dockerfile you have explicitly declared, in code, how to configure your Dev environment, so reproducing a Dev environment is no longer a mystery.
  2. Ease of Deployment — Docker is a universal deployment artifact. This means that you don’t have to do very much, if any, additional work to deploy your code. If your code works in Docker on your dev environment, it will work in any production environment that is already configured to run a Docker container. Most cloud infrastructure services today support Docker and many, such as Elastic Beanstalk, allow you to run a Docker image directly.
  3. Security — Damage from malware is now limited to the container because it does not have access to your whole computer. In practice, some vulnerabilities have been found, allowing a program to reach beyond the container. However, since Docker has such an active ecosystem, those bugs are usually fixed pretty quickly.

Docker Core Concepts:

Here are the four key concepts I had to get straight to understand Docker.

  1. Dockerfile: a text file that describes how your Docker Image should be built. I think of it as a blue print.
  2. Docker Image: an executable package built from a Dockerfile using the “docker build” command. Docker images are used to generate Docker containers. Think of them as the intermediate step.
  3. Docker Container: a live instance of your Docker Image created using the “docker run” command. A container is like a mini, light-weight virtual machine that you can take down whenever you like and fire back up again using your Docker image.
  4. Docker Hub: Docker Hub is a registry where you can store and share your Docker Images and get access to images created by others. Note that Dockerfiles are not stored on Docker Hub so the image creator has to tell you where to find it (usually on a github repo) if they want to share.

Have a look at the official docs for a deeper dive.

Dockerize your Flask app— Step-by-Step

Now that we are done with the preliminaries — here are step-by-step instructions for Dockerzing your Flask app.

Step 1: Create your Dockerfile

I decided to write my own Dockerfile instead of using the official Python pre-built image, so that I could install only the specific packages I needed for my application.

  1. Create a file in your text editor called “Dockerfile” and save it in the root directory of your app. Note you do not need a file extension.

Here’s quick explanation of what all the commands in the Dockerfile mean.

FROM
This specifies the base image you are starting with. I started with just the Docker image containing Ubuntu. This is a popular Docker image in wide use, so it is a good starting point.

MAINTAINER
That’s you! The creator of this beautiful Dockerfile.

RUN
RUN will execute any commands you give it. This is where you specify the packages you want to install. “apt-get” is a command specific to installing packages using Ubuntu. In this case, I installed Python and Pip.

The second RUN command in the file references a document called “requirements.txt”. This is generated by running:

pip freeze > requirements.txt

Here’s a little sample of what I got when I ran this on my machine. This document had 229 lines and seemed to list all the packages I have installed on my computer and not just the ones I need to run my app.

So I deleted all the non-essentials for my app and ended up with this two-liner.

COPY . /app
Copy all the files in your current working directory into the /app folder in the Docker container. The “.” means copy everything. You could also choose to just copy some of the files.

WORKDIR /app
Execute commands from the /app directory.

EXPOSE 5000
Expose indicates the ports (in this case 5000) that the container should listen to for connections.

ENTRYPOINT [“python”]
CMD [“application.py”]
Run application.py with Python.

For more details the official docs do an awesome job. The above is just a very quick summary.

Step 2: Build your Docker image

Now you will use your Dockerfile to build your Docker image. There are a few different ways to do this and the official docs will give you the details. Here are a few:

Build with PATH
Make sure you run this command from the same directory as the location of your Dockerfile

docker build .

The “.” refers to whatever Dockerfile is in the current directory.

Build with PATH and add a tag

docker build -t nadaa.taiyab/flask:latest .

The “-t” specifies a tag. Read here for info on tagging and note that you are still using the “.” as you did in the previous example

Now run this command to see the Docker images you have in your local repository.

docker images

Here is an example of what you should see on your screen:

Debug your build

If something goes wrong with the build you can fire up a plain ubuntu image and try installing each package from the Dockerfile manually. My build failed when I tried to use my 200+ requirements.txt that I had originally generated. So I used this method to reproduce the error.

docker pull ubuntu:16.04docker run -it -v [full file path to your app files]:/app ubuntu:16.04 /bin/bash

The “docker pull” command pulls down an image from Docker Hub.

The “docker run” command starts a container using the ubuntu image and gets you to the command line. The “-v” mounts the app files to your container (will explain this in the next section).

Step 3: Fire up your Docker container

Now you are going to use “docker run” to fire up a Docker container using a Docker image.

docker run -p 5000:5000 nadaataiyab/pe-calculator:latest

This command will run the docker image “nadaataiyab/pe-calculator:latest” and copy the files from the folder specified in your Dockerfile (remember COPY . /app).

The “-p” specifies which port on your host machine should be mapped to the corresponding port in your container. For some reason this only worked when I did 5000:5000.

Note: the command above will not let you develop in real time because changes to your files on your computer will not be reflected in the files on your container.

Here is what you should do instead if you want to develop in real time:

docker run -p 5000:5000 -v [file path to the project files on your computer]:/app nadaataiyab/pe-calculator

The “-v” mounts a folder on your local machine to your container. This means that you can edit your files locally and then run them on your container in real time, without having to rebuild the image.

To shut down the container hit “CTRL” + C.

Deploy on AWS Elastic Beanstalk

Now that you have Dockerized your app, it is unbelievably easy to deploy it on AWS Elastic Beanstalk. Without Docker, I was not able to deploy my app, in spite of reading the documentation, trying to do the tutorial, and studying blog posts. I was astonished when the deployment worked with absolutely no effort using Docker.

  1. Login to AWS and get to the Elastic Beanstalk service
  2. Create a new environment and select “Docker” as the preconfigured platform
  3. Upload a zip of your app files, which of course should include the Dockerfile. Create the zip from within the root directory of your app.

Note that there are better ways of doing this using the AWS command line interface, etc. However, this method is just quick and easy.

If you get a memory error, you may need to use a larger instance. The t2.micro was too small for my app.

Once you have successfully uploaded your files on the right size instance, Elastic Beanstalk will deploy your app and make it available. Here is mine:

You can, of course, specify a custom url too!

Conclusion

Docker is awesome and you should try it!

Feel free to try running my app using Docker on your local machine.

I hope you found this guide helpful. Feedback is always appreciated.

Other helpful resources and blog posts

Contact

LinkedIn | Github | Twitter

--

--

Nadaa Taiyab
Nadaa Taiyab

Written by Nadaa Taiyab

Data scientist. Passionate about using data for social good.

Responses (5)