Honestly, my motivation for looking into Docker was to see what all the hype was about… is the hype true? Can Docker really help out with my development experience? Can Docker make deploying a web application easier?
From what I’ve experienced, Docker is an amazing tool that can greatly help with developing, testing, and deploying software. I’ve heard a lot of people talk about how Docker is an ever changing ecosystem, which makes it tough to keep up to date with the tool (seriously, it feels like any blog post/video/book that is older than six months is out of date when it comes to Docker!). I’d argue that this makes it an exciting time to learn about Docker and how it can be great addition to your development and production environments. Given the short time period that Docker has been out, I think it has a huge amount of capability (Docker, Docker Hub, Docker Compose, Docker Swarm, etc.).
In this blog post, I’ll discuss why I’m switching from a traditional deployment strategy to using Docker to simplify the deployment process. I’ll discuss what I’m calling a “traditional” deployment and how Docker can simplify this process, with a focus on Flask web applications. I’ve found that Docker allows you to move past a lot of the headaches of traditional deployments, while also allowing you to configuration control your overall application environment.
The traditional deployment process that I’ve followed in the past involved using a development web server (built-in to the Flask framework) on my laptop, but then using a production web server (combination of Nginx and Gunicorn) on my production server. While this process works, it is by no means an easy process to switch from running in the development environment to the production environment. It usually felt like the challenges in developing a Flask web application paled in comparison to getting the production environment configured and working.
Since this always felt like a big effort to deploy to a production server, I usually waited until my web application was of a decent maturity before taking on this endeavor (there might be a bit of procrastination thrown in too!). As with a lot of software projects, waiting to tackle the really high-risk items until later in the project is usually a bad idea, even with a simple personal project.
Here’s a diagram that shows a high-level view of what I’m calling a traditional deployment:
For my development, I would utilize the development server that is built-in to the Flask framework for testing my application. The Flask development server is sufficient for this type of work, but it is not a good choice in a production environment due to it not scaling well and serving only a single request at a time (see Flask documentation). As with most web applications, a database is needed for storing persistent data in a structured manner. I’ve been using Postgres as my database, which requires having a Postgres server running on your laptop to interface with the Postgres database. This is one of the areas of setting up a development environment that can be a nightmare, as the installation of Postgres can be challenging (especially before discovering Postgres.app).
When switching over to the production server, there are a ton of new technologies to learn and get configured together. Instead of using the Flask development web server, I use Gunicorn as the WSGI server and Nginx as the web server. Why are both needed? Nginx is the front-end web server that serves up static content (images, documents, css files, etc.) and reverse-proxies requests to Gunicorn. Gunicorn provides the connection to the actual Flask web application that has been developed. Nginx has no way to directly talk to your Flask application, so Gunicorn provides this middle layer (called a WSGI (Web Server Gateway Interface) server). As with the development server, a Postgres server and database are utilized.
So what are the issues with this traditional development process that would make me want to consider a better or simpler approach? I’ve found that there are three major problems with this traditional deployment process:
- Different Environments: having a different environment for my development work on my laptop vs. on the production server.
- Configuration Management: not being able to easily configuration manage the application environment
- Collaboration: not being able to easily replicate an application environment (either development or production) for a colleague/friend
As it turns out, Docker is a great solution for solving each of these issues!
Using Docker for Development and Deployment
Switching to using Docker does not preclude you from using the development environment described above in the traditional deployment section. In fact, this is always a good option for starting off development of a new web application.
However, Docker provides a much easier solution for structuring web applications. One of the big side effects that I’ve really enjoyed about Docker is having to think about the overall architecture of my web application early on in the development process. Docker forces you to understand how all the pieces in your web application need to work together in a production environment earlier on in the development process. Why? Because you can easily jump right to your production configuration on your laptop. This is one of the great things about new technologies like Docker; they simplify a different process to allow you to focus on developing better applications/tools/services.
Here’s a high-level diagram that shows how I use Docker for my development and production environments:
There are four containers that interface with each other to encapsulate the full web application:
- Web application container – contains the Flask web application plus all of the dependent modules; this container includes the Gunicorn WSGI server
- Nginx container – runs an official Nginx image with our configuration
- Postgres container – runs an official Postgres image with our configuration
- Data volume – container for storing the Postgres database
Here’s where Docker becomes so powerful… the environment that we configure for using in our development environment (such as your laptop) is the same as what gets deployed to the production server!
Let’s see how Docker solves the three major problems with traditional deployments that were identified in the previous section:
- Different Environments: Docker allows you to come up with your “production” environment on your development machine (your laptop, for example) and then deploy this exact configuration to your production server. There are no differences between these two environments!
- Configuration Management: The Docker configuration files (Dockerfiles and docker-compose.yml) are included in your git repository and they allow you to exactly define the configuration of your overall web application. You can specify the exact version of each image to use, such as Nginx 1.11.3.
- Collaboration: Since the Docker configuration files are stored in your git repository on GitLab (or GitHub or BitBucket), it is easy for a colleague/friend to clone the repository and set up the same application environment on their machine using Docker.
While Docker solves a lot of problems with a traditional deployment process, there are still a number of technologies that you need to understand to do a deployment:
- How to secure a web server
- What Nginx is and how to configure it
- Why you need a WSGI server, such as Gunicorn, in your web application
- How to configure and work with Postgres
After spending a good deal of time researching Docker and actually using it to implement the application environment for a Flask web application, I’m a believer in Docker! The hype is real and Docker is a maturing technology that has so many advantages over traditional deployments. I really feel like Docker helps to reduce a lot of the bottlenecks that can be really frustrating with deploying a web application.
This blog post discussed the WHY of using Docker for web application and the next blog post will dive into the details of HOW to use Docker to create an application environment on your development machine that can be deployed to a production server.
Full Stack Python Guide to Deployments by Matt Makai
This is a great book that is focused more on traditional deployments, but it provides such great base for how to deploy web applications. I’ve used this book as the basis for deploying a Django and a Flask web application to DigitalOcean. I learned a ton from this book!
Docker for Developers by Chris Tankersley
I would recommend reading this book as the first step in learning about Docker. This book uses examples for running a PHP application, but that doesn’t take away from the great job in explaining the technology leading up to Docker and what all the different components of the Docker ecosystem are.
Dockerizing Flask With Compose and Machine – From Localhost to the Cloud (from Real Python Blog):
This blog post provides a really concise example of how to use Docker for a Flask application. I gained a lot of knowledge of how to configure a Flask application from this blog post and working through the example presented in this blog post was my first “Ah ha!” with Docker.
Docker for Beginners by Prakhar Srivastav
Excellent blog post on how to go from just using a Dockerfile for a single container to using Docker Compose to create a full application with multiple containers.